Repository: hyperfield/ai-file-sorter Branch: main Commit: 630b46a1c682 Files: 1196 Total size: 8.3 MB Directory structure: gitextract_jgso0h_k/ ├── .clang-format ├── .github/ │ └── workflows/ │ └── build.yml ├── .gitignore ├── .gitmodules ├── CHANGELOG.md ├── LICENSE ├── README.md ├── TESTS.md ├── TRADEMARKS.md ├── app/ │ ├── CMakeLists.txt │ ├── Makefile │ ├── build_windows.ps1 │ ├── include/ │ │ ├── AppInfo.hpp │ │ ├── CategorizationDialog.hpp │ │ ├── CategorizationProgressDialog.hpp │ │ ├── CategorizationService.hpp │ │ ├── CategorizationServiceTestAccess.hpp │ │ ├── CategorizationSession.hpp │ │ ├── CategoryLanguage.hpp │ │ ├── ConsistencyPassService.hpp │ │ ├── CustomApiDialog.hpp │ │ ├── CustomLLMDialog.hpp │ │ ├── DatabaseManager.hpp │ │ ├── DialogUtils.hpp │ │ ├── DocumentTextAnalyzer.hpp │ │ ├── DryRunPreviewDialog.hpp │ │ ├── EmbeddedEnv.hpp │ │ ├── ErrorMessages.hpp │ │ ├── FileScanner.hpp │ │ ├── GeminiClient.hpp │ │ ├── GgmlRuntimePaths.hpp │ │ ├── ILLMClient.hpp │ │ ├── ImageRenameMetadataService.hpp │ │ ├── IniConfig.hpp │ │ ├── LLMClient.hpp │ │ ├── LLMDownloader.hpp │ │ ├── LLMErrors.hpp │ │ ├── LLMSelectionDialog.hpp │ │ ├── LLMSelectionDialogTestAccess.hpp │ │ ├── Language.hpp │ │ ├── LlamaModelParams.hpp │ │ ├── LlavaImageAnalyzer.hpp │ │ ├── LlmCatalog.hpp │ │ ├── LocalLLMClient.hpp │ │ ├── LocalLLMTestAccess.hpp │ │ ├── Logger.hpp │ │ ├── MainApp.hpp │ │ ├── MainAppEditActions.hpp │ │ ├── MainAppHelpActions.hpp │ │ ├── MainAppTestAccess.hpp │ │ ├── MainAppUiBuilder.hpp │ │ ├── MediaRenameMetadataService.hpp │ │ ├── MovableCategorizedFile.hpp │ │ ├── ResultsCoordinator.hpp │ │ ├── Settings.hpp │ │ ├── SuitabilityBenchmarkDialog.hpp │ │ ├── SupportCodeManager.hpp │ │ ├── TestHooks.hpp │ │ ├── TranslationManager.hpp │ │ ├── Types.hpp │ │ ├── UiTranslator.hpp │ │ ├── UndoManager.hpp │ │ ├── UpdateArchiveExtractor.hpp │ │ ├── UpdateFeed.hpp │ │ ├── UpdateInstaller.hpp │ │ ├── UpdateInstallerTestAccess.hpp │ │ ├── Updater.hpp │ │ ├── UpdaterBuildConfig.hpp │ │ ├── UpdaterLaunchOptions.hpp │ │ ├── UpdaterLiveTestConfig.hpp │ │ ├── UpdaterTestAccess.hpp │ │ ├── Utils.hpp │ │ ├── Version.hpp │ │ ├── WhitelistManagerDialog.hpp │ │ ├── WhitelistStore.hpp │ │ ├── app_version.hpp │ │ ├── constants.hpp │ │ └── external/ │ │ └── dotenv.h │ ├── includePaths.txt │ ├── lib/ │ │ ├── CategorizationDialog.cpp │ │ ├── CategorizationProgressDialog.cpp │ │ ├── CategorizationService.cpp │ │ ├── CategorizationSession.cpp │ │ ├── ConsistencyPassService.cpp │ │ ├── CustomApiDialog.cpp │ │ ├── CustomLLMDialog.cpp │ │ ├── DatabaseManager.cpp │ │ ├── DialogUtils.cpp │ │ ├── DocumentTextAnalyzer.cpp │ │ ├── DryRunPreviewDialog.cpp │ │ ├── EmbeddedEnv.cpp │ │ ├── FileScanner.cpp │ │ ├── GeminiClient.cpp │ │ ├── GgmlRuntimePaths.cpp │ │ ├── ImageRenameMetadataService.cpp │ │ ├── IniConfig.cpp │ │ ├── LLMClient.cpp │ │ ├── LLMDownloader.cpp │ │ ├── LLMSelectionDialog.cpp │ │ ├── LlavaImageAnalyzer.cpp │ │ ├── LlmCatalog.cpp │ │ ├── LocalLLMClient.cpp │ │ ├── Logger.cpp │ │ ├── MainApp.cpp │ │ ├── MainAppEditActions.cpp │ │ ├── MainAppHelpActions.cpp │ │ ├── MainAppUiBuilder.cpp │ │ ├── MediaRenameMetadataService.cpp │ │ ├── MovableCategorizedFile.cpp │ │ ├── PugixmlBundle.cpp │ │ ├── ResultsCoordinator.cpp │ │ ├── Settings.cpp │ │ ├── SuitabilityBenchmarkDialog.cpp │ │ ├── SupportCodeManager.cpp │ │ ├── TranslationManager.cpp │ │ ├── UiTranslator.cpp │ │ ├── UndoManager.cpp │ │ ├── UpdateArchiveExtractor.cpp │ │ ├── UpdateFeed.cpp │ │ ├── UpdateInstaller.cpp │ │ ├── Updater.cpp │ │ ├── UpdaterLiveTestConfig.cpp │ │ ├── Utils.cpp │ │ ├── Version.cpp │ │ ├── WhitelistManagerDialog.cpp │ │ └── WhitelistStore.cpp │ ├── main.cpp │ ├── resources/ │ │ ├── app.qrc │ │ ├── certs/ │ │ │ └── cacert.pem │ │ ├── i18n/ │ │ │ ├── aifilesorter_de.ts │ │ │ ├── aifilesorter_es.ts │ │ │ ├── aifilesorter_fr.ts │ │ │ ├── aifilesorter_it.ts │ │ │ ├── aifilesorter_ko.ts │ │ │ ├── aifilesorter_nl.ts │ │ │ └── aifilesorter_tr.ts │ │ ├── images/ │ │ │ ├── app_icon_128.xcf │ │ │ ├── app_icon_128_magnified.xcf │ │ │ ├── app_icon_256.xcf │ │ │ ├── app_icon_256_magnified.xcf │ │ │ ├── app_icon_350.xcf │ │ │ ├── app_icon_512.xcf │ │ │ ├── app_icon_arrows_more_colours.xcf │ │ │ ├── logo.xcf │ │ │ ├── logo_inscription.xcf │ │ │ ├── qn_logo.xcf │ │ │ └── qn_logo_200.xcf │ │ └── windows/ │ │ ├── app_icon.rc.in │ │ └── version.rc.in │ ├── scripts/ │ │ ├── README.md │ │ ├── build_llama_linux.sh │ │ ├── build_llama_macos.sh │ │ ├── build_llama_windows.ps1 │ │ ├── collect_linux_diagnostics.sh │ │ ├── collect_macos_diagnostics.sh │ │ ├── collect_windows_diagnostics.ps1 │ │ ├── gen_run_wrapper.py │ │ ├── generate_icon.ps1 │ │ ├── package_deb.sh │ │ ├── rebuild_and_test.sh │ │ ├── run_aifilesorter.sh.in │ │ ├── vendor_doc_deps.ps1 │ │ └── vendor_doc_deps.sh │ ├── startapp_linux.cpp │ ├── startapp_windows.cpp │ └── vcpkg.json ├── external/ │ ├── README-doc-deps.md │ ├── THIRD_PARTY_LICENSES/ │ │ ├── libzip-LICENSE │ │ ├── pdfium-LICENSE │ │ └── pugixml-LICENSE.md │ ├── libzip/ │ │ ├── .clang-format │ │ ├── .github/ │ │ │ ├── ISSUE_TEMPLATE/ │ │ │ │ ├── bug-report.md │ │ │ │ ├── compile-error.md │ │ │ │ ├── feature-request.md │ │ │ │ └── other.md │ │ │ └── workflows/ │ │ │ ├── CIFuzz.yml │ │ │ ├── bsd.yml │ │ │ ├── build.yml │ │ │ ├── codeql-analysis.yml │ │ │ └── coverity.yml │ │ ├── API-CHANGES.md │ │ ├── AUTHORS │ │ ├── CMakeLists.txt │ │ ├── INSTALL.md │ │ ├── LICENSE │ │ ├── NEWS.md │ │ ├── README.md │ │ ├── SECURITY.md │ │ ├── THANKS │ │ ├── TODO.md │ │ ├── android/ │ │ │ ├── do.sh │ │ │ ├── docker/ │ │ │ │ └── Dockerfile │ │ │ └── readme.txt │ │ ├── appveyor.yml │ │ ├── cmake/ │ │ │ ├── Dist.cmake │ │ │ ├── FindMbedTLS.cmake │ │ │ ├── FindNettle.cmake │ │ │ ├── Findzstd.cmake │ │ │ └── GenerateZipErrorStrings.cmake │ │ ├── cmake-compat/ │ │ │ ├── CMakePushCheckState.cmake │ │ │ ├── CheckLibraryExists.cmake │ │ │ ├── CheckSymbolExists.cmake │ │ │ ├── FindBZip2.cmake │ │ │ ├── FindGnuTLS.cmake │ │ │ ├── FindLibLZMA.cmake │ │ │ ├── FindPackageHandleStandardArgs.cmake │ │ │ ├── FindPackageMessage.cmake │ │ │ └── SelectLibraryConfigurations.cmake │ │ ├── config.h.in │ │ ├── examples/ │ │ │ ├── CMakeLists.txt │ │ │ ├── add-compressed-data.c │ │ │ ├── autoclose-archive.c │ │ │ ├── cmake-project/ │ │ │ │ ├── CMakeLists.txt │ │ │ │ └── cmake-example.c │ │ │ ├── in-memory.c │ │ │ └── windows-open.c │ │ ├── lib/ │ │ │ ├── CMakeLists.txt │ │ │ ├── compat.h │ │ │ ├── zip.h │ │ │ ├── zip_add.c │ │ │ ├── zip_add_dir.c │ │ │ ├── zip_add_entry.c │ │ │ ├── zip_algorithm_bzip2.c │ │ │ ├── zip_algorithm_deflate.c │ │ │ ├── zip_algorithm_xz.c │ │ │ ├── zip_algorithm_zstd.c │ │ │ ├── zip_buffer.c │ │ │ ├── zip_close.c │ │ │ ├── zip_crypto.h │ │ │ ├── zip_crypto_commoncrypto.c │ │ │ ├── zip_crypto_commoncrypto.h │ │ │ ├── zip_crypto_gnutls.c │ │ │ ├── zip_crypto_gnutls.h │ │ │ ├── zip_crypto_mbedtls.c │ │ │ ├── zip_crypto_mbedtls.h │ │ │ ├── zip_crypto_openssl.c │ │ │ ├── zip_crypto_openssl.h │ │ │ ├── zip_crypto_win.c │ │ │ ├── zip_crypto_win.h │ │ │ ├── zip_delete.c │ │ │ ├── zip_dir_add.c │ │ │ ├── zip_dirent.c │ │ │ ├── zip_discard.c │ │ │ ├── zip_entry.c │ │ │ ├── zip_error.c │ │ │ ├── zip_error_clear.c │ │ │ ├── zip_error_get.c │ │ │ ├── zip_error_get_sys_type.c │ │ │ ├── zip_error_strerror.c │ │ │ ├── zip_error_to_str.c │ │ │ ├── zip_extra_field.c │ │ │ ├── zip_extra_field_api.c │ │ │ ├── zip_fclose.c │ │ │ ├── zip_fdopen.c │ │ │ ├── zip_file_add.c │ │ │ ├── zip_file_error_clear.c │ │ │ ├── zip_file_error_get.c │ │ │ ├── zip_file_get_comment.c │ │ │ ├── zip_file_get_external_attributes.c │ │ │ ├── zip_file_get_offset.c │ │ │ ├── zip_file_rename.c │ │ │ ├── zip_file_replace.c │ │ │ ├── zip_file_set_comment.c │ │ │ ├── zip_file_set_encryption.c │ │ │ ├── zip_file_set_external_attributes.c │ │ │ ├── zip_file_set_mtime.c │ │ │ ├── zip_file_strerror.c │ │ │ ├── zip_fopen.c │ │ │ ├── zip_fopen_encrypted.c │ │ │ ├── zip_fopen_index.c │ │ │ ├── zip_fopen_index_encrypted.c │ │ │ ├── zip_fread.c │ │ │ ├── zip_fseek.c │ │ │ ├── zip_ftell.c │ │ │ ├── zip_get_archive_comment.c │ │ │ ├── zip_get_archive_flag.c │ │ │ ├── zip_get_encryption_implementation.c │ │ │ ├── zip_get_file_comment.c │ │ │ ├── zip_get_name.c │ │ │ ├── zip_get_num_entries.c │ │ │ ├── zip_get_num_files.c │ │ │ ├── zip_hash.c │ │ │ ├── zip_io_util.c │ │ │ ├── zip_libzip_version.c │ │ │ ├── zip_memdup.c │ │ │ ├── zip_name_locate.c │ │ │ ├── zip_new.c │ │ │ ├── zip_open.c │ │ │ ├── zip_pkware.c │ │ │ ├── zip_progress.c │ │ │ ├── zip_random_unix.c │ │ │ ├── zip_random_uwp.c │ │ │ ├── zip_random_win32.c │ │ │ ├── zip_realloc.c │ │ │ ├── zip_rename.c │ │ │ ├── zip_replace.c │ │ │ ├── zip_set_archive_comment.c │ │ │ ├── zip_set_archive_flag.c │ │ │ ├── zip_set_default_password.c │ │ │ ├── zip_set_file_comment.c │ │ │ ├── zip_set_file_compression.c │ │ │ ├── zip_set_name.c │ │ │ ├── zip_source_accept_empty.c │ │ │ ├── zip_source_begin_write.c │ │ │ ├── zip_source_begin_write_cloning.c │ │ │ ├── zip_source_buffer.c │ │ │ ├── zip_source_call.c │ │ │ ├── zip_source_close.c │ │ │ ├── zip_source_commit_write.c │ │ │ ├── zip_source_compress.c │ │ │ ├── zip_source_crc.c │ │ │ ├── zip_source_error.c │ │ │ ├── zip_source_file.h │ │ │ ├── zip_source_file_common.c │ │ │ ├── zip_source_file_stdio.c │ │ │ ├── zip_source_file_stdio.h │ │ │ ├── zip_source_file_stdio_named.c │ │ │ ├── zip_source_file_win32.c │ │ │ ├── zip_source_file_win32.h │ │ │ ├── zip_source_file_win32_ansi.c │ │ │ ├── zip_source_file_win32_named.c │ │ │ ├── zip_source_file_win32_utf16.c │ │ │ ├── zip_source_file_win32_utf8.c │ │ │ ├── zip_source_free.c │ │ │ ├── zip_source_function.c │ │ │ ├── zip_source_get_dostime.c │ │ │ ├── zip_source_get_file_attributes.c │ │ │ ├── zip_source_is_deleted.c │ │ │ ├── zip_source_layered.c │ │ │ ├── zip_source_open.c │ │ │ ├── zip_source_pass_to_lower_layer.c │ │ │ ├── zip_source_pkware_decode.c │ │ │ ├── zip_source_pkware_encode.c │ │ │ ├── zip_source_read.c │ │ │ ├── zip_source_remove.c │ │ │ ├── zip_source_rollback_write.c │ │ │ ├── zip_source_seek.c │ │ │ ├── zip_source_seek_write.c │ │ │ ├── zip_source_stat.c │ │ │ ├── zip_source_supports.c │ │ │ ├── zip_source_tell.c │ │ │ ├── zip_source_tell_write.c │ │ │ ├── zip_source_window.c │ │ │ ├── zip_source_winzip_aes_decode.c │ │ │ ├── zip_source_winzip_aes_encode.c │ │ │ ├── zip_source_write.c │ │ │ ├── zip_source_zip.c │ │ │ ├── zip_source_zip_new.c │ │ │ ├── zip_stat.c │ │ │ ├── zip_stat_index.c │ │ │ ├── zip_stat_init.c │ │ │ ├── zip_strerror.c │ │ │ ├── zip_string.c │ │ │ ├── zip_unchange.c │ │ │ ├── zip_unchange_all.c │ │ │ ├── zip_unchange_archive.c │ │ │ ├── zip_unchange_data.c │ │ │ ├── zip_utf-8.c │ │ │ ├── zip_winzip_aes.c │ │ │ └── zipint.h │ │ ├── libzip-config.cmake.in │ │ ├── libzip.pc.in │ │ ├── man/ │ │ │ ├── CMakeLists.txt │ │ │ ├── ZIP_SOURCE_GET_ARGS.html │ │ │ ├── ZIP_SOURCE_GET_ARGS.man │ │ │ ├── ZIP_SOURCE_GET_ARGS.mdoc │ │ │ ├── handle_links │ │ │ ├── libzip.html │ │ │ ├── libzip.man │ │ │ ├── libzip.mdoc │ │ │ ├── links │ │ │ ├── update-html.cmake │ │ │ ├── update-man.cmake │ │ │ ├── zip.html │ │ │ ├── zip.man │ │ │ ├── zip.mdoc │ │ │ ├── zip_add.html │ │ │ ├── zip_add.man │ │ │ ├── zip_add.mdoc │ │ │ ├── zip_add_dir.html │ │ │ ├── zip_add_dir.man │ │ │ ├── zip_add_dir.mdoc │ │ │ ├── zip_close.html │ │ │ ├── zip_close.man │ │ │ ├── zip_close.mdoc │ │ │ ├── zip_compression_method_supported.html │ │ │ ├── zip_compression_method_supported.man │ │ │ ├── zip_compression_method_supported.mdoc │ │ │ ├── zip_delete.html │ │ │ ├── zip_delete.man │ │ │ ├── zip_delete.mdoc │ │ │ ├── zip_dir_add.html │ │ │ ├── zip_dir_add.man │ │ │ ├── zip_dir_add.mdoc │ │ │ ├── zip_discard.html │ │ │ ├── zip_discard.man │ │ │ ├── zip_discard.mdoc │ │ │ ├── zip_encryption_method_supported.html │ │ │ ├── zip_encryption_method_supported.man │ │ │ ├── zip_encryption_method_supported.mdoc │ │ │ ├── zip_error.html │ │ │ ├── zip_error.man │ │ │ ├── zip_error.mdoc │ │ │ ├── zip_error_clear.html │ │ │ ├── zip_error_clear.man │ │ │ ├── zip_error_clear.mdoc │ │ │ ├── zip_error_code_system.html │ │ │ ├── zip_error_code_system.man │ │ │ ├── zip_error_code_system.mdoc │ │ │ ├── zip_error_code_zip.html │ │ │ ├── zip_error_code_zip.man │ │ │ ├── zip_error_code_zip.mdoc │ │ │ ├── zip_error_fini.html │ │ │ ├── zip_error_fini.man │ │ │ ├── zip_error_fini.mdoc │ │ │ ├── zip_error_get.html │ │ │ ├── zip_error_get.man │ │ │ ├── zip_error_get.mdoc │ │ │ ├── zip_error_get_sys_type.html │ │ │ ├── zip_error_get_sys_type.man │ │ │ ├── zip_error_get_sys_type.mdoc │ │ │ ├── zip_error_init.html │ │ │ ├── zip_error_init.man │ │ │ ├── zip_error_init.mdoc │ │ │ ├── zip_error_set.html │ │ │ ├── zip_error_set.man │ │ │ ├── zip_error_set.mdoc │ │ │ ├── zip_error_set_from_source.html │ │ │ ├── zip_error_set_from_source.man │ │ │ ├── zip_error_set_from_source.mdoc │ │ │ ├── zip_error_strerror.html │ │ │ ├── zip_error_strerror.man │ │ │ ├── zip_error_strerror.mdoc │ │ │ ├── zip_error_system_type.html │ │ │ ├── zip_error_system_type.man │ │ │ ├── zip_error_system_type.mdoc │ │ │ ├── zip_error_to_data.html │ │ │ ├── zip_error_to_data.man │ │ │ ├── zip_error_to_data.mdoc │ │ │ ├── zip_error_to_str.html │ │ │ ├── zip_error_to_str.man │ │ │ ├── zip_error_to_str.mdoc │ │ │ ├── zip_errors.html │ │ │ ├── zip_errors.man │ │ │ ├── zip_errors.mdoc │ │ │ ├── zip_fclose.html │ │ │ ├── zip_fclose.man │ │ │ ├── zip_fclose.mdoc │ │ │ ├── zip_fdopen.html │ │ │ ├── zip_fdopen.man │ │ │ ├── zip_fdopen.mdoc │ │ │ ├── zip_file.html │ │ │ ├── zip_file.man │ │ │ ├── zip_file.mdoc │ │ │ ├── zip_file_add.html │ │ │ ├── zip_file_add.man │ │ │ ├── zip_file_add.mdoc │ │ │ ├── zip_file_attributes_init.html │ │ │ ├── zip_file_attributes_init.man │ │ │ ├── zip_file_attributes_init.mdoc │ │ │ ├── zip_file_extra_field_delete.html │ │ │ ├── zip_file_extra_field_delete.man │ │ │ ├── zip_file_extra_field_delete.mdoc │ │ │ ├── zip_file_extra_field_get.html │ │ │ ├── zip_file_extra_field_get.man │ │ │ ├── zip_file_extra_field_get.mdoc │ │ │ ├── zip_file_extra_field_set.html │ │ │ ├── zip_file_extra_field_set.man │ │ │ ├── zip_file_extra_field_set.mdoc │ │ │ ├── zip_file_extra_fields_count.html │ │ │ ├── zip_file_extra_fields_count.man │ │ │ ├── zip_file_extra_fields_count.mdoc │ │ │ ├── zip_file_get_comment.html │ │ │ ├── zip_file_get_comment.man │ │ │ ├── zip_file_get_comment.mdoc │ │ │ ├── zip_file_get_error.html │ │ │ ├── zip_file_get_error.man │ │ │ ├── zip_file_get_error.mdoc │ │ │ ├── zip_file_get_external_attributes.html │ │ │ ├── zip_file_get_external_attributes.man │ │ │ ├── zip_file_get_external_attributes.mdoc │ │ │ ├── zip_file_rename.html │ │ │ ├── zip_file_rename.man │ │ │ ├── zip_file_rename.mdoc │ │ │ ├── zip_file_set_comment.html │ │ │ ├── zip_file_set_comment.man │ │ │ ├── zip_file_set_comment.mdoc │ │ │ ├── zip_file_set_encryption.html │ │ │ ├── zip_file_set_encryption.man │ │ │ ├── zip_file_set_encryption.mdoc │ │ │ ├── zip_file_set_external_attributes.html │ │ │ ├── zip_file_set_external_attributes.man │ │ │ ├── zip_file_set_external_attributes.mdoc │ │ │ ├── zip_file_set_mtime.html │ │ │ ├── zip_file_set_mtime.man │ │ │ ├── zip_file_set_mtime.mdoc │ │ │ ├── zip_file_strerror.html │ │ │ ├── zip_file_strerror.man │ │ │ ├── zip_file_strerror.mdoc │ │ │ ├── zip_fopen.html │ │ │ ├── zip_fopen.man │ │ │ ├── zip_fopen.mdoc │ │ │ ├── zip_fopen_encrypted.html │ │ │ ├── zip_fopen_encrypted.man │ │ │ ├── zip_fopen_encrypted.mdoc │ │ │ ├── zip_fread.html │ │ │ ├── zip_fread.man │ │ │ ├── zip_fread.mdoc │ │ │ ├── zip_fseek.html │ │ │ ├── zip_fseek.man │ │ │ ├── zip_fseek.mdoc │ │ │ ├── zip_ftell.html │ │ │ ├── zip_ftell.man │ │ │ ├── zip_ftell.mdoc │ │ │ ├── zip_get_archive_comment.html │ │ │ ├── zip_get_archive_comment.man │ │ │ ├── zip_get_archive_comment.mdoc │ │ │ ├── zip_get_archive_flag.html │ │ │ ├── zip_get_archive_flag.man │ │ │ ├── zip_get_archive_flag.mdoc │ │ │ ├── zip_get_error.html │ │ │ ├── zip_get_error.man │ │ │ ├── zip_get_error.mdoc │ │ │ ├── zip_get_file_comment.html │ │ │ ├── zip_get_file_comment.man │ │ │ ├── zip_get_file_comment.mdoc │ │ │ ├── zip_get_name.html │ │ │ ├── zip_get_name.man │ │ │ ├── zip_get_name.mdoc │ │ │ ├── zip_get_num_entries.html │ │ │ ├── zip_get_num_entries.man │ │ │ ├── zip_get_num_entries.mdoc │ │ │ ├── zip_get_num_files.html │ │ │ ├── zip_get_num_files.man │ │ │ ├── zip_get_num_files.mdoc │ │ │ ├── zip_libzip_version.html │ │ │ ├── zip_libzip_version.man │ │ │ ├── zip_libzip_version.mdoc │ │ │ ├── zip_name_locate.html │ │ │ ├── zip_name_locate.man │ │ │ ├── zip_name_locate.mdoc │ │ │ ├── zip_open.html │ │ │ ├── zip_open.man │ │ │ ├── zip_open.mdoc │ │ │ ├── zip_register_cancel_callback_with_state.html │ │ │ ├── zip_register_cancel_callback_with_state.man │ │ │ ├── zip_register_cancel_callback_with_state.mdoc │ │ │ ├── zip_register_progress_callback.html │ │ │ ├── zip_register_progress_callback.man │ │ │ ├── zip_register_progress_callback.mdoc │ │ │ ├── zip_register_progress_callback_with_state.html │ │ │ ├── zip_register_progress_callback_with_state.man │ │ │ ├── zip_register_progress_callback_with_state.mdoc │ │ │ ├── zip_rename.html │ │ │ ├── zip_rename.man │ │ │ ├── zip_rename.mdoc │ │ │ ├── zip_set_archive_comment.html │ │ │ ├── zip_set_archive_comment.man │ │ │ ├── zip_set_archive_comment.mdoc │ │ │ ├── zip_set_archive_flag.html │ │ │ ├── zip_set_archive_flag.man │ │ │ ├── zip_set_archive_flag.mdoc │ │ │ ├── zip_set_default_password.html │ │ │ ├── zip_set_default_password.man │ │ │ ├── zip_set_default_password.mdoc │ │ │ ├── zip_set_file_comment.html │ │ │ ├── zip_set_file_comment.man │ │ │ ├── zip_set_file_comment.mdoc │ │ │ ├── zip_set_file_compression.html │ │ │ ├── zip_set_file_compression.man │ │ │ ├── zip_set_file_compression.mdoc │ │ │ ├── zip_source.html │ │ │ ├── zip_source.man │ │ │ ├── zip_source.mdoc │ │ │ ├── zip_source_begin_write.html │ │ │ ├── zip_source_begin_write.man │ │ │ ├── zip_source_begin_write.mdoc │ │ │ ├── zip_source_buffer.html │ │ │ ├── zip_source_buffer.man │ │ │ ├── zip_source_buffer.mdoc │ │ │ ├── zip_source_buffer_fragment.html │ │ │ ├── zip_source_buffer_fragment.man │ │ │ ├── zip_source_buffer_fragment.mdoc │ │ │ ├── zip_source_close.html │ │ │ ├── zip_source_close.man │ │ │ ├── zip_source_close.mdoc │ │ │ ├── zip_source_commit_write.html │ │ │ ├── zip_source_commit_write.man │ │ │ ├── zip_source_commit_write.mdoc │ │ │ ├── zip_source_error.html │ │ │ ├── zip_source_error.man │ │ │ ├── zip_source_error.mdoc │ │ │ ├── zip_source_file.html │ │ │ ├── zip_source_file.man │ │ │ ├── zip_source_file.mdoc │ │ │ ├── zip_source_filep.html │ │ │ ├── zip_source_filep.man │ │ │ ├── zip_source_filep.mdoc │ │ │ ├── zip_source_free.html │ │ │ ├── zip_source_free.man │ │ │ ├── zip_source_free.mdoc │ │ │ ├── zip_source_function.html │ │ │ ├── zip_source_function.man │ │ │ ├── zip_source_function.mdoc │ │ │ ├── zip_source_is_deleted.html │ │ │ ├── zip_source_is_deleted.man │ │ │ ├── zip_source_is_deleted.mdoc │ │ │ ├── zip_source_is_seekable.html │ │ │ ├── zip_source_is_seekable.man │ │ │ ├── zip_source_is_seekable.mdoc │ │ │ ├── zip_source_keep.html │ │ │ ├── zip_source_keep.man │ │ │ ├── zip_source_keep.mdoc │ │ │ ├── zip_source_layered.html │ │ │ ├── zip_source_layered.man │ │ │ ├── zip_source_layered.mdoc │ │ │ ├── zip_source_make_command_bitmap.html │ │ │ ├── zip_source_make_command_bitmap.man │ │ │ ├── zip_source_make_command_bitmap.mdoc │ │ │ ├── zip_source_open.html │ │ │ ├── zip_source_open.man │ │ │ ├── zip_source_open.mdoc │ │ │ ├── zip_source_pass_to_lower_layer.mdoc │ │ │ ├── zip_source_read.html │ │ │ ├── zip_source_read.man │ │ │ ├── zip_source_read.mdoc │ │ │ ├── zip_source_rollback_write.html │ │ │ ├── zip_source_rollback_write.man │ │ │ ├── zip_source_rollback_write.mdoc │ │ │ ├── zip_source_seek.html │ │ │ ├── zip_source_seek.man │ │ │ ├── zip_source_seek.mdoc │ │ │ ├── zip_source_seek_compute_offset.html │ │ │ ├── zip_source_seek_compute_offset.man │ │ │ ├── zip_source_seek_compute_offset.mdoc │ │ │ ├── zip_source_seek_write.html │ │ │ ├── zip_source_seek_write.man │ │ │ ├── zip_source_seek_write.mdoc │ │ │ ├── zip_source_stat.html │ │ │ ├── zip_source_stat.man │ │ │ ├── zip_source_stat.mdoc │ │ │ ├── zip_source_tell.html │ │ │ ├── zip_source_tell.man │ │ │ ├── zip_source_tell.mdoc │ │ │ ├── zip_source_tell_write.html │ │ │ ├── zip_source_tell_write.man │ │ │ ├── zip_source_tell_write.mdoc │ │ │ ├── zip_source_win32a.html │ │ │ ├── zip_source_win32a.man │ │ │ ├── zip_source_win32a.mdoc │ │ │ ├── zip_source_win32handle.html │ │ │ ├── zip_source_win32handle.man │ │ │ ├── zip_source_win32handle.mdoc │ │ │ ├── zip_source_win32w.html │ │ │ ├── zip_source_win32w.man │ │ │ ├── zip_source_win32w.mdoc │ │ │ ├── zip_source_window_create.html │ │ │ ├── zip_source_window_create.man │ │ │ ├── zip_source_window_create.mdoc │ │ │ ├── zip_source_write.html │ │ │ ├── zip_source_write.man │ │ │ ├── zip_source_write.mdoc │ │ │ ├── zip_source_zip.html │ │ │ ├── zip_source_zip.man │ │ │ ├── zip_source_zip.mdoc │ │ │ ├── zip_source_zip_file.html │ │ │ ├── zip_source_zip_file.man │ │ │ ├── zip_source_zip_file.mdoc │ │ │ ├── zip_stat.html │ │ │ ├── zip_stat.man │ │ │ ├── zip_stat.mdoc │ │ │ ├── zip_stat_init.html │ │ │ ├── zip_stat_init.man │ │ │ ├── zip_stat_init.mdoc │ │ │ ├── zip_unchange.html │ │ │ ├── zip_unchange.man │ │ │ ├── zip_unchange.mdoc │ │ │ ├── zip_unchange_all.html │ │ │ ├── zip_unchange_all.man │ │ │ ├── zip_unchange_all.mdoc │ │ │ ├── zip_unchange_archive.html │ │ │ ├── zip_unchange_archive.man │ │ │ ├── zip_unchange_archive.mdoc │ │ │ ├── zipcmp.html │ │ │ ├── zipcmp.man │ │ │ ├── zipcmp.mdoc │ │ │ ├── zipmerge.html │ │ │ ├── zipmerge.man │ │ │ ├── zipmerge.mdoc │ │ │ ├── ziptool.html │ │ │ ├── ziptool.man │ │ │ └── ziptool.mdoc │ │ ├── ossfuzz/ │ │ │ ├── CMakeLists.txt │ │ │ ├── fuzz_main.c │ │ │ ├── ossfuzz.sh │ │ │ ├── zip_read_file_fuzzer.c │ │ │ ├── zip_read_fuzzer.c │ │ │ ├── zip_read_fuzzer.dict │ │ │ ├── zip_read_fuzzer_common.h │ │ │ ├── zip_write_encrypt_aes256_file_fuzzer.c │ │ │ └── zip_write_encrypt_pkware_file_fuzzer.c │ │ ├── regress/ │ │ │ ├── CMakeLists.txt │ │ │ ├── add_dir.test │ │ │ ├── add_from_buffer.test │ │ │ ├── add_from_file.test │ │ │ ├── add_from_file_duplicate.test │ │ │ ├── add_from_file_twice_duplicate.test │ │ │ ├── add_from_file_unchange.test │ │ │ ├── add_from_filep.c │ │ │ ├── add_from_filep.test │ │ │ ├── add_from_stdin.test │ │ │ ├── add_from_zip_closed.test │ │ │ ├── add_from_zip_deflated.test │ │ │ ├── add_from_zip_deflated2.test │ │ │ ├── add_from_zip_partial_deflated.test │ │ │ ├── add_from_zip_partial_stored.test │ │ │ ├── add_from_zip_stored.test │ │ │ ├── add_stored.test │ │ │ ├── add_stored_in_memory.test │ │ │ ├── bigstored.zh │ │ │ ├── buffer-fragment-read.test │ │ │ ├── buffer-fragment-write.test │ │ │ ├── can_clone_file.c │ │ │ ├── cancel_45.test │ │ │ ├── cancel_90.test │ │ │ ├── changing-size-decreases-fixed.test │ │ │ ├── changing-size-decreases.test │ │ │ ├── changing-size-increases-fixed.test │ │ │ ├── changing-size-increases-unchecked.test │ │ │ ├── changing-size-increases.test │ │ │ ├── check_torrentzip_fail.test │ │ │ ├── check_torrentzip_modified.test │ │ │ ├── check_torrentzip_success.test │ │ │ ├── cleanup.cmake │ │ │ ├── clone-buffer-add.test │ │ │ ├── clone-buffer-delete.test │ │ │ ├── clone-buffer-replace.test │ │ │ ├── clone-fs-add.test │ │ │ ├── clone-fs-delete.test │ │ │ ├── clone-fs-replace.test │ │ │ ├── cm-default.test │ │ │ ├── convert_to_torrentzip.test │ │ │ ├── convert_to_torrentzip_ef.test │ │ │ ├── count_entries.test │ │ │ ├── create_empty_keep.test │ │ │ ├── decrypt-correct-password-aes128.test │ │ │ ├── decrypt-correct-password-aes192.test │ │ │ ├── decrypt-correct-password-aes256.test │ │ │ ├── decrypt-correct-password-pkware-2.test │ │ │ ├── decrypt-correct-password-pkware.test │ │ │ ├── decrypt-empty-file-pkware.test │ │ │ ├── decrypt-no-password-aes256.test │ │ │ ├── decrypt-wrong-password-aes128.test │ │ │ ├── decrypt-wrong-password-aes192.test │ │ │ ├── decrypt-wrong-password-aes256.test │ │ │ ├── decrypt-wrong-password-pkware-2.test │ │ │ ├── decrypt-wrong-password-pkware.test │ │ │ ├── delete_add_same.test │ │ │ ├── delete_invalid.test │ │ │ ├── delete_last.test │ │ │ ├── delete_last_keep.test │ │ │ ├── delete_multiple_last.test │ │ │ ├── delete_multiple_partial.test │ │ │ ├── delete_renamed_rename.test │ │ │ ├── encrypt.test │ │ │ ├── encryption-nonrandom-aes128.test │ │ │ ├── encryption-nonrandom-aes192.test │ │ │ ├── encryption-nonrandom-aes256.test │ │ │ ├── encryption-nonrandom-pkware-2.test │ │ │ ├── encryption-nonrandom-pkware.test │ │ │ ├── encryption-remove.test │ │ │ ├── encryption-stat.test │ │ │ ├── extra_add.test │ │ │ ├── extra_add_multiple.test │ │ │ ├── extra_count.test │ │ │ ├── extra_count_by_id.test │ │ │ ├── extra_count_ignore_zip64.test │ │ │ ├── extra_delete.test │ │ │ ├── extra_delete_by_id.test │ │ │ ├── extra_field_align.test │ │ │ ├── extra_get.test │ │ │ ├── extra_get_by_id.test │ │ │ ├── extra_set.test │ │ │ ├── extra_set_modify_c.test │ │ │ ├── extra_set_modify_l.test │ │ │ ├── fdopen_ok.test │ │ │ ├── file_comment_encmismatch.test │ │ │ ├── fopen_multiple.test │ │ │ ├── fopen_multiple_reopen.test │ │ │ ├── fopen_unchanged.c │ │ │ ├── fopen_unchanged.test │ │ │ ├── fread.c │ │ │ ├── fread.test │ │ │ ├── fseek.c │ │ │ ├── fseek_deflated.test │ │ │ ├── fseek_fail.test │ │ │ ├── fseek_ok.test │ │ │ ├── get_comment.test │ │ │ ├── get_comment_long.test │ │ │ ├── hmac-error.test │ │ │ ├── hole.c │ │ │ ├── junk_at_end.test │ │ │ ├── junk_at_start.test │ │ │ ├── large-uncompressible │ │ │ ├── liboverride-test.c │ │ │ ├── liboverride.c │ │ │ ├── malloc.c │ │ │ ├── mtime-dstpoint.test │ │ │ ├── mtime-post-dstpoint.test │ │ │ ├── mtime-pre-dstpoint.test │ │ │ ├── name_locate-cp437.test │ │ │ ├── name_locate-utf8.test │ │ │ ├── name_locate.test │ │ │ ├── nihtest.conf.in │ │ │ ├── nonrandomopen.c │ │ │ ├── nonrandomopentest.c │ │ │ ├── open_archive_comment_wrong.test │ │ │ ├── open_cons_extrabytes.test │ │ │ ├── open_empty.test │ │ │ ├── open_empty_2.test │ │ │ ├── open_extrabytes.test │ │ │ ├── open_file_count.test │ │ │ ├── open_filename_duplicate.test │ │ │ ├── open_filename_duplicate_consistency.test │ │ │ ├── open_filename_duplicate_empty.test │ │ │ ├── open_filename_duplicate_empty_consistency.test │ │ │ ├── open_filename_empty.test │ │ │ ├── open_incons.test │ │ │ ├── open_many_fail.test │ │ │ ├── open_many_ok.test │ │ │ ├── open_multidisk.test │ │ │ ├── open_new_but_exists.test │ │ │ ├── open_new_ok.test │ │ │ ├── open_nonarchive.test │ │ │ ├── open_nosuchfile.test │ │ │ ├── open_ok.test │ │ │ ├── open_too_short.test │ │ │ ├── open_truncate.test │ │ │ ├── open_truncated.test │ │ │ ├── open_zip64_3mf.test │ │ │ ├── open_zip64_ok.test │ │ │ ├── preload.test │ │ │ ├── progress.test │ │ │ ├── read_incons.test │ │ │ ├── read_seek_read.test │ │ │ ├── rename_ascii.test │ │ │ ├── rename_cp437.test │ │ │ ├── rename_deleted.test │ │ │ ├── rename_fail.test │ │ │ ├── rename_ok.test │ │ │ ├── rename_utf8.test │ │ │ ├── rename_utf8_encmismatch.test │ │ │ ├── reopen.test │ │ │ ├── reopen_partial.test │ │ │ ├── reopen_partial_rest.test │ │ │ ├── replace_set_stored.test │ │ │ ├── set_comment_all.test │ │ │ ├── set_comment_localonly.test │ │ │ ├── set_comment_removeglobal.test │ │ │ ├── set_comment_revert.test │ │ │ ├── set_compression_bzip2_to_deflate.test │ │ │ ├── set_compression_deflate_to_bzip2.test │ │ │ ├── set_compression_deflate_to_deflate.test │ │ │ ├── set_compression_deflate_to_store.test │ │ │ ├── set_compression_lzma_no_eos_to_store.test │ │ │ ├── set_compression_lzma_to_store.test │ │ │ ├── set_compression_store_to_bzip2.test │ │ │ ├── set_compression_store_to_deflate.test │ │ │ ├── set_compression_store_to_lzma.test │ │ │ ├── set_compression_store_to_store.test │ │ │ ├── set_compression_store_to_xz.test │ │ │ ├── set_compression_store_to_zstd.test │ │ │ ├── set_compression_unknown.test │ │ │ ├── set_compression_xz_to_store.test │ │ │ ├── set_compression_zstd_to_store.test │ │ │ ├── set_file_dostime.test │ │ │ ├── set_file_mtime.test │ │ │ ├── set_file_mtime_pkware.test │ │ │ ├── short │ │ │ ├── source_hole.c │ │ │ ├── stat_index_cp437_guess.test │ │ │ ├── stat_index_cp437_raw.test │ │ │ ├── stat_index_cp437_strict.test │ │ │ ├── stat_index_fileorder.test │ │ │ ├── stat_index_streamed.test │ │ │ ├── stat_index_streamed_zip64.test │ │ │ ├── stat_index_utf8_guess.test │ │ │ ├── stat_index_utf8_raw.test │ │ │ ├── stat_index_utf8_strict.test │ │ │ ├── stat_index_utf8_unmarked_strict.test │ │ │ ├── stat_index_zip64.test │ │ │ ├── testfile.txt │ │ │ ├── truncate_empty_keep.test │ │ │ ├── tryopen.c │ │ │ ├── unchange-delete-namelocate.test │ │ │ ├── utf-8-standardization.test │ │ │ ├── want_torrentzip_stat.test │ │ │ ├── zip-in-archive-comment.test │ │ │ ├── zip64-in-archive-comment.test │ │ │ ├── zip64_creation.test │ │ │ ├── zip64_stored_creation.test │ │ │ ├── zipcmp_zip_dir.test │ │ │ ├── zipcmp_zip_dir_slash.test │ │ │ └── ziptool_regress.c │ │ ├── src/ │ │ │ ├── CMakeLists.txt │ │ │ ├── diff_output.c │ │ │ ├── diff_output.h │ │ │ ├── getopt.c │ │ │ ├── getopt.h │ │ │ ├── zipcmp.c │ │ │ ├── zipmerge.c │ │ │ └── ziptool.c │ │ ├── vcpkg.json │ │ └── zipconf.h.in │ ├── pdfium/ │ │ ├── README.md │ │ ├── linux-x64/ │ │ │ ├── LICENSE │ │ │ ├── PDFiumConfig.cmake │ │ │ ├── VERSION │ │ │ ├── args.gn │ │ │ ├── include/ │ │ │ │ ├── cpp/ │ │ │ │ │ ├── fpdf_deleters.h │ │ │ │ │ └── fpdf_scopers.h │ │ │ │ ├── fpdf_annot.h │ │ │ │ ├── fpdf_attachment.h │ │ │ │ ├── fpdf_catalog.h │ │ │ │ ├── fpdf_dataavail.h │ │ │ │ ├── fpdf_doc.h │ │ │ │ ├── fpdf_edit.h │ │ │ │ ├── fpdf_ext.h │ │ │ │ ├── fpdf_flatten.h │ │ │ │ ├── fpdf_formfill.h │ │ │ │ ├── fpdf_fwlevent.h │ │ │ │ ├── fpdf_javascript.h │ │ │ │ ├── fpdf_ppo.h │ │ │ │ ├── fpdf_progressive.h │ │ │ │ ├── fpdf_save.h │ │ │ │ ├── fpdf_searchex.h │ │ │ │ ├── fpdf_signature.h │ │ │ │ ├── fpdf_structtree.h │ │ │ │ ├── fpdf_sysfontinfo.h │ │ │ │ ├── fpdf_text.h │ │ │ │ ├── fpdf_thumbnail.h │ │ │ │ ├── fpdf_transformpage.h │ │ │ │ ├── fpdfview.h │ │ │ │ └── fpdfview.h.orig │ │ │ └── licenses/ │ │ │ ├── abseil.txt │ │ │ ├── agg23.txt │ │ │ ├── fast_float.txt │ │ │ ├── freetype.txt │ │ │ ├── icu.txt │ │ │ ├── lcms.txt │ │ │ ├── libjpeg_turbo.ijg │ │ │ ├── libjpeg_turbo.md │ │ │ ├── libopenjpeg.txt │ │ │ ├── libpng.txt │ │ │ ├── libtiff.txt │ │ │ ├── llvm-libc.txt │ │ │ ├── pdfium.txt │ │ │ ├── simdutf.txt │ │ │ └── zlib.txt │ │ ├── macos-arm64/ │ │ │ ├── LICENSE │ │ │ ├── PDFiumConfig.cmake │ │ │ ├── VERSION │ │ │ ├── args.gn │ │ │ ├── include/ │ │ │ │ ├── cpp/ │ │ │ │ │ ├── fpdf_deleters.h │ │ │ │ │ └── fpdf_scopers.h │ │ │ │ ├── fpdf_annot.h │ │ │ │ ├── fpdf_attachment.h │ │ │ │ ├── fpdf_catalog.h │ │ │ │ ├── fpdf_dataavail.h │ │ │ │ ├── fpdf_doc.h │ │ │ │ ├── fpdf_edit.h │ │ │ │ ├── fpdf_ext.h │ │ │ │ ├── fpdf_flatten.h │ │ │ │ ├── fpdf_formfill.h │ │ │ │ ├── fpdf_fwlevent.h │ │ │ │ ├── fpdf_javascript.h │ │ │ │ ├── fpdf_ppo.h │ │ │ │ ├── fpdf_progressive.h │ │ │ │ ├── fpdf_save.h │ │ │ │ ├── fpdf_searchex.h │ │ │ │ ├── fpdf_signature.h │ │ │ │ ├── fpdf_structtree.h │ │ │ │ ├── fpdf_sysfontinfo.h │ │ │ │ ├── fpdf_text.h │ │ │ │ ├── fpdf_thumbnail.h │ │ │ │ ├── fpdf_transformpage.h │ │ │ │ ├── fpdfview.h │ │ │ │ └── fpdfview.h.orig │ │ │ └── licenses/ │ │ │ ├── abseil.txt │ │ │ ├── agg23.txt │ │ │ ├── fast_float.txt │ │ │ ├── freetype.txt │ │ │ ├── icu.txt │ │ │ ├── lcms.txt │ │ │ ├── libjpeg_turbo.ijg │ │ │ ├── libjpeg_turbo.md │ │ │ ├── libopenjpeg.txt │ │ │ ├── libpng.txt │ │ │ ├── libtiff.txt │ │ │ ├── llvm-libc.txt │ │ │ ├── pdfium.txt │ │ │ ├── simdutf.txt │ │ │ └── zlib.txt │ │ ├── macos-x64/ │ │ │ ├── LICENSE │ │ │ ├── PDFiumConfig.cmake │ │ │ ├── VERSION │ │ │ ├── args.gn │ │ │ ├── include/ │ │ │ │ ├── cpp/ │ │ │ │ │ ├── fpdf_deleters.h │ │ │ │ │ └── fpdf_scopers.h │ │ │ │ ├── fpdf_annot.h │ │ │ │ ├── fpdf_attachment.h │ │ │ │ ├── fpdf_catalog.h │ │ │ │ ├── fpdf_dataavail.h │ │ │ │ ├── fpdf_doc.h │ │ │ │ ├── fpdf_edit.h │ │ │ │ ├── fpdf_ext.h │ │ │ │ ├── fpdf_flatten.h │ │ │ │ ├── fpdf_formfill.h │ │ │ │ ├── fpdf_fwlevent.h │ │ │ │ ├── fpdf_javascript.h │ │ │ │ ├── fpdf_ppo.h │ │ │ │ ├── fpdf_progressive.h │ │ │ │ ├── fpdf_save.h │ │ │ │ ├── fpdf_searchex.h │ │ │ │ ├── fpdf_signature.h │ │ │ │ ├── fpdf_structtree.h │ │ │ │ ├── fpdf_sysfontinfo.h │ │ │ │ ├── fpdf_text.h │ │ │ │ ├── fpdf_thumbnail.h │ │ │ │ ├── fpdf_transformpage.h │ │ │ │ ├── fpdfview.h │ │ │ │ └── fpdfview.h.orig │ │ │ └── licenses/ │ │ │ ├── abseil.txt │ │ │ ├── agg23.txt │ │ │ ├── fast_float.txt │ │ │ ├── freetype.txt │ │ │ ├── icu.txt │ │ │ ├── lcms.txt │ │ │ ├── libjpeg_turbo.ijg │ │ │ ├── libjpeg_turbo.md │ │ │ ├── libopenjpeg.txt │ │ │ ├── libpng.txt │ │ │ ├── libtiff.txt │ │ │ ├── llvm-libc.txt │ │ │ ├── pdfium.txt │ │ │ ├── simdutf.txt │ │ │ └── zlib.txt │ │ └── windows-x64/ │ │ ├── LICENSE │ │ ├── PDFiumConfig.cmake │ │ ├── VERSION │ │ ├── args.gn │ │ ├── include/ │ │ │ ├── cpp/ │ │ │ │ ├── fpdf_deleters.h │ │ │ │ └── fpdf_scopers.h │ │ │ ├── fpdf_annot.h │ │ │ ├── fpdf_attachment.h │ │ │ ├── fpdf_catalog.h │ │ │ ├── fpdf_dataavail.h │ │ │ ├── fpdf_doc.h │ │ │ ├── fpdf_edit.h │ │ │ ├── fpdf_ext.h │ │ │ ├── fpdf_flatten.h │ │ │ ├── fpdf_formfill.h │ │ │ ├── fpdf_fwlevent.h │ │ │ ├── fpdf_javascript.h │ │ │ ├── fpdf_ppo.h │ │ │ ├── fpdf_progressive.h │ │ │ ├── fpdf_save.h │ │ │ ├── fpdf_searchex.h │ │ │ ├── fpdf_signature.h │ │ │ ├── fpdf_structtree.h │ │ │ ├── fpdf_sysfontinfo.h │ │ │ ├── fpdf_text.h │ │ │ ├── fpdf_thumbnail.h │ │ │ ├── fpdf_transformpage.h │ │ │ ├── fpdfview.h │ │ │ └── fpdfview.h.orig │ │ ├── lib/ │ │ │ └── pdfium.dll.lib │ │ └── licenses/ │ │ ├── abseil.txt │ │ ├── agg23.txt │ │ ├── fast_float.txt │ │ ├── freetype.txt │ │ ├── icu.txt │ │ ├── lcms.txt │ │ ├── libjpeg_turbo.ijg │ │ ├── libjpeg_turbo.md │ │ ├── libopenjpeg.txt │ │ ├── libpng.txt │ │ ├── libtiff.txt │ │ ├── llvm-libc.txt │ │ ├── pdfium.txt │ │ ├── simdutf.txt │ │ └── zlib.txt │ └── pugixml/ │ ├── CMakeLists.txt │ ├── LICENSE.md │ ├── docs/ │ │ ├── manual.html │ │ ├── quickstart.html │ │ └── samples/ │ │ ├── character.xml │ │ ├── custom_memory_management.cpp │ │ ├── include.cpp │ │ ├── load_error_handling.cpp │ │ ├── load_file.cpp │ │ ├── load_memory.cpp │ │ ├── load_options.cpp │ │ ├── load_stream.cpp │ │ ├── modify_add.cpp │ │ ├── modify_base.cpp │ │ ├── modify_remove.cpp │ │ ├── save_custom_writer.cpp │ │ ├── save_declaration.cpp │ │ ├── save_file.cpp │ │ ├── save_options.cpp │ │ ├── save_stream.cpp │ │ ├── save_subtree.cpp │ │ ├── text.cpp │ │ ├── transitions.xml │ │ ├── traverse_base.cpp │ │ ├── traverse_iter.cpp │ │ ├── traverse_predicate.cpp │ │ ├── traverse_rangefor.cpp │ │ ├── traverse_walker.cpp │ │ ├── tree.xml │ │ ├── weekly-shift_jis.xml │ │ ├── weekly-utf-16.xml │ │ ├── weekly-utf-8.xml │ │ ├── xgconsole.xml │ │ ├── xpath_error.cpp │ │ ├── xpath_query.cpp │ │ ├── xpath_select.cpp │ │ └── xpath_variables.cpp │ ├── readme.txt │ ├── scripts/ │ │ ├── cocoapods_push.sh │ │ ├── natvis/ │ │ │ ├── pugixml.natvis │ │ │ └── pugixml_compact.natvis │ │ ├── nuget/ │ │ │ └── pugixml.nuspec │ │ ├── nuget_build.ps1 │ │ ├── premake4.lua │ │ ├── pugixml-config.cmake.in │ │ ├── pugixml.pc.in │ │ ├── pugixml.podspec │ │ ├── pugixml.xcodeproj/ │ │ │ └── project.pbxproj │ │ ├── pugixml_airplay.mkf │ │ ├── pugixml_codeblocks.cbp │ │ ├── pugixml_codelite.project │ │ ├── pugixml_dll.rc │ │ ├── pugixml_vs2005.vcproj │ │ ├── pugixml_vs2005_static.vcproj │ │ ├── pugixml_vs2008.vcproj │ │ ├── pugixml_vs2008_static.vcproj │ │ ├── pugixml_vs2010.vcxproj │ │ ├── pugixml_vs2010_static.vcxproj │ │ ├── pugixml_vs2013.vcxproj │ │ ├── pugixml_vs2013_static.vcxproj │ │ ├── pugixml_vs2015.vcxproj │ │ ├── pugixml_vs2015_static.vcxproj │ │ ├── pugixml_vs2017.vcxproj │ │ ├── pugixml_vs2017_static.vcxproj │ │ ├── pugixml_vs2019.vcxproj │ │ ├── pugixml_vs2019_static.vcxproj │ │ ├── pugixml_vs2022.vcxproj │ │ ├── pugixml_vs2022_static.vcxproj │ │ └── sbom.cdx.json │ └── src/ │ ├── pugiconfig.hpp │ ├── pugixml.cpp │ └── pugixml.hpp └── tests/ ├── .gitignore ├── run_all_tests.sh ├── run_database_tests.sh ├── run_translation_tests.sh └── unit/ ├── TestHelpers.hpp ├── test_cache_interactions.cpp ├── test_categorization_dialog.cpp ├── test_checkbox_matrix.cpp ├── test_cli_reporter.cpp ├── test_custom_api_endpoint.cpp ├── test_custom_llm.cpp ├── test_database_manager_rename_only.cpp ├── test_file_scanner.cpp ├── test_ggml_runtime_paths.cpp ├── test_image_rename_metadata_service.cpp ├── test_llava_image_analyzer.cpp ├── test_llm_downloader.cpp ├── test_llm_selection_dialog_visual.cpp ├── test_local_llm_backend.cpp ├── test_main_app_image_options.cpp ├── test_main_app_translation.cpp ├── test_main_app_visual_fallback.cpp ├── test_media_rename_metadata_service.cpp ├── test_review_dialog_rename_gate.cpp ├── test_settings_image_options.cpp ├── test_support_prompt.cpp ├── test_ui_translator.cpp ├── test_update_feed.cpp ├── test_updater.cpp ├── test_updater_build_modes.cpp ├── test_utils.cpp └── test_whitelist_and_prompt.cpp ================================================ FILE CONTENTS ================================================ ================================================ FILE: .clang-format ================================================ BasedOnStyle: Google IndentWidth: 4 TabWidth: 4 UseTab: Never ColumnLimit: 120 BreakBeforeBraces: Attach AllowShortFunctionsOnASingleLine: Inline PointerAlignment: Left DerivePointerAlignment: false SpacesInParentheses: false SpaceAfterCStyleCast: true SpaceBeforeParens: ControlStatements SortIncludes: true ================================================ FILE: .github/workflows/build.yml ================================================ name: Build on: pull_request: branches: [ main, dev ] jobs: build-linux: runs-on: ${{ matrix.os }} strategy: matrix: os: [ubuntu-latest] steps: - name: Check out repository uses: actions/checkout@v4 with: submodules: recursive - name: Set up Qt uses: jurplel/install-qt-action@v3 with: version: '6.6.3' host: linux target: desktop - name: Install dependencies run: | sudo apt-get update sudo apt-get install -y build-essential cmake ninja-build libcurl4-openssl-dev libjsoncpp-dev libsqlite3-dev libssl-dev libfmt-dev libspdlog-dev - name: Configure run: | cmake -S app -B build -G "Ninja" -DCMAKE_BUILD_TYPE=Release - name: Build run: cmake --build build - name: Run ctest run: cd build && ctest --output-on-failure build-windows: runs-on: windows-latest steps: - name: Check out repository uses: actions/checkout@v4 with: submodules: recursive - name: Enable long paths run: git config --system core.longpaths true - name: Set up vcpkg shell: pwsh run: | git clone https://github.com/microsoft/vcpkg.git "$env:GITHUB_WORKSPACE\vcpkg" & "$env:GITHUB_WORKSPACE\vcpkg\bootstrap-vcpkg.bat" - name: Build llama runtime shell: pwsh run: | $vcpkgRoot = "$env:GITHUB_WORKSPACE\vcpkg" & "$env:GITHUB_WORKSPACE\app\scripts\build_llama_windows.ps1" ` "cuda=off" ` "vulkan=off" ` "blas=off" ` "vcpkgroot=$vcpkgRoot" - name: Build and test Windows app shell: pwsh run: | $vcpkgRoot = "$env:GITHUB_WORKSPACE\vcpkg" & "$env:GITHUB_WORKSPACE\app\build_windows.ps1" ` -Configuration Release ` -VcpkgRoot $vcpkgRoot ` -BuildTests ` -RunTests ` -Parallel 4 ================================================ FILE: .gitignore ================================================ # Created by https://www.toptal.com/developers/gitignore/api/c++,visualstudiocode # Edit at https://www.toptal.com/developers/gitignore?templates=c++,visualstudiocode ### C++ ### # Prerequisites *.d # Compiled Object files *.slo *.lo *.o *.obj obj/ # Precompiled Headers *.gch *.pch # Databases *.db # Environment variables # .env encryption.ini # Virtual environments .venv/ # Compiled Dynamic libraries *.so *.dylib *.dll # Fortran module files *.mod *.smod # Compiled Static libraries *.lai *.la *.a *.lib # Executables *.exe *.out *.app main obfuscate_encrypt bin/ # Keep vendored PDFium runtimes in source control. !external/pdfium/**/bin/ !external/pdfium/**/bin/pdfium.dll !external/pdfium/**/lib/ !external/pdfium/**/lib/pdfium.dll.lib !external/pdfium/**/lib/libpdfium.so !external/pdfium/**/lib/libpdfium.dylib # Scripts reset_key_4_github.sh create_macos_bundle.sh create_dmg.sh # Packaging *.nsi *.msix msix/ package_msix.ps1 appcert-AIFileSorter.xml msix-layout/ # References # includePaths.txt ### VisualStudioCode ### .vscode/ .vscode/* !.vscode/settings.json !.vscode/tasks.json !.vscode/launch.json !.vscode/extensions.json !.vscode/*.code-snippets ### Visual Studio vcpkg_installed/ # Local History for Visual Studio Code .history/ # Cache directories .cache/ .ccache*/ .codacy/ # Built Visual Studio Code Extensions *.vsix ### VisualStudioCode Patch ### # Ignore all local history of files .history .ionide # Temp files *.*~ *~ # Temp notes todos_md/ # Mac files .DS_Store # Script docs + backups app/scripts/SCRIPTS-README.md app/scripts/local_support_code_signer.py app/scripts/__pycache__/ *.bak # Ignore llama headers (generated or from external) app/include/llama/*.h # R & D stage /assets/ /docs/ /scripts/ !app/scripts/ /tools/ /reports/ /logo-workdir-temp/ /Testing/ /changelog/ /models/ /rd/ /prototypes/ /store/ms-store/ /.github/workflows/ms-store-listing.yml # Build artifacts build*/ dist/ app/lib/ggml/ # Generated precompiled llama runtime directories app/lib/precompiled*/ external/libzip/build*/ # No longer relevant api-key-encryption/ # End of https://www.toptal.com/developers/gitignore/api/c++,visualstudiocode #Ignore vscode AI rules .github/instructions/codacy.instructions.md ================================================ FILE: .gitmodules ================================================ [submodule "app/include/external/llama.cpp"] path = app/include/external/llama.cpp url = https://github.com/ggerganov/llama.cpp.git ignore = dirty [submodule "external/Catch2"] path = external/Catch2 url = https://github.com/catchorg/Catch2.git ================================================ FILE: CHANGELOG.md ================================================ # Changelog ## [1.7.3] - 2026-03-22 - Non-English categorization is now more reliable: files are categorized canonically in English first, then translated into the selected category language, with localized labels persisted separately from the canonical taxonomy/cache. - App updates now support separate update streams for Windows, macOS, and Linux, while still accepting the legacy single-stream manifest format for newer clients. - Windows feeds can now provide a direct installer URL plus SHA-256 checksum so the app can download the installer, show download progress, verify its integrity, and launch it after confirmation. - The UI translation system was migrated fully to Qt `.ts` / `.qm` catalogs. - Local categorization with local LLMs is now more robust: prompt budgeting, output sanitization, and category/subcategory parsing were hardened so verbose or oddly formatted replies no longer cause widespread invalid categorization failures. - Recursive scans now tolerate unreadable subfolders and other filesystem errors instead of aborting the overall run. - Cached category labels are sanitized more aggressively to avoid malformed UTF-8 data breaking later categorization or display. - macOS local-LLM packaging/runtime handling was hardened: bundled llama/ggml dylibs are now relocatable, and the app no longer falls back to conflicting system/Homebrew ggml libraries during backend loading. - Linux/macOS build and packaging flows were improved, including staged PDFium runtime files, better Debian package dependencies, CPU/CUDA/Vulkan Debian package variants, and improved Homebrew MediaInfo detection on macOS source builds. - Added cross-platform diagnostics collection scripts for Linux, macOS, and Windows. - Misc improvements. - Misc bug fixes. ## [1.7.0] - 2026-03-08 - Progress dialog redesigned into a stage-based table view with explicit stages for Image analysis, Document analysis, and Categorization. - Added an image analysis option to append image creation dates (if available) to category names. - Added optional audio/video metadata-based filename suggestions for supported media files. When enabled, AI File Sorter can use embedded tags (such as ID3, Vorbis comments, and MP4-style metadata) to propose normalized names like `year_artist_album_title.ext` during review. - Bug fixes. ## [1.6.1] - 2026-02-06 - Local text LLM now prompts to switch to CPU when GPU initialization or inference fails. ## [1.6.0] - 2026-02-04 - Added document content analysis (text LLM) with rename-only/document-only options and optional creation-date suffixes for categories. Supported document formats include PDF, DOCX, XLSX, PPTX, ODT, ODS, and ODP (plus common text formats). - Local 3B model download now defaults to Q4 for better GPU compatibility. The legacy Local 3B Q8 is still selectable when an existing download is found. - Improved the LLM selection dialog latency. - Added custom API endpoints to the Select LLM dialog. Custom endpoints accept base URLs or full /chat/completions endpoints, with optional API keys for local servers. - LLM-derived categorizations and rename suggestions are now saved as you go, so progress isn't lost if the app closes unexpectedly. - Image analysis now falls back (with a user prompt) to CPU if the GPU has insufficient available memory. - Review dialog now lets you select highlighted rows and bulk edit their categories. - Review dialog is now scrollable on smaller screens so action buttons stay visible. - Improved subcategory consistency by merging labels that only differ by generic suffixes (e.g., “files”). - Added a system compatibility check (benchmarking) to determine the most suitable LLM for your system. - Added Korean as an interface language. - macOS builds now include variant `make` targets for Apple Silicon (M1 / M2-M3) and Intel outputs, plus improved arch-aware llama.cpp builds. - UI, stability, persistence, and usability improvements. ## [1.5.0] - 2026-01-11 - Added content analysis for picture files via LLaVA (visual LLM), with separate model + mmproj downloads in the Select LLM dialog. - Added image analysis options in the main window (analyze images, offer rename suggestions, rename-only mode). - Added an image-only processing toggle to focus runs on supported picture files and disable standard categorization controls. - Added document content analysis (text LLM) with rename-only/document-only modes and optional creation-date suffixes for categories. - Added support for document formats including PDF, DOCX, XLSX, PPTX, ODT, ODS, and ODP (plus common text formats). - Document analysis now uses embedded PDFium/libzip/pugixml in bundled builds (no pdftotext/unzip requirement). - Review dialog now supports rename-only flows, suggested filename edits, and status labels for Renamed / Renamed & Moved. - Track applied picture renames so already-renamed files are not reprocessed; rename-only review hides them while categorization review keeps them visible for folder moves. - Added Dutch as a selectable interface language. - Analysis progress dialog output is now fully localized (status tags, scan/process lines, and file/directory labels) to match the selected UI language. - Build/test updates: mtmd progress callback auto-detection, mtmd-cli build fix, and new Catch2 tests for rename-only caching. ## [1.4.5] - 2025-12-05 - Added support for Gemini (a remote LLM) - with your own Gemini API key. - Fixed compile under Arch Linux. ## [1.4.0] - 2025-12-05 - Added dry run / preview-only mode with From/To table, no moves performed until you uncheck. - Persistent Undo: the latest sort saves a plan file; use Edit -> "Undo last run" even after closing dialogs. - UI tweaks: Name column auto-resizes, new translations for dry run/undo strings, Undo moved to top of Edit menu. - A few more guard rails added. - Remote LLM flow now uses your own OpenAI API key (any ChatGPT model supported); the bundled remote key and obfuscation step were removed. ## [1.3.0] - 2025-11-21 - You can now switch between two categorization modes: More Refined and More Consistent. Choose depending on your folder and use case. - Added optional Whitelists - limit the number and names of categories when needed. - Added sorting by file names, categories, subcategories in the Categorization Review dialog. - You can now add a custom Local LLM in the Select LLM dialog. - Multilingual categorization: the file categorization labels can now be assigned in Dutch, French, German, Italian, Polish, Portuguese, Spanish, and Turkish. - New interface languages: Dutch, German, Italian, Polish, Portugese, Spanish, and Turkish. ## [1.1.0] - 2025-11-08 - New feature: Support for Vulkan. This means that many non-Nvidia graphics cards (GPUs) are now supported for compute acceleration during local LLM inference. - New feature: Toggle subcategories in the categorization review dialog. - New feature: Undo the recent file sort (move) action. - Fixes: Bug fixes and stability improvements. - Added a CTest-integrated test suite. Expanded test coverage. - Code optimization refactors. ## [1.0.0] - 2025-10-30 - Migrated the entire desktop UI from GTK/Glade to a native Qt6 interface. - Added selection boxes for files in the categorization review dialog. - Added internatioinalization framework and the French translation for the user interface. - Added refreshed menu icons, mnemonic behaviour, and persistent File Explorer settings. - Simplified cross-platform builds (Linux/macOS) around Qt6; retired the MSYS2/GTK toolchain. - Optimized and cleaned up the code. Fixed error-prone areas. - Modernized the build pipeline. Introduced CMake for compilation on Windows. ## [0.9.7] - 2025-10-19 - Added paths to files in LLM requests for more context. - Added taxonomy for more consistent assignment of categories across categorizations. (Narrowing down the number of categories and subcategories). - Improved the readability of the categorization progress dialog box. - Improved the stability of CUDA detection and interaction. - Added more logging coverage throughout the code base. ## [0.9.3] - 2025-09-22 - Added compatibility with CUDA 13. ## [0.9.2] - 2025-08-06 - Bug fixes. - Increased code coverage with logging. ## [0.9.1] - 2025-08-01 - Bug fixes. - Minor improvements for stability. - Removed the deprecated GPU backend from the runtime build. ## [0.9.0] - 2025-07-18 - Local LLM support with `llama.cpp`. - LLM selection and download dialog. - Improved `Makefile` for a more hassle-free build and installation. - Minor bug fixes and improvements. ================================================ FILE: LICENSE ================================================ GNU AFFERO GENERAL PUBLIC LICENSE Version 3, 19 November 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU Affero General Public License is a free, copyleft license for software and other kinds of works, specifically designed to ensure cooperation with the community in the case of network server software. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, our General Public Licenses are intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. Developers that use our General Public Licenses protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License which gives you legal permission to copy, distribute and/or modify the software. A secondary benefit of defending all users' freedom is that improvements made in alternate versions of the program, if they receive widespread use, become available for other developers to incorporate. Many developers of free software are heartened and encouraged by the resulting cooperation. However, in the case of software used on network servers, this result may fail to come about. The GNU General Public License permits making a modified version and letting the public access it on a server without ever releasing its source code to the public. The GNU Affero General Public License is designed specifically to ensure that, in such cases, the modified source code becomes available to the community. It requires the operator of a network server to provide the source code of the modified version running there to the users of that server. Therefore, public use of a modified version, on a publicly accessible server, gives the public access to the source code of the modified version. An older license, called the Affero General Public License and published by Affero, was designed to accomplish similar goals. This is a different license, not a version of the Affero GPL, but Affero has released a new version of the Affero GPL which permits relicensing under this license. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU Affero General Public License. "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. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have 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 receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Remote Network Interaction; Use with the GNU General Public License. Notwithstanding any other provision of this License, if you modify the Program, your modified version must prominently offer all users interacting with it remotely through a computer network (if your version supports such interaction) an opportunity to receive the Corresponding Source of your version by providing access to the Corresponding Source from a network server at no charge, through some standard or customary means of facilitating copying of software. This Corresponding Source shall include the Corresponding Source for any work covered by version 3 of the GNU General Public License that is incorporated pursuant to the following paragraph. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the work with which it is combined will remain governed by version 3 of the GNU General Public License. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU Affero General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU Affero General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU Affero General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU Affero General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If your software can interact with users remotely through a computer network, you should also make sure that it provides a way for users to get its source. For example, if your program is a web application, its interface could display a "Source" link that leads users to an archive of the code. There are many ways you could offer source, and different solutions will be better for different programs; see section 13 for the specific requirements. You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU AGPL, see . ================================================ FILE: README.md ================================================ # AI File Sorter [![Code Version](https://img.shields.io/badge/Code-1.7.3-blue)](#) [![Release Version](https://img.shields.io/github/v/release/hyperfield/ai-file-sorter?label=Release)](#) ![filesorter.app Downloads](https://filesorter.app/download-stats/badge.svg) [![SourceForge Downloads](https://img.shields.io/sourceforge/dt/ai-file-sorter.svg?label=SourceForge%20downloads)](https://sourceforge.net/projects/ai-file-sorter/files/latest/download) [![Codacy Badge](https://app.codacy.com/project/badge/Grade/2c646c836a9844be964fbf681649c3cd)](https://app.codacy.com/gh/hyperfield/ai-file-sorter/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade) [![Donate](https://img.shields.io/badge/Support%20AI%20File%20Sorter-orange)](https://filesorter.app/donate/)

AI File Sorter logo

Vulkan CUDA Apple Metal Windows macOS Linux

AI File Sorter is a cross-platform desktop application that uses AI to organize files and suggest cleaner, more consistent names for images, documents, and supported audio/video files. It is designed to reduce clutter, improve consistency, and make files easier to find later, whether for review, archiving, or long-term storage.

AI File Sorter before and after organization example

The app can analyze picture files locally and suggest meaningful, human-readable names. For example, a generic file like IMG_2048.jpg can be renamed to something descriptive such as clouds_over_lake.jpg. It can also analyze supported document files and propose clearer names based on their text content. AI File Sorter can also clean up messy audio and video filenames by using the metadata already stored inside supported media files. If tags such as year, artist, album, or title are available, the app can turn them into a clear suggestion like `2024_artist_album_title.mp3`, which you can review, edit, or ignore before any change is applied. AI File Sorter helps tidy up cluttered folders such as Downloads, external drives, or NAS storage by automatically grouping files based on their names, extensions, folder context, and learned organization patterns. Instead of relying on fixed rules, the app gradually builds an internal understanding of how your files are typically organized and named. This allows it to make more consistent categorization and naming suggestions over time, while still letting you review and adjust everything before anything is applied. Categories (and optional subcategories) are suggested for each file, and for supported file types, rename suggestions are provided as well. Once you confirm, the required folders are created automatically and files are sorted accordingly. Privacy-first by design: AI File Sorter can run entirely on your device, using local AI models such as Llama 3B (Q4) and Mistral 7B. No files, filenames, images, or metadata are uploaded anywhere, and no telemetry is sent. An internet connection is only needed if you explicitly choose to enable a remote model. --- #### How It Works 1. Point the app at a folder or drive 2. Files (and image content, when applicable) are analyzed using the selected local or remote model 3. Category and rename suggestions are generated 4. You review and adjust if needed - done --- [![Download ai-file-sorter](https://a.fsdn.com/con/app/sf-download-button)](https://sourceforge.net/projects/ai-file-sorter/files/latest/download) [![Get it from Microsoft](https://get.microsoft.com/images/en-us%20dark.svg)](https://apps.microsoft.com/detail/9npk4dzd6r6s) ![AI File Sorter Screenshot](images/screenshots/ai-file-sorter-win.gif) ![AI File Sorter Screenshot](images/screenshots/main_windows_macos.png) ![AI File Sorter Screenshot](images/screenshots/sort-confirm-moved-win.png) --- - [AI File Sorter](#ai-file-sorter) - [Changelog](#changelog) - [Features](#features) - [Categorization](#categorization) - [Categorization modes](#categorization-modes) - [Category whitelists](#category-whitelists) - [Image analysis (Visual LLM)](#image-analysis-visual-llm) - [Required visual LLM files](#required-visual-llm-files) - [Main window options](#main-window-options) - [Document analysis (Text LLM)](#document-analysis-text-llm) - [Supported document formats](#supported-document-formats) - [Main window options (documents)](#main-window-options-documents) - [Audio/video metadata filename suggestions](#audiovideo-metadata-filename-suggestions) - [Supported audio/video formats](#supported-audiovideo-formats) - [System compatibility check](#system-compatibility-check) - [Requirements](#requirements) - [Installation](#installation) - [Linux](#linux) - [macOS](#macos) - [Windows](#windows) - [Categorization cache database](#categorization-cache-database) - [Uninstallation](#uninstallation) - [Using your OpenAI API key](#using-your-openai-api-key) - [Using your Gemini API key](#using-your-gemini-api-key) - [Testing](#testing) - [Diagnostics](#diagnostics) - [How to Use](#how-to-use) - [Sorting a Remote Directory (e.g., NAS)](#sorting-a-remote-directory-eg-nas) - [Contributing](#contributing) - [Credits](#credits) - [License](#license) - [Donation](#donation) --- ## Changelog ## [1.7.3] - 2026-03-22 - Non-English categorization is now more reliable: files are categorized canonically in English first, then translated into the selected category language. This change is due to LLM language limitations. - App updates now support separate update streams for Windows, macOS, and Linux, while still accepting the legacy single-stream manifest format for newer clients. - Windows feeds can now provide a direct installer URL plus SHA-256 checksum so the app can download the installer, show download progress, verify its integrity, and launch it after confirmation. - The UI translation system was migrated fully to Qt `.ts` / `.qm` catalogs. - Local categorization with local LLMs is now more robust. - Cached category labels are sanitized more aggressively to avoid malformed UTF-8 data breaking later categorization or display. - Misc improvements. - Misc bug fixes. See [CHANGELOG.md](CHANGELOG.md) for the full history. --- ## Features - **AI-Powered Categorization**: Classify files intelligently using either a **local LLM** (Llama, Mistral) or a remote model (ChatGPT with your own OpenAI API key, or Gemini with your own Gemini API key). - **Offline-Friendly**: Use a local LLM to categorize files entirely - no internet or API key required. - **Robust categorization**: Taxonomy and heuristics help keep labels more consistent across runs. - **Customizable sorting rules**: Automatically assign categories and subcategories for granular organization. - **Two categorization modes**: Pick **More Refined** for detailed labels or **More Consistent** to bias toward uniform categories within a folder. - **Category whitelists**: Define named whitelists of allowed categories/subcategories, manage them under **Settings → Manage category whitelists…**, and toggle/select them in the main window when you want to constrain model output for a session. - **Multilingual categorization**: Have the LLM assign categories in Dutch, French, German, Italian, Polish, Portuguese, Spanish, or Turkish (model dependent). - **Custom local LLMs**: Register your own local GGUF models directly from the **Select LLM** dialog. - **Image content analysis (Visual LLM)**: Analyze supported picture files with LLaVA to produce descriptions and optional filename suggestions (rename-only mode supported). - **Image date-to-category suffix (optional)**: Append image creation date metadata to image category names when available. - **Document content analysis (Text LLM)**: Analyze supported document files to summarize content and suggest filenames; uses the same selected LLM (local or remote). - **Audio/video metadata filename suggestions**: Turn embedded media tags into clean, library-style filenames for supported audio and video files, with full review before anything is renamed. - **Sortable review**: Sort the Categorization Review table by file name, category, or subcategory to triage faster. - **Qt6 Interface**: Lightweight and responsive UI with refreshed menus and icons. - **Interface languages**: English, Dutch, French, German, Italian, Korean, Spanish, and Turkish. - **Cross-Platform Compatibility**: Works on Windows, macOS, and Linux. - **Local Database Caching**: Speeds up repeated categorization and minimizes remote LLM usage costs. - **Sorting Preview**: See how files will be organized before confirming changes. - **Dry run** / preview-only mode to inspect planned moves without touching files. - **Persistent Undo** ("Undo last run") even after closing the sort dialog. - **Bring your own key**: Paste your OpenAI or Gemini API key once; it's stored locally and reused for remote runs. - **Update Notifications**: Get notified about updates - with optional or required update flows. --- ## Categorization ### Categorization modes - **More refined**: The flexible, detail-oriented mode. Consistency hints are disabled so the model can pick the most specific category/subcategory it deems appropriate, which is useful for long-tail or mixed folders. - **More consistent**: The uniform mode. The model receives consistency hints from prior assignments in the current session so files with similar names/extensions trend toward the same categories. This is helpful when you want strict uniformity across a batch. - Switch between the two via the **Categorization type** radio buttons on the main window; your choice is saved for the next run. ### Category whitelists - Enable **Use a whitelist** to inject the selected whitelist into the LLM prompt; disable it to let the model choose freely. - Manage lists (add, edit, remove) under **Settings → Manage category whitelists…**. A default list is auto-created only when no lists exist, and multiple named lists can be kept for different projects. - Keep each whitelist to roughly **15–20 categories/subcategories** to avoid overlong prompts on smaller local models. Use several narrower lists instead of a single very long one. - Whitelists apply in either categorization mode; pair them with **More consistent** when you want the strongest adherence to a constrained vocabulary. --- ## Image analysis (Visual LLM) Image analysis uses a local LLaVA-based visual LLM to describe image contents and (optionally) suggest a better filename. This runs locally and does not require an API key. ### Required visual LLM files The **Select LLM** dialog now includes an "Image analysis models (LLaVA)" section with two downloads: - **LLaVA text model (GGUF)**: The main language model that produces the description and the filename suggestion. - **LLaVA mmproj (vision encoder projection, GGUF)**: The adapter that maps vision embeddings into the LLM token space so the model can accept images. Both files are required. If either one is missing, image analysis is disabled and the app will prompt to open the **Select LLM** dialog to download them. The download URLs can be overridden with `LLAVA_MODEL_URL` and `LLAVA_MMPROJ_URL` (see [Environment variables](#environment-variables)). ### Main window options Image analysis adds six related checkboxes to the main window: - **Analyze picture files by content (can be slow)**: Runs the visual LLM on supported picture files and reports progress in the analysis dialog. - **Process picture files only (ignore any other files)**: Restricts the run to supported picture files and disables the categorization controls while active. - **Add image creation date (if available) to category name**: Appends `YYYY-MM-DD` from image metadata to the category label when available. Disabled when rename-only is enabled. - **Add photo date and place to filename (if available)**: Adds metadata-based date/place prefixes to suggested image filenames when available. - **Offer to rename picture files**: Shows a **Suggested filename** column in the Review dialog with the visual LLM proposal. You can edit it before confirming. - **Do not categorize picture files (only rename)**: Skips text categorization for images and keeps them in place while applying (optional) renames. The separate top-level checkbox **Add audio/video metadata to file name (if available)** controls metadata-based rename suggestions for supported audio/video files. See [Audio/video metadata filename suggestions](#audiovideo-metadata-filename-suggestions). --- ## Document analysis (Text LLM) Document analysis uses the same selected LLM (local or remote) to extract text from supported document files, summarize content, and optionally suggest a better filename. No extra model downloads are required. ### Supported document formats - Plain text: `.txt`, `.md`, `.rtf`, `.csv`, `.tsv`, `.json`, `.xml`, `.yml`/`.yaml`, `.ini`/`.cfg`/`.conf`, `.log`, `.html`/`.htm`, `.tex`, `.rst` - PDF: `.pdf` (embedded PDFium by default; CLI fallback via `pdftotext` is available only if you explicitly configure `-DAI_FILE_SORTER_REQUIRE_EMBEDDED_PDF_BACKEND=OFF`) - Office/OpenOffice: `.docx`, `.xlsx`, `.pptx`, `.odt`, `.ods`, `.odp` (embedded libzip+pugixml in bundled builds; CLI fallback uses `unzip` if you build without vendored libs) - Legacy binary formats like `.doc`, `.xls`, `.ppt` are not currently supported. Source builds: embedded extractors are used by default. If the vendored PDFium artifacts are missing for your target platform, CMake now fails loudly instead of silently disabling PDF content extraction. You can opt back into the old CLI fallback with `-DAI_FILE_SORTER_REQUIRE_EMBEDDED_PDF_BACKEND=OFF`. ### Main window options (documents) - **Analyze document files by content**: Extracts document text and feeds it into the LLM for summary + rename suggestion. - **Process document files only (ignore any other files)**: Restricts the run to supported document files and disables the categorization controls while active. - **Offer to rename document files**: Shows a **Suggested filename** column in the Review dialog with the LLM proposal. You can edit it before confirming. - **Do not categorize document files (only rename)**: Skips text categorization for documents and keeps them in place while applying (optional) renames. - **Add document creation date (if available) to category name**: Appends `YYYY-MM` from metadata when available. Disabled when rename-only is enabled. --- ## Audio/video metadata filename suggestions Let AI File Sorter turn embedded media tags into clean, consistent filenames for your music and video library. When enabled, the app reads supported metadata fields and builds a polished suggested name in the format `year_artist_album_title.ext`. As with all rename suggestions, nothing is changed until you review and confirm it. ### Supported audio/video formats - Audio extensions: `.aac`, `.aif`, `.aiff`, `.alac`, `.ape`, `.flac`, `.m4a`, `.mp3`, `.ogg`, `.oga`, `.opus`, `.wav`, `.wma` - Video extensions: `.3gp`, `.avi`, `.flv`, `.m4v`, `.mkv`, `.mov`, `.mp4`, `.mpeg`, `.mpg`, `.mts`, `.m2ts`, `.ts`, `.webm`, `.wmv` - Built-in tag readers currently cover MP3 (`ID3v1`/`ID3v2`), FLAC (Vorbis comments), OGG/OGA/Opus (Vorbis comments), and MP4-family containers such as `.m4a`, `.mp4`, `.m4v`, `.mov`, and `.3gp` (MP4/MOV metadata atoms). - When compiled with package-managed `MediaInfoLib`, the same rename flow can also use metadata exposed by MediaInfo for additional supported containers when available. --- ## System compatibility check The **System compatibility check** runs a quick benchmark that estimates how well your system can handle: - **Categorization** with the selected local LLMs - **Document analysis** by content - **Image analysis** (visual LLM) You can launch it from the menu (**File → System compatibility check…**). It only runs if at least one local or visual LLM is downloaded, and it won’t auto-rerun if it's already been run. What it does: - Detects available CPU threads and GPU backends (e.g., Vulkan/CUDA) - Times a small categorization and document-analysis workload per default model - Times a single image-analysis pass if visual LLM files are present - Reports speed tiers (optimal / acceptable / a bit long) and suggests a recommended local LLM Tip: quit CPU/GPU‑intensive apps before running the check for more accurate results. --- ## Requirements - **Operating System**: Linux, macOS, or Windows. Linux/macOS source builds use the Makefile flow below; Windows source builds use the native Qt/MSVC + CMake flow in the Windows section. - **Compiler**: A C++20-capable compiler (`g++` or `clang++` on Linux/macOS, MSVC 2022 on Windows). - **Qt 6**: Core, Gui, Widgets modules and the Qt resource compiler (`qt6-base-dev` / `qt6-tools` on Linux, `brew install qt` on macOS, or a Qt 6 MSVC kit / `qtbase` via vcpkg on Windows). - **Libraries**: `curl`, `sqlite3`, `fmt`, `spdlog`, `libmediainfo` (required for full source builds), and the prebuilt `llama` libraries shipped under `app/lib/precompiled` on Linux/Windows or `app/lib/precompiled-*` for macOS variant builds. On Windows, these non-Qt libraries are supplied through the `app/vcpkg.json` manifest. - **MediaInfo policy**: MediaInfo must be installed through a package manager (`apt`/`dnf`/`pacman`/`brew`/`vcpkg`). The build rejects vendored MediaInfo submodules and checked-in binaries. - **Document analysis libraries** (vendored): PDFium, libzip, and pugixml. PDFium is required by default so packaged/source builds keep PDF extraction embedded on Windows, macOS, and Linux; set `-DAI_FILE_SORTER_REQUIRE_EMBEDDED_PDF_BACKEND=OFF` only if you intentionally want the `pdftotext` fallback. - **Optional GPU backends**: A Vulkan 1.2+ runtime (preferred) or CUDA 12.x for NVIDIA cards. `StartAiFileSorter.exe`/`run_aifilesorter.sh` auto-detect the best available backend and fall back to CPU/OpenBLAS automatically, so CUDA is never required to run the app. - **Git** (optional): For cloning this repository. Archives can also be downloaded. - **OpenAI or Gemini API key** (optional): Required only when using the remote ChatGPT or Gemini workflow. --- ## Installation File categorization with local LLMs is completely free of charge. If you prefer to use a remote workflow (ChatGPT or Gemini) you will need your own API key with a small balance or within the free tier (see [Using your OpenAI API key](#using-your-openai-api-key) or [Using your Gemini API key](#using-your-gemini-api-key)). ### Linux #### Prebuilt Debian/Ubuntu package 1. **Install runtime prerequisites** (Qt6, networking, database, math libraries): - Ubuntu 24.04 / Debian 12: ```bash sudo apt update && sudo apt install -y \ libqt6widgets6 libcurl4 libjsoncpp25 libfmt9 libopenblas0-pthread \ libvulkan1 mesa-vulkan-drivers patchelf ``` - Debian 13 (trixie): ```bash sudo apt update && sudo apt install -y \ libqt6widgets6 libcurl4t64 libjsoncpp26 libfmt10 libopenblas0-pthread \ libvulkan1 mesa-vulkan-drivers patchelf ``` If you build the Vulkan backend from source, install `glslc` (Debian/Ubuntu package: `glslc`; on some distros: `shaderc` or `shaderc-tools`). On Debian 13, use `libjsoncpp26`, `libfmt10`, and `libcurl4t64` (APT may auto-select `libcurl4t64` if `libcurl4` is not available). Ensure that the Qt platform plugins are installed (on Ubuntu 22.04 this is provided by `qt6-wayland`). GPU acceleration additionally requires either a working Vulkan 1.2+ stack (Mesa, AMD/Intel/NVIDIA drivers) or, for NVIDIA users, the matching CUDA runtime (`nvidia-cuda-toolkit` or vendor packages). The launcher automatically prefers Vulkan when both are present and falls back to CPU if neither is available. 2. **Install the package** ```bash sudo apt install ./aifilesorter_*.deb ``` Using `apt install` (rather than `dpkg -i`) ensures any missing dependencies listed above are installed automatically. #### Build from source 1. **Install dependencies** - Debian / Ubuntu: ```bash sudo apt update && sudo apt install -y \ build-essential cmake git qt6-base-dev qt6-base-dev-tools qt6-l10n-tools qt6-tools-dev-tools \ libcurl4-openssl-dev libjsoncpp-dev libsqlite3-dev libssl-dev libfmt-dev libspdlog-dev libmediainfo-dev \ zlib1g-dev ``` - Fedora / RHEL: ```bash export PATH="/usr/lib64/qt6/libexec:$PATH" sudo dnf install -y gcc-c++ cmake git qt6-qtbase-devel qt6-qttools-devel \ libcurl-devel jsoncpp-devel sqlite-devel openssl-devel fmt-devel spdlog-devel mediainfo-devel ``` - Arch / Manjaro: ```bash sudo pacman -S --needed base-devel git cmake qt6-base qt6-tools curl jsoncpp sqlite openssl fmt spdlog mediainfo ``` Optional GPU acceleration also requires either the distro Vulkan 1.2+ driver/runtime (Mesa, AMD, Intel, NVIDIA) or CUDA packages for NVIDIA cards. Install whichever stack you plan to use; the app will fall back to CPU automatically if none are detected. MediaInfo is enforced as package-managed only; vendored `MediaInfoLib` folders or repo-local binaries are rejected by the build. 2. **Clone the repository** ```bash git clone https://github.com/hyperfield/ai-file-sorter.git cd ai-file-sorter git submodule update --init --recursive ``` > **Submodule tip:** If you previously downloaded `llama.cpp` or Catch2 manually, remove or rename `app/include/external/llama.cpp` and `external/Catch2` before running the `git submodule` command. Git needs those directories to be empty so it can populate them with the tracked submodules. 3. **Build vendored libzip** (generates `zipconf.h` and `libzip.a`) ```bash cmake -S external/libzip -B external/libzip/build \ -DBUILD_SHARED_LIBS=OFF \ -DBUILD_DOC=OFF \ -DENABLE_BZIP2=OFF \ -DENABLE_LZMA=OFF \ -DENABLE_ZSTD=OFF \ -DENABLE_OPENSSL=OFF \ -DENABLE_GNUTLS=OFF \ -DENABLE_MBEDTLS=OFF \ -DENABLE_COMMONCRYPTO=OFF \ -DENABLE_WINDOWS_CRYPTO=OFF cmake --build external/libzip/build ``` On Ubuntu/Debian you will also need the Zlib development headers (`zlib1g-dev`) or the libzip configure step will fail. If you prefer system headers instead, install `libzip-dev` and ensure `zipconf.h` is on your include path. 4. **Build the llama runtime variants** (run once per backend you plan to ship/test) ```bash # CPU / OpenBLAS ./app/scripts/build_llama_linux.sh cuda=off vulkan=off # CUDA (optional; requires NVIDIA driver + CUDA toolkit) ./app/scripts/build_llama_linux.sh cuda=on vulkan=off # Vulkan (optional; requires a working Vulkan 1.2+ stack and glslc, e.g. mesa-vulkan-drivers + vulkan-tools + glslc) ./app/scripts/build_llama_linux.sh cuda=off vulkan=on ``` Each invocation stages the corresponding `llama`/`ggml` libraries under `app/lib/precompiled/` and the runtime DLL/SO copies under `app/lib/ggml/w`. The script refuses to enable CUDA and Vulkan simultaneously, so run it separately for each backend. Shipping both directories lets the launcher pick Vulkan when available, then CUDA, and otherwise stay on CPU—no CUDA-only dependency remains. 5. **Compile the application** ```bash cd app make -j4 ``` The binary is produced at `app/bin/aifilesorter`. The Makefile requires `pkg-config` + package-managed `libmediainfo`; it intentionally rejects vendored MediaInfo copies. 6. **Install system-wide (optional)** ```bash sudo make install ``` 7. **Build a Debian package (optional)** ```bash ./app/scripts/package_deb.sh ``` The packaging script always bundles the CPU runtime and auto-includes any staged GPU variants already present under `app/lib/precompiled` (for example `vulkan` after `./app/scripts/build_llama_linux.sh cuda=off vulkan=on`). Use `./app/scripts/package_deb.sh --cpu-only` for a smaller CPU-only package, or `--include-vulkan` / `--include-cuda` if you want the script to fail when a specific staged variant is missing. ### macOS 1. **Install Xcode command-line tools** (`xcode-select --install`). 2. **Install Homebrew** (if required). 3. **Install dependencies** ```bash brew install qt curl jsoncpp sqlite openssl fmt spdlog mediainfo cmake git pkgconfig libffi ``` Add Qt to your environment if it is not already present: ```bash export PATH="$(brew --prefix)/opt/qt/bin:$PATH" export PKG_CONFIG_PATH="$(brew --prefix)/lib/pkgconfig:$(brew --prefix)/share/pkgconfig:$PKG_CONFIG_PATH" ``` 4. **Clone the repository and submodules** (same commands as Linux). > The macOS build pins `MACOSX_DEPLOYMENT_TARGET=11.0` so the Mach-O `LC_BUILD_VERSION` covers Apple Silicon and newer releases (including Sequoia). Raise or lower it (e.g., `export MACOSX_DEPLOYMENT_TARGET=15.0`) if you need a different floor. 5. **Build vendored libzip** (generates `zipconf.h` and `libzip.a`) ```bash cmake -S external/libzip -B external/libzip/build \ -DBUILD_SHARED_LIBS=OFF \ -DBUILD_DOC=OFF \ -DENABLE_BZIP2=OFF \ -DENABLE_LZMA=OFF \ -DENABLE_ZSTD=OFF \ -DENABLE_OPENSSL=OFF \ -DENABLE_GNUTLS=OFF \ -DENABLE_MBEDTLS=OFF \ -DENABLE_COMMONCRYPTO=OFF \ -DENABLE_WINDOWS_CRYPTO=OFF cmake --build external/libzip/build ``` 6. **Build the llama runtime (Metal-enabled on Apple Silicon)** ```bash ./app/scripts/build_llama_macos.sh ``` The macOS app and `.app` bundles use the runtime staged under `app/lib/precompiled*`; they do not need Homebrew `ggml` or `llama.cpp` libraries. If you have older `ggml` / `llama.cpp` copies installed in generic library locations, prefer unlinking or removing them instead of relying on them implicitly. 7. **Compile the application** ```bash cd app make -j8 # use -jN to control parallelism sudo make install # optional ``` The default build places the binary at `app/bin/aifilesorter`. **Variant targets:** ```bash make -j8 MACOS_LLAMA_M1 # outputs app/bin/m1/aifilesorter make -j8 MACOS_LLAMA_M2 # outputs app/bin/m2/aifilesorter make -j8 MACOS_LLAMA_INTEL # outputs app/bin/intel/aifilesorter ``` These targets rebuild the llama.cpp runtime before compiling the app. When cross-compiling Intel on Apple Silicon, use x86_64 Homebrew (under `/usr/local`) or set `BREW_PREFIX=/usr/local` so Qt/pkg-config resolve correctly. `sudo make install` places the macOS runtime libraries under `/usr/local/lib/aifilesorter` to avoid collisions with unrelated system or Homebrew ggml libraries. Each variant uses distinct build directories to avoid cross-arch collisions: - llama.cpp libs: `app/lib/precompiled-m1`, `app/lib/precompiled-m2`, `app/lib/precompiled-intel` - object files: `app/obj/arm64` or `app/obj/x86_64` ### Windows Build now targets native MSVC + Qt6 without MSYS2. Two options are supported; the vcpkg route is simplest. Option A - CMake + vcpkg (recommended) 1. Install prerequisites: - Visual Studio 2022 with Desktop C++ workload - CMake 3.21+ (Visual Studio ships a recent version) - vcpkg: (clone and bootstrap) - package-managed `libmediainfo` via vcpkg manifest (no vendored MediaInfo submodule/binaries) - **MSYS2 MinGW64 + OpenBLAS**: install MSYS2 from , open an *MSYS2 MINGW64* shell, and run `pacman -S --needed mingw-w64-x86_64-openblas`. The `build_llama_windows.ps1` script uses this OpenBLAS copy for CPU-only builds (the vcpkg variant is not suitable), defaulting to `C:\msys64\mingw64` unless you pass `openblasroot=` or set `OPENBLAS_ROOT`. 2. Clone repo and submodules: ```powershell git clone https://github.com/hyperfield/ai-file-sorter.git cd ai-file-sorter git submodule update --init --recursive ``` 3. **Build vendored libzip** (generates `zipconf.h` and `libzip.lib`) Run from the same x64 Native Tools / VS Developer PowerShell you will use to build the app: ```powershell cmake -S external\libzip -B external\libzip\build -A x64 ` -DBUILD_SHARED_LIBS=OFF ` -DBUILD_DOC=OFF ` -DENABLE_BZIP2=OFF ` -DENABLE_LZMA=OFF ` -DENABLE_ZSTD=OFF ` -DENABLE_OPENSSL=OFF ` -DENABLE_GNUTLS=OFF ` -DENABLE_MBEDTLS=OFF ` -DENABLE_COMMONCRYPTO=OFF ` -DENABLE_WINDOWS_CRYPTO=OFF cmake --build external\libzip\build --config Release ``` 4. Determine your vcpkg root. It is the folder that contains `vcpkg.exe` (for example `C:\dev\vcpkg`). - If `vcpkg` is on your `PATH`, run this command to print the location: ```powershell Split-Path -Parent (Get-Command vcpkg).Source ``` - Otherwise use the directory where you cloned vcpkg. MediaInfo note: you do **not** manually add `MediaInfoLib` include/lib paths on Windows. The project already declares `libmediainfo` in `app/vcpkg.json`, and `app\build_windows.ps1` configures CMake with the vcpkg toolchain + manifest so `find_package(MediaInfoLib ...)` resolves it automatically. If you want to preinstall or verify it explicitly, run `vcpkg install libmediainfo:x64-windows`. 5. Build the bundled `llama.cpp` runtime variants (run from the same **x64 Native Tools** / **VS 2022 Developer PowerShell** shell). Invoke the script once per backend you need. Make sure the MSYS2 OpenBLAS install from step 1 is present before running the CPU-only variant (or pass `openblasroot=` explicitly): ```powershell # CPU / OpenBLAS only app\scripts\build_llama_windows.ps1 cuda=off vulkan=off vcpkgroot=C:\dev\vcpkg # CUDA (requires matching NVIDIA toolkit/driver) app\scripts\build_llama_windows.ps1 cuda=on vulkan=off vcpkgroot=C:\dev\vcpkg # Vulkan (requires LunarG Vulkan SDK or vendor Vulkan 1.2+ runtime) app\scripts\build_llama_windows.ps1 cuda=off vulkan=on vcpkgroot=C:\dev\vcpkg ``` Each run emits the appropriate `llama.dll` / `ggml*.dll` pair under `app\lib\precompiled\` and copies the runtime DLLs into `app\lib\ggml\w`. For Vulkan builds, install the latest LunarG Vulkan SDK (or the vendor's runtime), ensure `vulkaninfo` succeeds in the same shell, and then run the script. Supplying both Vulkan and (optionally) CUDA artifacts lets `StartAiFileSorter.exe` detect the best backend at launch—Vulkan is preferred, CUDA is used when Vulkan is missing, and CPU remains the fallback, so CUDA is not required. 6. Build the Qt6 application using the helper script (still in the VS shell). The helper stages runtime DLLs via `windeployqt`, shares one dependency install tree across variants, and by default produces three Windows builds in one run: ```powershell # One-time per shell if script execution is blocked: Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass app\build_windows.ps1 -Configuration Release -VcpkgRoot C:\dev\vcpkg ``` - Replace `C:\dev\vcpkg` with the path where you cloned vcpkg; it must contain `scripts\buildsystems\vcpkg.cmake`. - The helper produces these output directories by default: - Standard installer build with Windows auto-update enabled: `app\build-windows\Release` - Microsoft Store build with update checks disabled: `app\build-windows-store\Release` - Standalone Windows build with notification-only/manual updates: `app\build-windows-standalone\Release` - Use `-Variants Standard`, `-Variants MsStore`, or `-Variants Standalone` to build only a subset. - `aifilesorter.exe` is the primary Windows GUI entry point. `StartAiFileSorter.exe` is still built beside it as the legacy bootstrapper and carries the same updater mode. - `-VcpkgRoot` is optional if `VCPKG_ROOT`/`VPKG_ROOT` is set or `vcpkg`/`vpkg` is on `PATH`. - Each variant directory receives its own executable and staged Qt/third-party DLLs. Pass `-SkipDeploy` if you only want the binaries without bundling runtime DLLs. - Pass `-Parallel ` to override the default “all cores” parallel build behaviour (for example, `-Parallel 8`). By default the script invokes `cmake --build ... --parallel ` and `ctest -j ` to keep both MSBuild and Ninja fully utilized. Option B - CMake + Qt online installer 1. Install prerequisites: - Visual Studio 2022 with Desktop C++ workload - Qt 6.x MSVC kit via Qt Online Installer (e.g., Qt 6.6+ with MSVC 2019/2022) - CMake 3.21+ - vcpkg (for non-Qt libs): curl, jsoncpp, sqlite3, openssl, fmt, spdlog, gettext, libmediainfo 2. **Build vendored libzip** (generates `zipconf.h` and `libzip.lib`) Run from the same x64 Native Tools / VS Developer PowerShell you will use to build the app: ```powershell cmake -S external\libzip -B external\libzip\build -A x64 ` -DBUILD_SHARED_LIBS=OFF ` -DBUILD_DOC=OFF ` -DENABLE_BZIP2=OFF ` -DENABLE_LZMA=OFF ` -DENABLE_ZSTD=OFF ` -DENABLE_OPENSSL=OFF ` -DENABLE_GNUTLS=OFF ` -DENABLE_MBEDTLS=OFF ` -DENABLE_COMMONCRYPTO=OFF ` -DENABLE_WINDOWS_CRYPTO=OFF cmake --build external\libzip\build --config Release ``` 3. Build the bundled `llama.cpp` runtime (same VS shell). Any missing OpenBLAS/cURL packages are installed automatically via vcpkg: ```powershell pwsh .\app\scripts\build_llama_windows.ps1 [cuda=on|off] [vulkan=on|off] [vcpkgroot=C:\dev\vcpkg] ``` This is required before configuring the GUI because the build links against the produced `llama` static libraries/DLLs. 4. Configure CMake from the repo root so CMake sees both the Qt install and the app's vcpkg manifest (adapt `CMAKE_PREFIX_PATH` to your Qt install): ```powershell $env:VCPKG_ROOT = "C:\path\to\vcpkg" # e.g. C:\dev\vcpkg $qt = "C:\Qt\6.6.3\msvc2019_64" # example cmake -S app -B build -G "Ninja" ` -DCMAKE_PREFIX_PATH=$qt ` -DCMAKE_TOOLCHAIN_FILE=$env:VCPKG_ROOT\scripts\buildsystems\vcpkg.cmake ` -DVCPKG_MANIFEST_DIR=app ` -DAI_FILE_SORTER_REQUIRE_MEDIAINFOLIB=ON ` -DVCPKG_TARGET_TRIPLET=x64-windows cmake --build build --config Release ``` This configure step enables vcpkg manifest mode, so `libmediainfo` is installed/resolved from `app\vcpkg.json` automatically. No manual linker or include-path edits are needed for MediaInfo on Windows. Notes - To rebuild from scratch, run `.\app\build_windows.ps1 -Clean`. The script removes the selected variant build directories and the shared `app\build-windows-vcpkg_installed` dependency tree before configuring. - Runtime DLLs are copied automatically via `windeployqt` after each successful build; skip this step with `-SkipDeploy` if you manage deployment yourself. - If Visual Studio sets `VCPKG_ROOT` to its bundled copy under `Program Files`, clone vcpkg to a writable directory (for example `C:\dev\vcpkg`) and pass `vcpkgroot=` when running `build_llama_windows.ps1`. - If you plan to ship CUDA or Vulkan acceleration, run the `build_llama_*` helper for each backend you intend to include before configuring CMake so the libraries exist. The runtime can carry both and auto-select at launch, so CUDA remains optional. - `-BuildTests` and `-RunTests` currently build and execute tests only in the `Standard` variant, which is the primary Windows development/CI configuration. ### Running tests Catch2-based unit tests are optional. Enable them via CMake: ```bash cmake -S app -B build-tests -DAI_FILE_SORTER_BUILD_TESTS=ON -DAI_FILE_SORTER_REQUIRE_MEDIAINFOLIB=ON cmake --build build-tests --target ai_file_sorter_tests --parallel $(nproc) ctest --test-dir build-tests --output-on-failure -j $(nproc) ``` On macOS, replace `$(nproc)` with `$(sysctl -n hw.ncpu)`. On Windows (PowerShell), use: ```powershell cmake -S app -B build-tests -DAI_FILE_SORTER_BUILD_TESTS=ON -DAI_FILE_SORTER_REQUIRE_MEDIAINFOLIB=ON cmake --build build-tests --target ai_file_sorter_tests --parallel $env:NUMBER_OF_PROCESSORS ctest --test-dir build-tests --output-on-failure -j $env:NUMBER_OF_PROCESSORS ``` Notes - List individual Catch2 cases: `./build-tests/ai_file_sorter_tests --list-tests` - Print each case name (including successes): `./build-tests/ai_file_sorter_tests --verbosity high --success` On Windows you can pass `-BuildTests` (and `-RunTests` to execute `ctest`) to `app\build_windows.ps1`: ```powershell app\build_windows.ps1 -Configuration Release -Variants Standard -BuildTests -RunTests ``` The current suite (under `tests/unit`) focuses on core utilities; expand it as new functionality gains coverage. ### Selecting a backend at runtime Both the Linux launcher (`app/bin/run_aifilesorter.sh` / `aifilesorter-bin`) and the Windows starter accept the following optional flags: - `--cuda={on|off}` – force-enable or disable the CUDA backend. - `--vulkan={on|off}` – force-enable or disable the Vulkan backend. When no flags are provided the app auto-detects available runtimes in priority order (Vulkan → CUDA → CPU). Use the flags to skip a backend (`--cuda=off` forces Vulkan/CPU even if CUDA is installed, `--vulkan=off` tests CUDA explicitly) or to validate a newly installed stack (`--vulkan=on`). Passing `on` to both flags is rejected, and if neither GPU backend is detected the app automatically stays on CPU. #### Vulkan and VRAM notes - Vulkan is preferred when available; CUDA is used only if Vulkan is missing or explicitly requested. - The app auto-estimates `n_gpu_layers` based on available VRAM. Integrated GPUs are capped to 4 GiB for safety, which can limit offloading. - If VRAM is tight, the app may fall back to CPU or reduce offload. As a rule of thumb, 8 GB+ VRAM provides a smoother experience for Vulkan offload and image analysis; 4 GB often results in partial offload or CPU fallback. - Override auto-estimation with `AI_FILE_SORTER_N_GPU_LAYERS` (`-1` auto, `0` force CPU) or `AI_FILE_SORTER_GPU_BACKEND=cpu`. - For image analysis, `AI_FILE_SORTER_VISUAL_USE_GPU=0` forces the visual encoder to run on CPU to avoid VRAM allocation errors. ### Environment variables Runtime and GPU: - `AI_FILE_SORTER_GPU_BACKEND` - select GPU backend: `auto` (default), `vulkan`, `cuda`, or `cpu`. - `AI_FILE_SORTER_N_GPU_LAYERS` - override `n_gpu_layers` for llama.cpp; `-1` = auto, `0` = force CPU. - `AI_FILE_SORTER_CTX_TOKENS` - override local LLM context length (default 2048; clamped 512-8192). - `AI_FILE_SORTER_GGML_DIR` - directory to load ggml backend shared libraries from. On macOS this is only auto-discovered from bundled or sibling app runtime directories; use this variable explicitly if you want a custom ggml runtime. Visual LLM: - `LLAVA_MODEL_URL` - download URL for the visual LLM GGUF model (required to enable image analysis). - `LLAVA_MMPROJ_URL` - download URL for the visual LLM mmproj GGUF file (required to enable image analysis). - `AI_FILE_SORTER_VISUAL_USE_GPU` - force visual encoder GPU usage (`1`) or CPU (`0`). Defaults to auto; Vulkan may fall back to CPU if VRAM is low. Timeouts and logging: - `AI_FILE_SORTER_LOCAL_LLM_TIMEOUT` - seconds to wait for local LLM responses (default 60). - `AI_FILE_SORTER_REMOTE_LLM_TIMEOUT` - seconds to wait for OpenAI/Gemini responses (default 10). - `AI_FILE_SORTER_CUSTOM_LLM_TIMEOUT` - seconds to wait for custom OpenAI-compatible API responses (default 60). - `AI_FILE_SORTER_LLAMA_LOGS` - enable verbose llama.cpp logs (`1`/`true`); also honors `LLAMA_CPP_DEBUG_LOGS`. Storage and updates: - `AI_FILE_SORTER_CONFIG_DIR` - override the base config directory (where `config.ini` lives). - `CATEGORIZATION_CACHE_FILE` - override the SQLite cache filename inside the config dir. - `UPDATE_SPEC_FILE_URL` - override the update feed spec URL (dev/testing). The updater now reads per-platform streams from `update.windows`, `update.macos`, and `update.linux`, with legacy single-stream feeds still accepted. - `AI_FILE_SORTER_UPDATER_TEST_MODE` - enable Windows updater live-test mode (`1`/`true`). When enabled, the app skips the update feed fetch and synthesizes a newer version from the values below. - `AI_FILE_SORTER_UPDATER_TEST_URL` - direct URL for the Windows updater live-test package. This can point to an `.exe`, `.msi`, or a `.zip` containing exactly one `.exe` or `.msi`. - `AI_FILE_SORTER_UPDATER_TEST_SHA256` - SHA-256 checksum for the downloaded live-test package. If the URL points to a ZIP, this checksum must be for the ZIP archive itself. - `AI_FILE_SORTER_UPDATER_TEST_VERSION` - optional synthetic version shown by live-test mode. Defaults to the current app version with an extra trailing segment, for example `1.7.2.1`. - `AI_FILE_SORTER_UPDATER_TEST_MIN_VERSION` - optional synthetic minimum version for live-test mode. Defaults to `0.0.0` so the test behaves like an optional update. Example update feed: ```json { "update": { "current_version": "1.7.1", "min_version": "1.6.0", "download_url": "https://filesorter.app/download", "windows": { "current_version": "1.7.1", "min_version": "1.6.0", "download_url": "https://filesorter.app/download", "installer_url": "https://filesorter.app/downloads/AIFileSorterSetup-1.7.1.exe", "installer_sha256": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" }, "macos": { "current_version": "1.7.1", "min_version": "1.6.0", "download_url": "https://filesorter.app/download" }, "linux": { "current_version": "1.7.1", "min_version": "1.6.0", "download_url": "https://filesorter.app/download" } } } ``` Compatibility note: - Older app versions only read the flat top-level fields under `update`, so keep `current_version`, `min_version`, and `download_url` there as a legacy compatibility stream if you still need to support them. - Newer app versions prefer the platform-specific streams and will use `update.windows`, `update.macos`, or `update.linux` when present. - The legacy compatibility stream can only represent one generic stream, not separate per-platform versions or installers. Windows-only direct installer updates: - `installer_url` - direct URL to the Windows installer package. - `installer_sha256` - SHA-256 checksum used to verify the downloaded installer before launch. - `installer_url` can now also point to a ZIP archive, as long as the archive contains exactly one installer payload (`.exe` or `.msi`). - When both fields are present on Windows, the app can download the installer, verify it, and then prompt: `Quit the app and launch the installer to update`. Windows updater live-test mode: - `aifilesorter.exe` accepts the following flags directly on Windows: `--updater-live-test` `--updater-live-test-url=` `--updater-live-test-sha256=` `--updater-live-test-version=` `--updater-live-test-min-version=` - `StartAiFileSorter.exe` accepts and forwards the same flag family if you still use the bootstrapper path. - Live-test mode is Windows-only and intentionally bypasses the normal update JSON feed. - If the ZIP contains more than one `.exe` or `.msi`, the updater stops instead of guessing which installer to launch. - If `--updater-live-test` is present and the URL / SHA flags are omitted, `aifilesorter.exe` also looks for a `live-test.ini` file next to the executable and fills in the missing values from there. - Command-line flags still win over `live-test.ini`, so you can keep a default file and override just one field when needed. Example `live-test.ini`: ```ini [LiveTest] download_url = https://files.example.com/AIFileSorterSetup-1.7.3.zip sha256 = 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef current_version = 1.7.3 min_version = 0.0.0 ``` Example PowerShell launch: ```powershell .\aifilesorter.exe ` --development ` --updater-live-test ``` --- ## Categorization cache database AI File Sorter stores categorization results in a local SQLite database next to `config.ini` (the base directory can be overridden via `AI_FILE_SORTER_CONFIG_DIR`). This cache allows the app to skip already-processed files and preserve rename suggestions between runs. What is stored: - Directory path, file name, and file type (used as a unique key). - Category/subcategory, taxonomy id, categorization style, and timestamp. - Suggested filename (for picture and document rename suggestions). - Rename-only flag (used when picture/document rename-only modes are enabled). - Rename-applied flag (marks when a rename was executed so it is not offered again). If you rename or move a file from the Review dialog, the cache entry is updated to the new name. Already-renamed picture files are skipped for visual analysis and rename suggestions on later runs. In the Review dialog, those already-renamed rows are hidden when rename-only is enabled, but they stay visible when categorization is enabled so you can still move them into category folders. To reset a folder's cache, accept the recategorization prompt or delete the cache file (or point `CATEGORIZATION_CACHE_FILE` to a new filename). --- ## Uninstallation - **Debian/Ubuntu package installs**: `sudo apt remove aifilesorter` - **Linux source installs**: `cd app && sudo make uninstall` - **macOS source installs**: `cd app && sudo make uninstall` For source installs, `make uninstall` removes the executable and the staged precompiled libraries. You can also delete cached local LLM models in `~/.local/share/aifilesorter/llms` (Linux) or `~/Library/Application Support/aifilesorter/llms` (macOS) if you no longer need them. --- ## Using your OpenAI API key Want to use ChatGPT instead of the bundled local models? Bring your own OpenAI API key: 1. Open **Settings -> Select LLM** in the app. 2. Choose **ChatGPT (OpenAI API key)**, paste your key, and enter the ChatGPT model you want to use (for example `gpt-4o-mini`, `gpt-4.1`, or `o3-mini`). 3. Click **OK**. The key is stored locally in your AI File Sorter config (`config.ini` in the app data folder) and reused for future runs. Clear the field to remove it. 4. An internet connection is only required while this option is selected. > The app no longer embeds a bundled key; you always provide your own OpenAI key. --- ## Using your Gemini API key Prefer Google's models? Use your own Gemini API key: 1. Visit **https://aistudio.google.com** and sign in with your Google account. 2. In the left navigation, open **API keys** (or **Get API key**) and click **Create API key**. Choose *Create API key in new project* (or select an existing project) and copy the generated key. 3. In the app, open **Settings -> Select LLM**, choose **Gemini (Google AI Studio API key)**, paste your key, and enter the Gemini model you want (for example `gemini-2.5-flash-lite`, `gemini-2.5-flash`, or `gemini-2.5-pro`). 4. Click **OK**. The key is stored locally in your AI File Sorter config and reused for future runs. Clear the field to remove it. > AI Studio keys can be used on the free tier until you hit Google’s limits; higher quotas or enterprise use require billing via Google Cloud. > The app calls the Gemini `v1` `generateContent` endpoint; use model IDs from `https://generativelanguage.googleapis.com/v1/models?key=YOUR_KEY`. You can enter them with or without the leading `models/` prefix. --- ## Testing - From the repo root, clean any old cache and run the CTest wrapper: ```bash cd app rm -rf ../build-tests # clear a cache from another checkout ./scripts/rebuild_and_test.sh ``` - The script configures to `../build-tests`, builds, then runs `ctest`. - If you have multiple copies of the repo (e.g., `ai-file-sorter` and `ai-file-sorter-mac-dist`), each needs its own `build-tests` folder; reusing one from a different path will make CMake complain about mismatched source/build directories. --- ## Diagnostics If you need to report a bug or collect troubleshooting data, use the bundled diagnostics scripts: - **macOS:** `./app/scripts/collect_macos_diagnostics.sh` - **Linux:** `./app/scripts/collect_linux_diagnostics.sh` - **Windows (PowerShell):** `.\app\scripts\collect_windows_diagnostics.ps1` Each script collects relevant logs, redacts common sensitive paths, and packages the result into a zip archive for sharing. See [app/scripts/README.md](app/scripts/README.md) for options such as time filtering and opening the output folder automatically. --- ## How to Use 1. Launch the application (see the last step in [Installation](#installation) according your OS). 2. Select a directory to analyze. ### Using dry run and undo - In the results dialog, you can enable **"Dry run (preview only, do not move files)"** to preview planned moves. A preview dialog shows From/To without moving any files. - After a real sort, the app saves a persistent undo plan. You can revert later via **Edit → "Undo last run"** (best-effort; skips conflicts/changes). 3. Tick off the checkboxes on the main window according to your preferences. 4. Click the **"Analyze"** button. The app will scan each file and/or directory based on your selected options. 5. A review dialog will appear. Verify the assigned categories (and subcategories, if enabled in step 3). 6. Click **"Confirm & Sort!"** to move the files, or **"Continue Later"** to postpone. You can always resume where you left off since categorization results are saved. --- ## Sorting a Remote Directory (e.g., NAS) Follow the steps in [How to Use](#how-to-use), but modify **step 2** as follows: - **Windows:** Assign a drive letter (e.g., `Z:` or `X:`) to your network share ([instructions here](https://support.microsoft.com/en-us/windows/map-a-network-drive-in-windows-29ce55d1-34e3-a7e2-4801-131475f9557d)). - **Linux & macOS:** Mount the network share to a local folder using a command like: ```sh sudo mount -t cifs //192.168.1.100/shared_folder /mnt/nas -o username=myuser,password=mypass,uid=$(id -u),gid=$(id -g) ``` (Replace 192.168.1.100/shared_folder with your actual network location path and adjust options as needed.) --- ## Contributing - Fork the repository and submit pull requests. - Report issues or suggest features on the GitHub issue tracker. - Follow the existing code style and documentation format. --- ## Credits - Curl: - Dotenv: - git-scm: - Hugging Face: - JSONCPP: - Llama: - libzip: - Local File Organizer - llama.cpp - MediaInfoLib: - Mistral AI: - OpenAI: - OpenSSL: - PDFium: - Poppler (pdftotext): - pugixml: - Qt: - spdlog: - unzip (Info-ZIP): ## License This project is licensed under the GNU AFFERO GENERAL PUBLIC LICENSE (GNU AGPL). See the [LICENSE](LICENSE) file for details, or https://www.gnu.org/licenses/agpl-3.0.html. --- ## Donation Support the development of **AI File Sorter** and its future features. Every contribution counts! - **[Donate](https://filesorter.app/donate/)** --- ================================================ FILE: TESTS.md ================================================ # Test Suite Guide This document provides a detailed description of every test case in the project. It is organized by test file and mirrors the intent, setup, procedure, and expected outcomes for each case. All unit tests live under `tests/unit`. Some UI-centric tests are compiled only on non-Windows platforms and use the Qt offscreen platform plugin so they can run without a visible display. ## How to run tests - Configure tests (once): `cmake -S app -B build-tests -DAI_FILE_SORTER_BUILD_TESTS=ON -DAI_FILE_SORTER_REQUIRE_MEDIAINFOLIB=ON` - Build and run all tests: `cmake --build build-tests` then `ctest --test-dir build-tests --output-on-failure -j $(nproc)` - Run a single test case by name: `./build-tests/ai_file_sorter_tests ""` - MediaInfo is expected from a package manager (`apt`/`dnf`/`pacman`/`brew`/`vcpkg`); vendored MediaInfo directories/binaries are intentionally rejected by the build. ## Unit test catalog ### `tests/unit/test_local_llm_backend.cpp` (skipped when `GGML_USE_METAL` is defined) #### Test case: detect_preferred_backend reads environment Purpose: Verify that the backend preference resolver honors the explicit environment override. Setup: Set `AI_FILE_SORTER_GPU_BACKEND` to `cuda` via an environment guard. Procedure: Call `detect_preferred_backend()` through the test access layer. Expected outcome: The detected preference is `Cuda`. Run: `./build-tests/ai_file_sorter_tests "detect_preferred_backend reads environment"` #### Test case: CPU backend is honored when forced Purpose: Ensure the GPU layer count is forced to CPU when the backend is set to CPU. Setup: Create a temporary GGUF model file and set `AI_FILE_SORTER_GPU_BACKEND=cpu`. Ensure no CUDA disable flag or layer override is set. Procedure: Call `prepare_model_params_for_testing()` for the temporary model. Expected outcome: `n_gpu_layers` is `0`. Run: `./build-tests/ai_file_sorter_tests "CPU backend is honored when forced"` #### Test case: CUDA backend can be forced off via GGML_DISABLE_CUDA Purpose: Confirm that the global CUDA disable flag overrides a CUDA backend preference. Setup: Set `AI_FILE_SORTER_GPU_BACKEND=cuda` and `GGML_DISABLE_CUDA=1`. Inject a probe that reports CUDA available. Procedure: Call `prepare_model_params_for_testing()`. Expected outcome: `n_gpu_layers` is `0`, indicating CPU fallback. Run: `./build-tests/ai_file_sorter_tests "CUDA backend can be forced off via GGML_DISABLE_CUDA"` #### Test case: CUDA override is applied when backend is available Purpose: Validate that an explicit layer override is used when CUDA is available. Setup: Set `AI_FILE_SORTER_GPU_BACKEND=cuda`, set `AI_FILE_SORTER_N_GPU_LAYERS=7`, and inject a CUDA-available probe. Procedure: Call `prepare_model_params_for_testing()`. Expected outcome: `n_gpu_layers` equals `7`. Run: `./build-tests/ai_file_sorter_tests "CUDA override is applied when backend is available"` #### Test case: CUDA fallback when no GPU is available Purpose: Ensure CUDA preference falls back when no GPU is detected. Setup: Set `AI_FILE_SORTER_GPU_BACKEND=cuda`, leave layer override unset, and inject a CUDA-unavailable probe. Procedure: Call `prepare_model_params_for_testing()`. Expected outcome: `n_gpu_layers` is `0` or `-1` (CPU or auto fallback). Run: `./build-tests/ai_file_sorter_tests "CUDA fallback when no GPU is available"` #### Test case: Vulkan backend honors explicit override Purpose: Check that Vulkan backend respects a specific GPU layer override. Setup: Set `AI_FILE_SORTER_GPU_BACKEND=vulkan`, set `AI_FILE_SORTER_N_GPU_LAYERS=12`, and provide a memory probe that returns no data. Procedure: Call `prepare_model_params_for_testing()`. Expected outcome: `n_gpu_layers` equals `12`. Run: `./build-tests/ai_file_sorter_tests "Vulkan backend honors explicit override"` #### Test case: Vulkan backend derives layer count from memory probe Purpose: Verify that Vulkan backend derives a sensible layer count from reported GPU memory. Setup: Use a model with 48 blocks, set `AI_FILE_SORTER_GPU_BACKEND=vulkan`, and inject a probe reporting a 3 GB discrete GPU. Procedure: Call `prepare_model_params_for_testing()`. Expected outcome: `n_gpu_layers` is greater than `0` and less than or equal to `48`. Run: `./build-tests/ai_file_sorter_tests "Vulkan backend derives layer count from memory probe"` ### `tests/unit/test_main_app_image_options.cpp` (non-Windows only) #### Test case: Image analysis checkboxes enable and enforce rename-only behavior Purpose: Ensure the image analysis options enable correctly and enforce the rename-only rule. Setup: Create dummy LLaVA model files, configure settings with image analysis and rename options off, and construct `MainApp` with offscreen Qt. Procedure: Toggle the "Analyze picture files" checkbox on, then toggle the "Do not categorize picture files" checkbox on and attempt to unset "Offer to rename picture files". Expected outcome: The option group enables when analysis is checked; enabling rename-only forces offer-rename on; disabling offer-rename clears rename-only. Run: `./build-tests/ai_file_sorter_tests "Image analysis checkboxes enable and enforce rename-only behavior"` #### Test case: Image rename-only does not disable categorization unless processing images only Purpose: Confirm that rename-only for images does not disable file categorization by itself. Setup: Initialize settings with image analysis off and build `MainApp` with offscreen Qt. Procedure: Enable image analysis and rename-only, then check whether "Categorize files" remains enabled. Next, enable "Process picture files only". Expected outcome: Categorization remains enabled with rename-only, but becomes disabled when processing images only. Run: `./build-tests/ai_file_sorter_tests "Image rename-only does not disable categorization unless processing images only"` #### Test case: Document rename-only does not disable categorization unless processing documents only Purpose: Mirror the image-only behavior for documents. Setup: Initialize settings with document analysis off and build `MainApp` with offscreen Qt. Procedure: Enable document analysis and rename-only, then check whether "Categorize files" remains enabled. Next, enable "Process document files only". Expected outcome: Categorization remains enabled with rename-only, but becomes disabled when processing documents only. Run: `./build-tests/ai_file_sorter_tests "Document rename-only does not disable categorization unless processing documents only"` #### Test case: Document analysis ignores other files when categorize files is off Purpose: Verify the entry splitter respects the "categorize files" flag when only document analysis is active. Setup: Prepare a mixed list of image, document, other file, and a directory entry. Set all flags to analyze documents only and categorize files off. Procedure: Call `split_entries_for_analysis()` and inspect the output buckets. Expected outcome: Document entries are analyzed, other non-document files are excluded, and directories are still included in the "other" bucket. Run: `./build-tests/ai_file_sorter_tests "Document analysis ignores other files when categorize files is off"` #### Test case: Image analysis toggle disables when dialog closes without downloads Purpose: Ensure the analysis checkbox reverts if the required visual models are not available. Setup: Configure settings with image analysis off and inject probes that simulate missing visual models and a prompt acceptance. Procedure: Toggle the image analysis checkbox on. Expected outcome: The checkbox reverts to unchecked and settings remain unchanged. Run: `./build-tests/ai_file_sorter_tests "Image analysis toggle disables when dialog closes without downloads"` #### Test case: Image analysis toggle cancels when user declines download Purpose: Verify that declining the download prompt cancels enabling image analysis. Setup: Configure settings with image analysis off and inject probes that simulate missing visual models and prompt rejection. Procedure: Toggle the image analysis checkbox on. Expected outcome: The checkbox remains unchecked, settings remain unchanged, and no download dialog is launched. Run: `./build-tests/ai_file_sorter_tests "Image analysis toggle cancels when user declines download"` #### Test case: Already-renamed images skip vision analysis Purpose: Confirm that images already renamed are handled without re-analysis. Setup: Provide image entries where one is already renamed and a rename-only flag can be toggled. Procedure: Run `split_entries_for_analysis()` in two sections: (a) normal categorization and (b) rename-only enabled. Expected outcome: In normal mode, the already-renamed image is routed to filename-based categorization ("other" bucket). In rename-only mode, the already-renamed image is excluded entirely. Run: `./build-tests/ai_file_sorter_tests "Already-renamed images skip vision analysis"` ### `tests/unit/test_ui_translator.cpp` (non-Windows only) #### Test case: UiTranslator updates menus, actions, and controls Purpose: Validate that the UI translator updates all primary controls, menus, and stateful labels in a consistent pass. Setup: Build a test harness with a `QMainWindow`, many UI controls, and a translator state set to French in settings. Use a translation function that returns the input string to test label wiring rather than actual translation files. Procedure: Call `retranslate_all()` and verify the text of buttons, checkboxes, menus, status labels, and the file explorer dock title. Also verify the language action group selection. Expected outcome: All UI elements show the expected English strings and the French language action is marked checked, demonstrating the retranslate pipeline is correctly wired. Run: `./build-tests/ai_file_sorter_tests "*UiTranslator updates menus*"` ### `tests/unit/test_utils.cpp` #### Test case: get_file_name_from_url extracts filename Purpose: Ensure URL filename extraction returns the last path component. Setup: Use a URL ending with a file name. Procedure: Call `Utils::get_file_name_from_url()`. Expected outcome: The returned string equals the file name (e.g., `mistral-7b.gguf`). Run: `./build-tests/ai_file_sorter_tests "get_file_name_from_url extracts filename"` #### Test case: get_file_name_from_url rejects malformed input Purpose: Confirm invalid URLs are rejected. Setup: Use a URL with no filename component. Procedure: Call `Utils::get_file_name_from_url()` and expect an exception. Expected outcome: A `std::runtime_error` is thrown. Run: `./build-tests/ai_file_sorter_tests "get_file_name_from_url rejects malformed input"` #### Test case: is_cuda_available honors probe overrides Purpose: Verify that CUDA availability probes are honored. Setup: Install a test hook that returns `true`, then one that returns `false`. Procedure: Call `Utils::is_cuda_available()` after each probe. Expected outcome: The function returns `true` and then `false`, matching the probe. Run: `./build-tests/ai_file_sorter_tests "is_cuda_available honors probe overrides"` #### Test case: abbreviate_user_path strips home prefix Purpose: Ensure user paths are shortened relative to `HOME`. Setup: Create a temporary home directory, set `HOME`, and create a file inside `Documents/`. Procedure: Call `Utils::abbreviate_user_path()` on the full path. Expected outcome: The returned string omits the home prefix and begins with `Documents/`. Run: `./build-tests/ai_file_sorter_tests "abbreviate_user_path strips home prefix"` #### Test case: sanitize_path_label strips invalid UTF-8 bytes Purpose: Ensure path labels remain valid UTF-8 even when upstream text contains malformed byte sequences. Setup: Build a string containing an invalid UTF-8 byte between otherwise valid ASCII text. Procedure: Call `Utils::sanitize_path_label()`. Expected outcome: The invalid byte is removed and the returned label remains valid UTF-8 text. Run: `./build-tests/ai_file_sorter_tests "sanitize_path_label strips invalid UTF-8 bytes"` ### `tests/unit/test_llm_selection_dialog_visual.cpp` (non-Windows only) #### Test case: Visual LLaVA entry shows missing env var state Purpose: Confirm UI indicates missing LLaVA download URLs. Setup: Clear `LLAVA_MODEL_URL` and `LLAVA_MMPROJ_URL` and construct the dialog. Procedure: Fetch the LLaVA entry via test access. Expected outcome: The status label reports the missing environment variable and the download button is disabled. Run: `./build-tests/ai_file_sorter_tests "Visual LLaVA entry shows missing env var state"` #### Test case: Visual LLaVA entry shows resume state for partial downloads Purpose: Validate resume state for partial LLaVA downloads. Setup: Create a fake source file and a smaller destination file, inject metadata headers with an expected size. Procedure: Update the LLaVA entry state. Expected outcome: The status label indicates a partial download and the download button changes to "Resume download" and is enabled. Run: `./build-tests/ai_file_sorter_tests "Visual LLaVA entry shows resume state for partial downloads"` #### Test case: Visual LLaVA entry reports download errors Purpose: Ensure download failures are surfaced in the UI. Setup: Inject a network-available override and a download probe that returns a CURL connection error. Procedure: Start the LLaVA model download and wait for the label to update. Expected outcome: The status label begins with "Download error:" indicating the failure is shown to the user. Run: `./build-tests/ai_file_sorter_tests "Visual LLaVA entry reports download errors"` ### `tests/unit/test_settings_image_options.cpp` #### Test case: Settings defaults image analysis off even when visual LLM files exist Purpose: Verify that image analysis defaults remain off when no settings file exists, even if model files are present. Setup: Create dummy LLaVA model files in the expected location and load settings from an empty config directory. Procedure: Call `Settings::load()` and read the image analysis flags. Expected outcome: `load()` returns false, and both analyze and offer-rename flags are false. Run: `./build-tests/ai_file_sorter_tests "Settings defaults image analysis off even when visual LLM files exist"` #### Test case: Settings defaults image analysis off when visual LLM files are missing Purpose: Verify default settings are still off when model files are absent. Setup: Use a fresh config directory with no LLaVA files. Procedure: Call `Settings::load()` and read image analysis flags. Expected outcome: `load()` returns false and analysis/offer-rename remain disabled. Run: `./build-tests/ai_file_sorter_tests "Settings defaults image analysis off when visual LLM files are missing"` #### Test case: Settings enforces rename-only implies offer rename Purpose: Ensure rename-only cannot be enabled without offer-rename. Setup: Save settings with analyze on, offer-rename off, and rename-only on. Procedure: Reload settings from disk. Expected outcome: Offer-rename is forced on while rename-only and process-only settings persist. Run: `./build-tests/ai_file_sorter_tests "Settings enforces rename-only implies offer rename"` #### Test case: Settings persists options group expansion state Purpose: Ensure the image/document option group expansion states persist across load/save. Setup: Use a temporary config directory and set expanded flags for image and document groups. Procedure: Save settings, reload into a new `Settings` instance, and read the flags. Expected outcome: The expansion flags match the saved values. Run: `./build-tests/ai_file_sorter_tests "Settings persists options group expansion state"` ### `tests/unit/test_checkbox_matrix.cpp` #### Test case: Checkbox combinations route entries without renamed files Purpose: Exhaustively validate the file-routing logic for every combination of checkbox flags. Setup: Define a fixed sample set containing an image, a document, an other file, and a directory. Use an empty set of renamed files. Procedure: Iterate all 128 combinations of analysis and filtering flags, call `split_entries_for_analysis()`, and compute the expected bucket for each entry. Expected outcome: Each entry appears only in its expected bucket, image and document buckets contain only supported file types, and a detailed per-combination summary is printed. Run: `./build-tests/ai_file_sorter_tests "Checkbox combinations route entries without renamed files"` #### Test case: Checkbox combinations route entries with renamed files Purpose: Validate routing when image and document entries have already been renamed. Setup: Use the same sample set but mark the image and document names as already renamed. Procedure: Repeat the 128-combination sweep and compare actual buckets to expected behavior for rename-only and categorization scenarios. Expected outcome: Already-renamed items are either skipped or routed to filename-based categorization depending on the rename-only flags, with all entries matching the expected bucket. Run: `./build-tests/ai_file_sorter_tests "Checkbox combinations route entries with renamed files"` ### `tests/unit/test_llm_downloader.cpp` #### Test case: LLMDownloader retries full download after a range error Purpose: Ensure a failed resume attempt triggers a full restart. Setup: Create a partial destination file and configure the downloader with resume headers. Inject a download probe that returns `CURLE_HTTP_RANGE_ERROR` on the first call and succeeds on the second. Procedure: Start the download and wait for completion. Expected outcome: Two attempts are recorded, the second starts from offset 0, the final file size matches the expected size, and no error is reported. Run: `./build-tests/ai_file_sorter_tests "LLMDownloader retries full download after a range error"` #### Test case: LLMDownloader uses cached metadata for partial downloads Purpose: Validate that cached metadata drives download status. Setup: Create a partial local file and an `.aifs.meta` file with the expected content length. Procedure: Construct the downloader and query its status. Expected outcome: Both local and overall download status report `InProgress`, content length is read from metadata, and the downloader is not yet initialized. Run: `./build-tests/ai_file_sorter_tests "LLMDownloader uses cached metadata for partial downloads"` #### Test case: LLMDownloader resets to not started when local file is missing Purpose: Ensure metadata alone does not imply a partial download. Setup: Create metadata without the local file. Procedure: Construct the downloader and query its status. Expected outcome: The status is `NotStarted` for both local and overall views. Run: `./build-tests/ai_file_sorter_tests "LLMDownloader resets to not started when local file is missing"` #### Test case: LLMDownloader treats full local file as complete with cached metadata Purpose: Confirm that a complete local file is recognized as complete. Setup: Create a local file whose size matches the cached content length. Procedure: Construct the downloader and query its status. Expected outcome: Both local and overall download status report `Complete`. Run: `./build-tests/ai_file_sorter_tests "LLMDownloader treats full local file as complete with cached metadata"` ### `tests/unit/test_update_feed.cpp` #### Test case: UpdateFeed selects the correct platform stream Purpose: Ensure the updater resolves the correct platform-specific stream from the shared feed. Setup: Build a feed JSON payload with distinct `windows`, `macos`, and `linux` entries. Procedure: Parse the feed for each platform enum. Expected outcome: Each platform receives its own version and URLs, and the Windows installer checksum is normalized. Run: `./build-tests/ai_file_sorter_tests "UpdateFeed selects the correct platform stream"` #### Test case: UpdateFeed falls back to the legacy single-stream schema Purpose: Preserve compatibility with existing single-stream feeds. Setup: Build a feed JSON payload with the original flat `update` object. Procedure: Parse the feed for a platform. Expected outcome: The legacy fields are still accepted and returned as update info. Run: `./build-tests/ai_file_sorter_tests "UpdateFeed falls back to the legacy single-stream schema"` #### Test case: UpdateInstaller downloads, verifies, and reuses a cached installer Purpose: Validate the Windows-style installer preparation flow without network access. Setup: Inject a fake installer download callback and a fake launch callback. Procedure: Prepare the installer twice and then launch it. Expected outcome: The first prepare downloads and verifies the installer, the second reuses the cached artifact, and the launch callback receives the finalized path. Run: `./build-tests/ai_file_sorter_tests "UpdateInstaller downloads, verifies, and reuses a cached installer"` #### Test case: UpdateInstaller rejects installers that fail SHA-256 verification Purpose: Ensure invalid installer downloads are rejected before launch. Setup: Inject a fake download callback that writes mismatched bytes. Procedure: Prepare the installer with an expected SHA-256 that does not match. Expected outcome: Preparation fails and no finalized installer path is returned. Run: `./build-tests/ai_file_sorter_tests "UpdateInstaller rejects installers that fail SHA-256 verification"` #### Test case: UpdateInstaller redownloads cached installers that fail verification Purpose: Ensure corrupted cached installers are not reused silently. Setup: Prepare a valid cached installer, then overwrite it with different bytes. Procedure: Prepare the installer a second time with the same expected SHA-256. Expected outcome: The cached file is rejected, a new download occurs, and the finalized installer contents match the expected payload. Run: `./build-tests/ai_file_sorter_tests "UpdateInstaller redownloads cached installers that fail verification"` #### Test case: UpdateInstaller reports canceled downloads and removes partial files Purpose: Confirm cancelation produces a canceled result instead of a generic failure and cleans up partial output. Setup: Inject a fake download callback that writes a partial file and then throws the installer cancelation exception when the cancel probe is true. Procedure: Call `prepare()` with a cancel probe that always returns true. Expected outcome: Preparation returns `Canceled`, no finalized installer path is returned, and the partial `.part` file is removed. Run: `./build-tests/ai_file_sorter_tests "UpdateInstaller reports canceled downloads and removes partial files"` #### Test case: UpdateInstaller requires installer metadata before preparing Purpose: Reject malformed update feeds that omit required direct-installer fields. Setup: Create update info once without `installer_url` and once without `installer_sha256`. Procedure: Call `prepare()` for both cases. Expected outcome: Both calls fail with messages indicating the missing field. Run: `./build-tests/ai_file_sorter_tests "UpdateInstaller requires installer metadata before preparing"` #### Test case: UpdateInstaller builds launch requests for EXE and MSI installers Purpose: Verify the installer launch plan uses direct execution for `.exe` files and `msiexec /i` for `.msi` packages. Setup: Build launch requests for representative `.exe` and `.MSI` paths. Procedure: Query the test access helper for both inputs. Expected outcome: The `.exe` request launches the installer directly with no extra arguments, while the `.msi` request targets `msiexec.exe` with `/i `. Run: `./build-tests/ai_file_sorter_tests "UpdateInstaller builds launch requests for EXE and MSI installers"` #### Test case: UpdateInstaller auto-install support remains Windows-only Purpose: Confirm the direct-installer flow is currently gated to Windows builds. Setup: Create update info with installer metadata. Procedure: Query the updater installer support state. Expected outcome: Windows builds report support; other platforms do not. Run: `./build-tests/ai_file_sorter_tests "UpdateInstaller auto-install support remains Windows-only"` ### `tests/unit/test_updater.cpp` #### Test case: Updater error dialog offers manual update fallback without quitting when not requested Purpose: Verify installer-preparation failures still let the user open the normal download page manually for optional updates. Setup: Construct an updater with test handlers for opening the download URL and quitting the app, and schedule the error dialog to click `Update manually`. Procedure: Invoke the updater error handler with a `download_url` and `quit_after_open=false`. Expected outcome: The dialog includes `Update manually`, the download URL handler is called, and the quit handler is not called. Run: `./build-tests/ai_file_sorter_tests "Updater error dialog offers manual update fallback without quitting when not requested"` #### Test case: Updater error dialog can request quit after manual fallback Purpose: Ensure required-update failures can still fall back to the manual download link and then close the app. Setup: Construct an updater with test handlers and schedule the error dialog to click `Update manually`. Procedure: Invoke the updater error handler with a `download_url` and `quit_after_open=true`. Expected outcome: The manual download handler is called and the quit handler is triggered. Run: `./build-tests/ai_file_sorter_tests "Updater error dialog can request quit after manual fallback"` #### Test case: Updater error dialog omits manual fallback when no download URL is available Purpose: Confirm the fallback button is only offered when a manual download link exists. Setup: Construct an updater with test handlers and invoke the error dialog without a `download_url`. Procedure: Attempt to click `Update manually`; the helper falls back to `OK` when the button is absent. Expected outcome: No manual fallback button is present, the error handler returns `false`, and neither the download nor quit handler runs. Run: `./build-tests/ai_file_sorter_tests "Updater error dialog omits manual fallback when no download URL is available"` ### `tests/unit/test_review_dialog_rename_gate.cpp` (non-Windows only) #### Test case: Review dialog rename-only toggles disabled when renames are not allowed Purpose: Verify the review dialog respects the "Offer to rename" gating for images and documents. Setup: Build a dialog with sample image and document entries and auto-close it using a timer. Procedure: Show results once with image/document renames disallowed, then again with renames allowed. Expected outcome: The rename-only checkboxes are disabled in the first case and enabled in the second. Run: `./build-tests/ai_file_sorter_tests "Review dialog rename-only toggles disabled when renames are not allowed"` ### `tests/unit/test_custom_llm.cpp` #### Test case: Custom LLM entries persist across Settings load/save Purpose: Ensure custom LLM definitions persist correctly. Setup: Insert a custom LLM entry and set it as active, then save settings. Procedure: Reload settings and retrieve the custom LLM by ID. Expected outcome: The reloaded entry matches the original fields and the active ID is preserved. Run: `./build-tests/ai_file_sorter_tests "Custom LLM entries persist across Settings load/save"` ### `tests/unit/test_database_manager_rename_only.cpp` #### Test case: DatabaseManager keeps rename-only entries with empty labels Purpose: Ensure rename-only entries are not removed when categories are empty. Setup: Insert one rename-only entry with a suggested name and one empty entry with no rename suggestion. Procedure: Call `remove_empty_categorizations()` and then fetch categorized files. Expected outcome: Only the truly empty entry is removed; the rename-only entry remains with empty category labels and the suggestion intact. Run: `./build-tests/ai_file_sorter_tests "DatabaseManager keeps rename-only entries with empty labels"` #### Test case: DatabaseManager sanitizes invalid UTF-8 in cached labels Purpose: Ensure malformed UTF-8 in cached category labels or suggestions does not propagate into the review dialog pipeline. Setup: Insert a cached entry whose category, subcategory, and suggested filename contain invalid UTF-8 bytes. Procedure: Fetch categorized files from the database. Expected outcome: The loaded category, subcategory, and suggested name are returned with invalid UTF-8 bytes removed. Run: `./build-tests/ai_file_sorter_tests "DatabaseManager sanitizes invalid UTF-8 in cached labels"` #### Test case: DatabaseManager normalizes subcategory stopword suffixes for taxonomy matching Purpose: Verify taxonomy resolution normalizes stopword suffixes like "files". Setup: Resolve categories with and without the "files" suffix (e.g., "Graphics" vs "Graphics files"). Procedure: Compare the resolved taxonomy IDs and labels. Expected outcome: Both resolutions share the same taxonomy ID and normalized labels, while unrelated subcategories (e.g., "Photos") remain unchanged. Run: `./build-tests/ai_file_sorter_tests "DatabaseManager normalizes subcategory stopword suffixes for taxonomy matching"` #### Test case: DatabaseManager normalizes backup category synonyms for taxonomy matching Purpose: Ensure backup/archive category variants collapse to a single canonical taxonomy entry. Setup: Resolve `Archives` and `backup files` with the same subcategory. Procedure: Compare taxonomy IDs and canonical labels. Expected outcome: Both labels map to the same taxonomy entry with canonical category `Archives`. Run: `./build-tests/ai_file_sorter_tests "DatabaseManager normalizes backup category synonyms for taxonomy matching"` #### Test case: DatabaseManager normalizes image category synonyms and image media aliases Purpose: Ensure image-related category variants collapse while non-image media remains distinct. Setup: Resolve `Images`, `Graphics`, `Media + Photos`, and `Media + Audio`. Procedure: Compare taxonomy IDs and canonical labels. Expected outcome: `Images/Graphics/Media+Photos` share taxonomy and canonicalize to `Images`; `Media+Audio` remains `Media`. Run: `./build-tests/ai_file_sorter_tests "DatabaseManager normalizes image category synonyms and image media aliases"` #### Test case: DatabaseManager normalizes document category synonyms for taxonomy matching Purpose: Ensure document-like category variants collapse to `Documents`. Setup: Resolve `Documents`, `Texts`, `Papers`, and `Spreadsheets` with the same subcategory. Procedure: Compare taxonomy IDs and canonical labels. Expected outcome: All variants map to the same taxonomy entry with canonical category `Documents`. Run: `./build-tests/ai_file_sorter_tests "DatabaseManager normalizes document category synonyms for taxonomy matching"` #### Test case: DatabaseManager normalizes installer and update category synonyms for taxonomy matching Purpose: Ensure software/install/update category variants collapse to `Software`. Setup: Resolve `Software`, `Installers`, `Setup files`, `Software Update`, and `Patches`. Procedure: Compare taxonomy IDs and canonical labels. Expected outcome: All variants map to the same taxonomy entry with canonical category `Software`. Run: `./build-tests/ai_file_sorter_tests "DatabaseManager normalizes installer and update category synonyms for taxonomy matching"` ### `tests/unit/test_file_scanner.cpp` #### Test case: hidden files require explicit flag Purpose: Ensure hidden files are filtered unless explicitly requested. Setup: Create a hidden file in a temporary directory. Procedure: Scan with only `Files`, then with `Files | HiddenFiles`. Expected outcome: The hidden file is absent in the first scan and present in the second. Run: `./build-tests/ai_file_sorter_tests "hidden files require explicit flag"` #### Test case: junk files are skipped regardless of flags Purpose: Confirm that known junk files are always excluded. Setup: Create a `.DS_Store` file. Procedure: Scan with `Files | HiddenFiles`. Expected outcome: The junk file does not appear in the results. Run: `./build-tests/ai_file_sorter_tests "junk files are skipped regardless of flags"` #### Test case: application bundles are treated as files Purpose: Ensure application bundles are treated as files rather than directories. Setup: Create a `Sample.app` directory with a `Contents` subdirectory. Procedure: Scan once for files and once for directories. Expected outcome: The bundle appears only in the file scan and not in the directory scan. Run: `./build-tests/ai_file_sorter_tests "application bundles are treated as files"` #### Test case: recursive scans include nested files Purpose: Ensure recursive scans still return files from nested subdirectories. Setup: Create one file in the root and one file in a nested subdirectory. Procedure: Scan with `Files | Recursive`. Expected outcome: Both files appear in the results. Run: `./build-tests/ai_file_sorter_tests "recursive scans include nested files"` #### Test case: recursive scans skip unreadable directories and continue Purpose: Ensure one inaccessible subdirectory does not abort an otherwise valid recursive scan. Setup: Create a readable subtree and a second subtree whose directory permissions are removed (non-Windows only). Procedure: Scan with `Files | Recursive`. Expected outcome: The readable file is returned, the scan does not throw, and the unreadable subtree is skipped. Run: `./build-tests/ai_file_sorter_tests "recursive scans skip unreadable directories and continue"` ### `tests/unit/test_support_prompt.cpp` #### Test case: Support prompt thresholds advance based on response Purpose: Verify support prompt scheduling logic under different user responses. Setup: Create a fresh settings environment and define a callback that returns a simulated response (`NotSure`, `CannotDonate`, or `Support`). Procedure: Increment the categorized file count to the current threshold, observe the prompt, then advance to the next threshold. Expected outcome: The prompt fires exactly at thresholds, the total count increments correctly, and the next threshold increases for all response types. Run: `./build-tests/ai_file_sorter_tests "Support prompt thresholds advance based on response"` #### Test case: Zero categorized increments do not change totals or trigger prompts Purpose: Ensure a zero increment is a no-op. Setup: Fresh settings with a baseline threshold. Procedure: Call the prompt simulation with an increment of `0`. Expected outcome: Total counts and thresholds remain unchanged and the callback is not invoked. Run: `./build-tests/ai_file_sorter_tests "Zero categorized increments do not change totals or trigger prompts"` ### `tests/unit/test_custom_api_endpoint.cpp` #### Test case: Custom API endpoints persist across Settings load/save Purpose: Ensure custom OpenAI-compatible endpoint definitions persist correctly. Setup: Create a custom endpoint with name, description, base URL, API key, and model, then set it active and save. Procedure: Reload settings and retrieve the endpoint by ID. Expected outcome: All fields match the original, and the active endpoint ID is preserved. Run: `./build-tests/ai_file_sorter_tests "Custom API endpoints persist across Settings load/save"` ### `tests/unit/test_categorization_dialog.cpp` (non-Windows only) #### Test case: CategorizationDialog uses subcategory toggle when moving files Purpose: Ensure the dialog respects the subcategory visibility toggle during file moves. Setup: Create a sample categorized file and attach a move probe. Procedure: Toggle the subcategory column state and confirm the dialog. Expected outcome: The move probe records the same subcategory setting that was applied. Run: `./build-tests/ai_file_sorter_tests "CategorizationDialog uses subcategory toggle when moving files"` #### Test case: CategorizationDialog supports sorting by columns Purpose: Verify that the table model sorts correctly by different columns. Setup: Insert two entries with out-of-order file names and categories. Procedure: Sort by the file name column ascending, then by category descending. Expected outcome: The first sort yields alphabetical file names; the second yields categories in reverse alphabetical order. Run: `./build-tests/ai_file_sorter_tests "CategorizationDialog supports sorting by columns"` #### Test case: CategorizationDialog undo restores moved files Purpose: Confirm that undo reverses category moves. Setup: Create a file on disk with a category and subcategory. Procedure: Confirm the dialog to move the file, then trigger undo. Expected outcome: The file moves to the category path, then returns to the original location; undo is enabled only when a move exists. Run: `./build-tests/ai_file_sorter_tests "CategorizationDialog undo restores moved files"` #### Test case: CategorizationDialog undo allows renaming again Purpose: Ensure undo resets rename-only operations and allows reapplication. Setup: Create a rename-only entry with a suggested name. Procedure: Confirm the rename, undo it, and confirm again. Expected outcome: Each confirm applies the rename, and undo restores the original filename for a second rename. Run: `./build-tests/ai_file_sorter_tests "CategorizationDialog undo allows renaming again"` #### Test case: CategorizationDialog rename-only updates cached filename Purpose: Verify database updates when a rename-only action occurs. Setup: Use a dialog with a database manager and a rename-only file with a suggestion. Procedure: Confirm the dialog and query the database. Expected outcome: The old name is not cached; the new name is cached with rename-only metadata and the suggested name. Run: `./build-tests/ai_file_sorter_tests "CategorizationDialog rename-only updates cached filename"` #### Test case: CategorizationDialog allows editing when rename-only checkbox is off Purpose: Ensure category fields remain editable when rename-only mode is not enforced. Setup: Populate the dialog with one rename-only entry and one categorized entry. Procedure: Inspect the category column editability in the model. Expected outcome: Both rows remain editable in the category column. Run: `./build-tests/ai_file_sorter_tests "CategorizationDialog allows editing when rename-only checkbox is off"` #### Test case: CategorizationDialog deduplicates suggested names when rename-only is toggled Purpose: Ensure duplicate suggestions are made unique when rename-only is turned on. Setup: Provide two image entries with identical suggested names. Procedure: Toggle the rename-only checkbox in the dialog. Expected outcome: The suggestions are rewritten with numbered suffixes (e.g., `_1`, `_2`). Run: `./build-tests/ai_file_sorter_tests "CategorizationDialog deduplicates suggested names when rename-only is toggled"` #### Test case: CategorizationDialog avoids double suffixes for numbered suggestions Purpose: Prevent double-numbering when suggestions already contain a suffix. Setup: Use two rename-only entries with a suggestion ending in `_1`. Procedure: Populate the dialog and read back the suggested names. Expected outcome: The first remains `_1`, and the second becomes `_2` without duplicating the suffix. Run: `./build-tests/ai_file_sorter_tests "CategorizationDialog avoids double suffixes for numbered suggestions"` #### Test case: CategorizationDialog hides suggested names for renamed entries Purpose: Hide rename suggestions once the rename has already been applied. Setup: Create an entry with `rename_applied=true` and a suggested name. Procedure: Populate the dialog and inspect the suggested name cell. Expected outcome: The suggested name cell is empty and not editable. Run: `./build-tests/ai_file_sorter_tests "CategorizationDialog hides suggested names for renamed entries"` #### Test case: CategorizationDialog hides already renamed rows when rename-only is on Purpose: Ensure completed renames are hidden when only renaming is requested. Setup: Add one renamed entry and one pending entry, then enable the rename-only checkbox. Procedure: Toggle rename-only and inspect row visibility. Expected outcome: The already renamed row becomes hidden while the pending row remains visible. Run: `./build-tests/ai_file_sorter_tests "CategorizationDialog hides already renamed rows when rename-only is on"` #### Test case: CategorizationDialog deduplicates suggested picture filenames Purpose: Ensure image rename suggestions are unique across multiple rows. Setup: Provide two rename-only image entries with identical suggested names. Procedure: Populate the dialog and read the suggested names. Expected outcome: Suggestions become `_1` and `_2` variants to avoid collisions. Run: `./build-tests/ai_file_sorter_tests "CategorizationDialog deduplicates suggested picture filenames"` #### Test case: CategorizationDialog avoids existing picture filename collisions Purpose: Ensure suggested names do not collide with existing files on disk. Setup: Create a file on disk that matches the suggested name and add a rename-only entry with that suggestion. Procedure: Populate the dialog and inspect the suggestion. Expected outcome: The suggestion is incremented (e.g., `_1`) to avoid the existing file. Run: `./build-tests/ai_file_sorter_tests "CategorizationDialog avoids existing picture filename collisions"` #### Test case: CategorizationDialog rename-only preserves cached categories without renaming Purpose: Ensure rename-only mode keeps existing category assignments even when no rename occurs. Setup: Cache a categorization in the database, then run the dialog with a rename-only entry that has no suggested name. Procedure: Confirm the dialog and query the cache. Expected outcome: The cached category and subcategory are preserved and the entry remains marked rename-only. Run: `./build-tests/ai_file_sorter_tests "CategorizationDialog rename-only preserves cached categories without renaming"` #### Test case: CategorizationDialog rename-only preserves cached categories when renaming Purpose: Ensure rename-only mode keeps cached categories after a rename. Setup: Cache a categorization, then run the dialog with a rename-only entry that includes a suggested name. Procedure: Confirm the dialog and query the cache for the renamed file. Expected outcome: The renamed entry retains the cached category and subcategory with rename-only metadata. Run: `./build-tests/ai_file_sorter_tests "CategorizationDialog rename-only preserves cached categories when renaming"` ### `tests/unit/test_main_app_translation.cpp` (non-Windows only) #### Test case: MainApp retranslate reflects language changes Purpose: Validate that main window labels update for all supported UI languages. Setup: Construct `MainApp` with a settings object and a translation manager. Procedure: Iterate through supported languages, set the language, trigger a retranslate, and read the analyze button and folder label text. Expected outcome: Each language produces the exact expected translations for the two labels. Run: `./build-tests/ai_file_sorter_tests "MainApp retranslate reflects language changes"` ### `tests/unit/test_whitelist_and_prompt.cpp` #### Test case: WhitelistStore initializes from settings and persists defaults Purpose: Ensure whitelist entries are loaded into settings and persisted. Setup: Create a whitelist entry, save it, and initialize the store from settings with a selected whitelist name. Procedure: Verify the settings fields and reload the whitelist store from disk. Expected outcome: The whitelist name, categories, and subcategories remain consistent across initialization and reload. Run: `./build-tests/ai_file_sorter_tests "WhitelistStore initializes from settings and persists defaults"` #### Test case: CategorizationService builds numbered whitelist context Purpose: Confirm the whitelist context includes numbered categories and an "any" subcategory fallback. Setup: Set allowed categories in settings and build a service instance. Procedure: Call the test access method to build the whitelist context string. Expected outcome: The context includes numbered category lines and indicates that subcategories are unrestricted. Run: `./build-tests/ai_file_sorter_tests "CategorizationService builds numbered whitelist context"` #### Test case: CategorizationService builds category language context when non-English selected Purpose: Ensure the category language context is generated for non-English settings. Setup: Set the category language to French. Procedure: Build the category language context string. Expected outcome: The context is non-empty and references "French". Run: `./build-tests/ai_file_sorter_tests "CategorizationService builds category language context when non-English selected"` #### Test case: CategorizationService builds category language context for Spanish Purpose: Verify Spanish category language is handled explicitly. Setup: Set the category language to Spanish. Procedure: Build the category language context string. Expected outcome: The context is non-empty and references "Spanish". Run: `./build-tests/ai_file_sorter_tests "CategorizationService builds category language context for Spanish"` #### Test case: CategorizationService parses category output without spaced colon delimiters Purpose: Ensure category parsing accepts compact `Category:Subcategory` output. Setup: Use a fixed LLM stub response `Documents:Spreadsheets`. Procedure: Run `categorize_entries` for one file entry. Expected outcome: Parsed category is `Documents` and parsed subcategory is `Spreadsheets`. Run: `./build-tests/ai_file_sorter_tests "CategorizationService parses category output without spaced colon delimiters"` #### Test case: CategorizationService parses labeled category and subcategory lines Purpose: Ensure category parsing accepts labeled multiline output. Setup: Use a fixed LLM stub response with `Category: ...` and `Subcategory: ...` lines. Procedure: Run `categorize_entries` for one file entry. Expected outcome: Parsed labels match the provided category and subcategory values. Run: `./build-tests/ai_file_sorter_tests "CategorizationService parses labeled category and subcategory lines"` ### `tests/unit/test_cache_interactions.cpp` #### Test case: CategorizationService uses cached categorization without calling LLM Purpose: Ensure cached category/subcategory rows are returned without invoking the LLM. Setup: Seed the database with a resolved category for a file entry and prepare a counting LLM stub. Procedure: Call `categorize_entries` for that file. Expected outcome: The cached category is returned and the LLM call counter stays at zero. Run: `./build-tests/ai_file_sorter_tests "CategorizationService uses cached categorization without calling LLM"` #### Test case: CategorizationService falls back to LLM when cache is empty Purpose: Validate cache fallback to LLM and persistence of returned category values. Setup: Seed an empty cache record for a file and prepare a counting LLM stub with a valid label response. Procedure: Call `categorize_entries` for that file and then read the DB row. Expected outcome: The LLM is called once and the resulting category/subcategory are written back to cache. Run: `./build-tests/ai_file_sorter_tests "CategorizationService falls back to LLM when cache is empty"` #### Test case: CategorizationService loads cached entries recursively for analysis Purpose: Confirm recursive cache loading obeys the `include_subdirectories` setting. Setup: Seed one cached row at root level and one in a child path. Procedure: Call `load_cached_entries` with recursion off, then on. Expected outcome: Non-recursive mode returns only root rows; recursive mode returns both rows. Run: `./build-tests/ai_file_sorter_tests "CategorizationService loads cached entries recursively for analysis"` #### Test case: ResultsCoordinator respects full-path cache keys for recursive scans Purpose: Ensure recursive scans treat same-name files in different folders as distinct when using full-path cache keys. Setup: Create duplicate filenames at root and nested paths, then seed cache keys by full path. Procedure: Compute uncached entries via `find_files_to_categorize`. Expected outcome: Only the truly uncached nested path remains in the result set. Run: `./build-tests/ai_file_sorter_tests "ResultsCoordinator respects full-path cache keys for recursive scans"` #### Test case: CategorizationService invokes completion callback per entry Purpose: Verify per-entry completion notifications fire for categorization progress tracking. Setup: Prepare multiple file entries and callbacks that count queued/completed events. Procedure: Run `categorize_entries` and capture callback counters. Expected outcome: Queue and completion callbacks are each invoked once per processed entry. Run: `./build-tests/ai_file_sorter_tests "CategorizationService invokes completion callback per entry"` ### Test infrastructure: `tests/unit/test_cli_reporter.cpp` This file registers a Catch2 event listener that prints a one-line "[TEST]" banner for each test case as it begins. It does not define test cases itself, but it makes CLI output easier to follow during long runs. ================================================ FILE: TRADEMARKS.md ================================================ # Trademarks This project is open source, but its name and branding are not licensed for general reuse. The project owner claims trademark rights, to the extent permitted by law, in the following project marks (the "Project Marks"): - `AI File Sorter` - `ai-file-sorter` - The AI File Sorter app name, word marks, logos, icons, badges, and other official branding assets included in this repository, including the app icon in `app/resources/images/icon_256x256.png` The source code in this repository is licensed separately under the GNU Affero General Public License v3.0 (see `LICENSE`). That license applies to the code and other material covered by copyright. It does not grant permission to use the Project Marks, except for truthful, nominative reference. You may: - Use the Project Marks in plain text to refer to the official project, discuss compatibility, or describe unmodified official releases. - Keep existing trademark notices intact when redistributing unmodified copies. You may not, without prior written permission from the project owner: - Use the Project Marks to brand a modified build, fork, derivative distribution, commercial service, or other product in a way that is likely to cause confusion. - Use the Project Marks, logos, or other branding in a way that implies sponsorship, endorsement, affiliation, or official status. - Register, adopt, or use confusingly similar names, domains, package names, or social handles. If you distribute a modified version of this project, you should remove or replace the Project Marks, including the app name, icon, and logos, unless you have separate written permission to keep them. Third-party product names, logos, and trademarks referenced in this repository remain the property of their respective owners. All trademark rights are reserved. No trademark license is granted by this repository, by the AGPL, or by any contributor, except by separate express written permission. This file provides notice of the project's trademark policy. It is not a substitute for trademark registration or jurisdiction-specific legal advice. ================================================ FILE: app/CMakeLists.txt ================================================ cmake_minimum_required(VERSION 3.21) project(AIFileSorter LANGUAGES CXX) # C++ standard set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) option(AI_FILE_SORTER_BUILD_TESTS "Build unit tests (requires Catch2 submodule)" OFF) option(AI_FILE_SORTER_REQUIRE_EMBEDDED_PDF_BACKEND "Require vendored PDFium for PDF extraction instead of silently falling back to external CLI tools." ON) set(AI_FILE_SORTER_UPDATE_MODE "PLATFORM_DEFAULT" CACHE STRING "Updater behavior for this build: PLATFORM_DEFAULT, AUTO_INSTALL, NOTIFY_ONLY, or DISABLED") set_property(CACHE AI_FILE_SORTER_UPDATE_MODE PROPERTY STRINGS PLATFORM_DEFAULT AUTO_INSTALL NOTIFY_ONLY DISABLED) set(_aifs_effective_update_mode "${AI_FILE_SORTER_UPDATE_MODE}") if(_aifs_effective_update_mode STREQUAL "PLATFORM_DEFAULT") if(WIN32) set(_aifs_effective_update_mode "AUTO_INSTALL") else() set(_aifs_effective_update_mode "NOTIFY_ONLY") endif() endif() set(_aifs_allowed_update_modes AUTO_INSTALL NOTIFY_ONLY DISABLED) list(FIND _aifs_allowed_update_modes "${_aifs_effective_update_mode}" _aifs_update_mode_index) if(_aifs_update_mode_index EQUAL -1) message(FATAL_ERROR "Unsupported AI_FILE_SORTER_UPDATE_MODE='${AI_FILE_SORTER_UPDATE_MODE}'. " "Expected PLATFORM_DEFAULT, AUTO_INSTALL, NOTIFY_ONLY, or DISABLED.") endif() if(_aifs_effective_update_mode STREQUAL "AUTO_INSTALL") set(AI_FILE_SORTER_UPDATE_MODE_DEFINE AI_FILE_SORTER_UPDATE_MODE_AUTO_INSTALL) elseif(_aifs_effective_update_mode STREQUAL "NOTIFY_ONLY") set(AI_FILE_SORTER_UPDATE_MODE_DEFINE AI_FILE_SORTER_UPDATE_MODE_NOTIFY_ONLY) else() set(AI_FILE_SORTER_UPDATE_MODE_DEFINE AI_FILE_SORTER_UPDATE_MODE_DISABLED) endif() if(DEFINED VCPKG_INSTALLED_DIR AND NOT "${VCPKG_INSTALLED_DIR}" STREQUAL "") set(AIFS_VCPKG_INSTALLED_ROOT "${VCPKG_INSTALLED_DIR}") else() set(AIFS_VCPKG_INSTALLED_ROOT "${CMAKE_BINARY_DIR}/vcpkg_installed") endif() message(STATUS "AI File Sorter updater mode: ${_aifs_effective_update_mode}") include(CheckSymbolExists) include(CheckCXXSourceCompiles) function(aifs_apply_update_mode target_name) target_compile_definitions(${target_name} PRIVATE ${AI_FILE_SORTER_UPDATE_MODE_DEFINE}) endfunction() function(aifs_apply_named_update_mode target_name update_mode) if(update_mode STREQUAL "AUTO_INSTALL") target_compile_definitions(${target_name} PRIVATE AI_FILE_SORTER_UPDATE_MODE_AUTO_INSTALL) elseif(update_mode STREQUAL "NOTIFY_ONLY") target_compile_definitions(${target_name} PRIVATE AI_FILE_SORTER_UPDATE_MODE_NOTIFY_ONLY) elseif(update_mode STREQUAL "DISABLED") target_compile_definitions(${target_name} PRIVATE AI_FILE_SORTER_UPDATE_MODE_DISABLED) else() message(FATAL_ERROR "Unsupported explicit updater mode '${update_mode}' for target '${target_name}'.") endif() endfunction() function(aifs_apply_expected_update_mode target_name update_mode) if(update_mode STREQUAL "AUTO_INSTALL") target_compile_definitions(${target_name} PRIVATE AI_FILE_SORTER_EXPECTED_UPDATE_MODE_AUTO_INSTALL) elseif(update_mode STREQUAL "NOTIFY_ONLY") target_compile_definitions(${target_name} PRIVATE AI_FILE_SORTER_EXPECTED_UPDATE_MODE_NOTIFY_ONLY) elseif(update_mode STREQUAL "DISABLED") target_compile_definitions(${target_name} PRIVATE AI_FILE_SORTER_EXPECTED_UPDATE_MODE_DISABLED) else() message(FATAL_ERROR "Unsupported expected updater mode '${update_mode}' for target '${target_name}'.") endif() endfunction() # Prefer MSVC on Windows if available if(WIN32 AND CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") add_definitions(-D_CRT_SECURE_NO_WARNINGS) # Keep MSVC worker processes busy within each project in addition to # the top-level cmake --build --parallel job scheduling. add_compile_options( "$<$:/MP>" "$<$:/MP>" ) endif() # Qt6 find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets) find_package(Qt6LinguistTools CONFIG QUIET) if(NOT Qt6LinguistTools_FOUND) set(_aifs_qttools_hints "") if(DEFINED ENV{HOMEBREW_PREFIX} AND NOT "$ENV{HOMEBREW_PREFIX}" STREQUAL "") list(APPEND _aifs_qttools_hints "$ENV{HOMEBREW_PREFIX}/opt/qttools") endif() list(APPEND _aifs_qttools_hints /opt/homebrew/opt/qttools /usr/local/opt/qttools) if(DEFINED Qt6_DIR AND NOT "${Qt6_DIR}" STREQUAL "") get_filename_component(_aifs_qt6_prefix "${Qt6_DIR}/../../.." ABSOLUTE) list(APPEND _aifs_qttools_hints "${_aifs_qt6_prefix}") endif() list(REMOVE_DUPLICATES _aifs_qttools_hints) foreach(_aifs_qttools_hint IN LISTS _aifs_qttools_hints) if(EXISTS "${_aifs_qttools_hint}/lib/cmake/Qt6LinguistTools/Qt6LinguistToolsConfig.cmake") list(APPEND CMAKE_PREFIX_PATH "${_aifs_qttools_hint}") endif() endforeach() list(REMOVE_DUPLICATES CMAKE_PREFIX_PATH) find_package(Qt6LinguistTools CONFIG REQUIRED) endif() # Third-party deps (resolved best via vcpkg on Windows) find_package(CURL REQUIRED) find_package(OpenSSL REQUIRED) find_package(SQLite3 REQUIRED) # JsonCpp may not ship a CMake config on some distros (e.g. Ubuntu). Try # config mode first, then fall back to pkg-config. find_package(JsonCpp CONFIG QUIET) if(NOT JsonCpp_FOUND) find_package(PkgConfig REQUIRED) pkg_check_modules(JSONCPP REQUIRED jsoncpp) add_library(JsonCpp::JsonCpp INTERFACE IMPORTED) target_include_directories(JsonCpp::JsonCpp INTERFACE ${JSONCPP_INCLUDE_DIRS}) target_link_directories(JsonCpp::JsonCpp INTERFACE ${JSONCPP_LIBRARY_DIRS}) target_link_libraries(JsonCpp::JsonCpp INTERFACE ${JSONCPP_LINK_LIBRARIES}) else() if(NOT TARGET JsonCpp::JsonCpp) add_library(JsonCpp::JsonCpp INTERFACE IMPORTED) endif() endif() find_package(fmt REQUIRED CONFIG) find_package(spdlog REQUIRED CONFIG) find_package(Intl REQUIRED) # libintl/gettext # MediaInfoLib from vcpkg depends on the separate ZenLib package and refers to # its imported target as plain "zen". find_package(ZenLib CONFIG QUIET) # MediaInfoLib policy: # - Must come from package managers (apt/dnf/pacman/brew/vcpkg) # - Vendored submodules / checked-in binaries are rejected option(AI_FILE_SORTER_REQUIRE_MEDIAINFOLIB "Require MediaInfoLib at configure time for full audio/video metadata extraction" ON) option(AI_FILE_SORTER_ALLOW_VENDORED_MEDIAINFOLIB "Allow vendored MediaInfo in the repository (not recommended)" OFF) file(REAL_PATH "${CMAKE_CURRENT_SOURCE_DIR}/.." AI_FILE_SORTER_REPO_ROOT) set(_aifs_blocked_mediainfo_paths "${AI_FILE_SORTER_REPO_ROOT}/external/MediaInfoLib" "${AI_FILE_SORTER_REPO_ROOT}/external/libmediainfo" "${CMAKE_CURRENT_SOURCE_DIR}/lib/mediainfo" "${CMAKE_CURRENT_SOURCE_DIR}/include/MediaInfo" ) if(NOT AI_FILE_SORTER_ALLOW_VENDORED_MEDIAINFOLIB) foreach(_blocked_path IN LISTS _aifs_blocked_mediainfo_paths) if(EXISTS "${_blocked_path}") message(FATAL_ERROR "Found vendored MediaInfo content at '${_blocked_path}'. " "Use a package-managed libmediainfo (apt/dnf/pacman/brew/vcpkg) instead.") endif() endforeach() endif() function(aifs_assert_path_not_in_repo path_value label) if(NOT path_value) return() endif() file(TO_CMAKE_PATH "${AI_FILE_SORTER_REPO_ROOT}" _repo_root_norm) string(REGEX REPLACE "([][+.*^$(){}|?\\\\])" "\\\\\\1" _repo_root_regex "${_repo_root_norm}") foreach(_entry IN LISTS path_value) if(NOT _entry OR _entry MATCHES "^\\$<") continue() endif() file(TO_CMAKE_PATH "${_entry}" _entry_norm) # vcpkg manifest mode can stage package-managed headers/libs inside the # build tree under a local vcpkg_installed directory. That is still a # package-manager origin, not vendored MediaInfo content. if(_entry_norm MATCHES "(^|/)vcpkg_installed(/|$)") continue() endif() if(_entry_norm MATCHES "^${_repo_root_regex}(/|$)") message(FATAL_ERROR "MediaInfo must come from a package manager. " "Repository-local path detected for ${label}: '${_entry}'.") endif() endforeach() endfunction() function(aifs_assert_mediainfo_target_external target_name) if(NOT TARGET ${target_name}) return() endif() foreach(_prop IN ITEMS IMPORTED_LOCATION IMPORTED_IMPLIB INTERFACE_INCLUDE_DIRECTORIES INTERFACE_LINK_DIRECTORIES) get_target_property(_prop_value ${target_name} ${_prop}) if(NOT _prop_value OR _prop_value STREQUAL "_prop_value-NOTFOUND") continue() endif() aifs_assert_path_not_in_repo("${_prop_value}" "${target_name}:${_prop}") endforeach() endfunction() set(MEDIAINFO_DEPS_LIBS "") find_package(MediaInfoLib CONFIG QUIET) if(TARGET MediaInfoLib::MediaInfoLib) list(APPEND MEDIAINFO_DEPS_LIBS MediaInfoLib::MediaInfoLib) elseif(TARGET MediaInfoLib::MediaInfo) list(APPEND MEDIAINFO_DEPS_LIBS MediaInfoLib::MediaInfo) elseif(TARGET MediaInfo::MediaInfo) list(APPEND MEDIAINFO_DEPS_LIBS MediaInfo::MediaInfo) elseif(DEFINED MediaInfoLib_LIBRARY AND TARGET ${MediaInfoLib_LIBRARY}) # The vcpkg MediaInfoLib port exports a plain imported target named # "mediainfo" and exposes that name through MediaInfoLib_LIBRARY. list(APPEND MEDIAINFO_DEPS_LIBS ${MediaInfoLib_LIBRARY}) elseif(TARGET mediainfo) list(APPEND MEDIAINFO_DEPS_LIBS mediainfo) else() find_package(PkgConfig QUIET) if(PkgConfig_FOUND) pkg_check_modules(MEDIAINFO QUIET IMPORTED_TARGET libmediainfo) if(TARGET PkgConfig::MEDIAINFO) list(APPEND MEDIAINFO_DEPS_LIBS PkgConfig::MEDIAINFO) endif() endif() if(NOT MEDIAINFO_DEPS_LIBS AND APPLE) set(_aifs_mediainfo_prefixes "") if(DEFINED ENV{HOMEBREW_PREFIX} AND NOT "$ENV{HOMEBREW_PREFIX}" STREQUAL "") list(APPEND _aifs_mediainfo_prefixes "$ENV{HOMEBREW_PREFIX}") endif() list(APPEND _aifs_mediainfo_prefixes /opt/homebrew /usr/local) list(REMOVE_DUPLICATES _aifs_mediainfo_prefixes) set(_aifs_mediainfo_include_hints "") set(_aifs_mediainfo_library_hints "") foreach(_aifs_prefix IN LISTS _aifs_mediainfo_prefixes) list(APPEND _aifs_mediainfo_include_hints "${_aifs_prefix}/opt/libmediainfo/include" "${_aifs_prefix}/include" ) list(APPEND _aifs_mediainfo_library_hints "${_aifs_prefix}/opt/libmediainfo/lib" "${_aifs_prefix}/lib" ) endforeach() find_path(AIFS_MEDIAINFO_INCLUDE_DIR NAMES MediaInfo/MediaInfo.h HINTS ${_aifs_mediainfo_include_hints} ) find_library(AIFS_MEDIAINFO_LIBRARY NAMES mediainfo libmediainfo HINTS ${_aifs_mediainfo_library_hints} ) if(AIFS_MEDIAINFO_INCLUDE_DIR AND AIFS_MEDIAINFO_LIBRARY) if(NOT TARGET AIFS::MediaInfoLib) add_library(AIFS::MediaInfoLib UNKNOWN IMPORTED) set_target_properties(AIFS::MediaInfoLib PROPERTIES IMPORTED_LOCATION "${AIFS_MEDIAINFO_LIBRARY}" INTERFACE_INCLUDE_DIRECTORIES "${AIFS_MEDIAINFO_INCLUDE_DIR}" ) endif() list(APPEND MEDIAINFO_DEPS_LIBS AIFS::MediaInfoLib) endif() unset(_aifs_mediainfo_include_hints) unset(_aifs_mediainfo_library_hints) unset(_aifs_mediainfo_prefixes) endif() endif() if(MEDIAINFO_DEPS_LIBS) foreach(_mediainfo_target IN LISTS MEDIAINFO_DEPS_LIBS) aifs_assert_mediainfo_target_external(${_mediainfo_target}) endforeach() add_compile_definitions(AI_FILE_SORTER_USE_MEDIAINFOLIB) message(STATUS "MediaInfoLib found via package-managed dependency: enabling full audio/video metadata extraction.") elseif(AI_FILE_SORTER_REQUIRE_MEDIAINFOLIB) message(FATAL_ERROR "MediaInfoLib is required but was not found. Install libmediainfo development files " "(Linux: libmediainfo-dev, macOS: brew install mediainfo, Windows/vcpkg: libmediainfo). " "Vendored MediaInfo submodules/binaries are not supported.") else() message(STATUS "MediaInfoLib not found: using built-in metadata fallback parsers " "(audio + MP4/MOV/M4V/3GP tags only).") endif() # Vendored document analysis deps set(EXTERNAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../external") set(PUGIXML_DIR "${EXTERNAL_DIR}/pugixml") set(LIBZIP_DIR "${EXTERNAL_DIR}/libzip") set(PDFIUM_DIR "${EXTERNAL_DIR}/pdfium") set(DOC_DEPS_INCLUDE_DIRS "") set(DOC_DEPS_LIBS "") # Pugixml (compiled via PugixmlBundle.cpp) if(EXISTS "${PUGIXML_DIR}/src/pugixml.hpp") list(APPEND DOC_DEPS_INCLUDE_DIRS "${PUGIXML_DIR}/src") add_compile_definitions(PUGIXML_NO_EXCEPTIONS AI_FILE_SORTER_USE_PUGIXML) endif() # libzip (build from vendored source) if(EXISTS "${LIBZIP_DIR}/CMakeLists.txt") set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE) set(ENABLE_BZIP2 OFF CACHE BOOL "" FORCE) set(ENABLE_LZMA OFF CACHE BOOL "" FORCE) set(ENABLE_ZSTD OFF CACHE BOOL "" FORCE) set(ENABLE_OPENSSL OFF CACHE BOOL "" FORCE) set(ENABLE_GNUTLS OFF CACHE BOOL "" FORCE) set(ENABLE_MBEDTLS OFF CACHE BOOL "" FORCE) set(ENABLE_COMMONCRYPTO OFF CACHE BOOL "" FORCE) set(ENABLE_WINDOWS_CRYPTO OFF CACHE BOOL "" FORCE) add_subdirectory("${LIBZIP_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/libzip") if(TARGET libzip::zip) add_compile_definitions(AI_FILE_SORTER_USE_LIBZIP) list(APPEND DOC_DEPS_INCLUDE_DIRS "${LIBZIP_DIR}/lib" "${CMAKE_CURRENT_BINARY_DIR}/libzip") list(APPEND DOC_DEPS_LIBS libzip::zip) endif() endif() set(PDFIUM_PLATFORM_DIR "") set(PDFIUM_LIBRARY "") set(PDFIUM_RUNTIME "") set(_aifs_pdfium_missing_reason "") if(WIN32) if(CMAKE_SIZEOF_VOID_P EQUAL 8) set(PDFIUM_PLATFORM_DIR "${PDFIUM_DIR}/windows-x64") set(PDFIUM_LIBRARY "${PDFIUM_PLATFORM_DIR}/lib/pdfium.dll.lib") set(PDFIUM_RUNTIME "${PDFIUM_PLATFORM_DIR}/bin/pdfium.dll") else() set(_aifs_pdfium_missing_reason "Embedded PDFium is only vendored for 64-bit Windows builds.") endif() elseif(APPLE) set(_aifs_pdfium_apple_arch "") if(CMAKE_OSX_ARCHITECTURES) list(LENGTH CMAKE_OSX_ARCHITECTURES _aifs_pdfium_arch_count) if(_aifs_pdfium_arch_count GREATER 1) set(_aifs_pdfium_missing_reason "Embedded PDFium is vendored per-architecture. Configure a single macOS architecture instead of a universal build.") else() list(GET CMAKE_OSX_ARCHITECTURES 0 _aifs_pdfium_apple_arch) endif() endif() if(NOT _aifs_pdfium_apple_arch) set(_aifs_pdfium_apple_arch "${CMAKE_SYSTEM_PROCESSOR}") endif() string(TOLOWER "${_aifs_pdfium_apple_arch}" _aifs_pdfium_apple_arch) if(_aifs_pdfium_apple_arch MATCHES "^(arm64|aarch64)$") set(PDFIUM_PLATFORM_DIR "${PDFIUM_DIR}/macos-arm64") set(PDFIUM_LIBRARY "${PDFIUM_PLATFORM_DIR}/lib/libpdfium.dylib") set(PDFIUM_RUNTIME "${PDFIUM_LIBRARY}") elseif(_aifs_pdfium_apple_arch MATCHES "^(x86_64|amd64)$") set(PDFIUM_PLATFORM_DIR "${PDFIUM_DIR}/macos-x64") set(PDFIUM_LIBRARY "${PDFIUM_PLATFORM_DIR}/lib/libpdfium.dylib") set(PDFIUM_RUNTIME "${PDFIUM_LIBRARY}") else() set(_aifs_pdfium_missing_reason "Embedded PDFium is not vendored for macOS architecture '${_aifs_pdfium_apple_arch}'.") endif() elseif(UNIX) string(TOLOWER "${CMAKE_SYSTEM_PROCESSOR}" _aifs_pdfium_linux_arch) if(_aifs_pdfium_linux_arch MATCHES "^(x86_64|amd64)$") set(PDFIUM_PLATFORM_DIR "${PDFIUM_DIR}/linux-x64") set(PDFIUM_LIBRARY "${PDFIUM_PLATFORM_DIR}/lib/libpdfium.so") set(PDFIUM_RUNTIME "${PDFIUM_LIBRARY}") else() set(_aifs_pdfium_missing_reason "Embedded PDFium is not vendored for Linux architecture '${CMAKE_SYSTEM_PROCESSOR}'.") endif() endif() set(_aifs_pdfium_ready FALSE) if(PDFIUM_PLATFORM_DIR AND EXISTS "${PDFIUM_PLATFORM_DIR}/include/fpdfview.h" AND EXISTS "${PDFIUM_LIBRARY}" AND PDFIUM_RUNTIME AND EXISTS "${PDFIUM_RUNTIME}") set(_aifs_pdfium_ready TRUE) endif() if(_aifs_pdfium_ready) add_compile_definitions(AI_FILE_SORTER_USE_PDFIUM) list(APPEND DOC_DEPS_INCLUDE_DIRS "${PDFIUM_PLATFORM_DIR}/include") add_library(pdfium SHARED IMPORTED) if(WIN32) set_target_properties(pdfium PROPERTIES IMPORTED_IMPLIB "${PDFIUM_LIBRARY}" IMPORTED_LOCATION "${PDFIUM_RUNTIME}" ) else() set_target_properties(pdfium PROPERTIES IMPORTED_LOCATION "${PDFIUM_LIBRARY}" ) endif() list(APPEND DOC_DEPS_LIBS pdfium) elseif(PDFIUM_PLATFORM_DIR OR _aifs_pdfium_missing_reason) if(NOT _aifs_pdfium_missing_reason) set(_aifs_pdfium_missing_reason "Embedded PDFium is incomplete under '${PDFIUM_PLATFORM_DIR}'. Run app/scripts/vendor_doc_deps.sh or app/scripts/vendor_doc_deps.ps1 to populate the vendored runtime files.") endif() if(AI_FILE_SORTER_REQUIRE_EMBEDDED_PDF_BACKEND) message(FATAL_ERROR "${_aifs_pdfium_missing_reason}") else() message(WARNING "${_aifs_pdfium_missing_reason} Falling back to 'pdftotext' when available.") endif() endif() # Sources set(APP_MAIN_SOURCE "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp") file(GLOB APP_LIB_SOURCES CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/lib/*.cpp" ) file(GLOB APP_HEADER_SOURCES CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/include/*.hpp" ) set(APP_SOURCES ${APP_MAIN_SOURCE} ${APP_LIB_SOURCES}) set(AIFS_TRANSLATION_TS_FILES "${CMAKE_CURRENT_SOURCE_DIR}/resources/i18n/aifilesorter_fr.ts" "${CMAKE_CURRENT_SOURCE_DIR}/resources/i18n/aifilesorter_de.ts" "${CMAKE_CURRENT_SOURCE_DIR}/resources/i18n/aifilesorter_it.ts" "${CMAKE_CURRENT_SOURCE_DIR}/resources/i18n/aifilesorter_es.ts" "${CMAKE_CURRENT_SOURCE_DIR}/resources/i18n/aifilesorter_nl.ts" "${CMAKE_CURRENT_SOURCE_DIR}/resources/i18n/aifilesorter_tr.ts" "${CMAKE_CURRENT_SOURCE_DIR}/resources/i18n/aifilesorter_ko.ts" ) set(AIFS_TRANSLATION_QM_DIR "${CMAKE_CURRENT_BINARY_DIR}/i18n") # Executable (GUI subsystem on Windows) if(WIN32) add_executable(aifilesorter WIN32 ${APP_SOURCES}) else() add_executable(aifilesorter ${APP_SOURCES}) endif() aifs_apply_update_mode(aifilesorter) target_include_directories(aifilesorter PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/include" "${CMAKE_CURRENT_SOURCE_DIR}/include/llama" "${CMAKE_CURRENT_SOURCE_DIR}/include/external/llama.cpp/tools/mtmd" ${DOC_DEPS_INCLUDE_DIRS} ) qt_add_lupdate( NO_GLOBAL_TARGET LUPDATE_TARGET update_translations SOURCE_TARGETS aifilesorter TS_FILES ${AIFS_TRANSLATION_TS_FILES} SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/startapp_windows.cpp" ${APP_HEADER_SOURCES} OPTIONS -no-obsolete ) qt_add_lrelease( LRELEASE_TARGET release_app_translations TS_FILES ${AIFS_TRANSLATION_TS_FILES} QM_OUTPUT_DIRECTORY "${AIFS_TRANSLATION_QM_DIR}" QM_FILES_OUTPUT_VARIABLE AIFS_TRANSLATION_QM_FILES ) set_source_files_properties(${AIFS_TRANSLATION_QM_FILES} PROPERTIES GENERATED TRUE) function(aifs_add_translation_resources target_name) qt_add_resources(${target_name} "${target_name}_translations" PREFIX "/i18n" BASE "${AIFS_TRANSLATION_QM_DIR}" FILES ${AIFS_TRANSLATION_QM_FILES} ) endfunction() aifs_add_translation_resources(aifilesorter) # Resources (equivalent to rcc generation in Makefile) set(APP_RESOURCE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/resources/.env" "${CMAKE_CURRENT_SOURCE_DIR}/resources/images/logo.png" "${CMAKE_CURRENT_SOURCE_DIR}/resources/images/qn_logo.png" "${CMAKE_CURRENT_SOURCE_DIR}/resources/images/app_icon_128.png" "${CMAKE_CURRENT_SOURCE_DIR}/resources/images/icon_512x512.png" "${CMAKE_CURRENT_SOURCE_DIR}/resources/certs/cacert.pem" ) set_source_files_properties( "${CMAKE_CURRENT_SOURCE_DIR}/resources/.env" PROPERTIES QT_RESOURCE_ALIAS ".env" ) set_source_files_properties( "${CMAKE_CURRENT_SOURCE_DIR}/resources/images/logo.png" PROPERTIES QT_RESOURCE_ALIAS "images/logo.png" ) set_source_files_properties( "${CMAKE_CURRENT_SOURCE_DIR}/resources/images/qn_logo.png" PROPERTIES QT_RESOURCE_ALIAS "images/qn_logo.png" ) set_source_files_properties( "${CMAKE_CURRENT_SOURCE_DIR}/resources/images/app_icon_128.png" PROPERTIES QT_RESOURCE_ALIAS "images/app_icon_128.png" ) set_source_files_properties( "${CMAKE_CURRENT_SOURCE_DIR}/resources/images/icon_512x512.png" PROPERTIES QT_RESOURCE_ALIAS "images/icon_512x512.png" ) set_source_files_properties( "${CMAKE_CURRENT_SOURCE_DIR}/resources/certs/cacert.pem" PROPERTIES QT_RESOURCE_ALIAS "certs/cacert.pem" ) qt_add_resources(aifilesorter "app_resources" PREFIX "/net/quicknode/AIFileSorter" FILES ${APP_RESOURCE_FILES} ) if(WIN32) if(DEFINED ENV{WindowsSdkDir} AND DEFINED ENV{WindowsSDKLibVersion}) set(WIN_SDK_UM_DIR "$ENV{WindowsSdkDir}Lib/$ENV{WindowsSDKLibVersion}/um/x64") set(WIN_SDK_UCRT_DIR "$ENV{WindowsSdkDir}Lib/$ENV{WindowsSDKLibVersion}/ucrt/x64") if(EXISTS "${WIN_SDK_UM_DIR}") link_directories("${WIN_SDK_UM_DIR}") endif() if(EXISTS "${WIN_SDK_UCRT_DIR}") link_directories("${WIN_SDK_UCRT_DIR}") endif() endif() set(PRECOMPILED_CPU_LIB_DIR "${CMAKE_CURRENT_SOURCE_DIR}/lib/precompiled/cpu/lib") set(PRECOMPILED_CPU_BIN_DIR "${CMAKE_CURRENT_SOURCE_DIR}/lib/precompiled/cpu/bin") set(LLAMA_CPU_IMPORT "${PRECOMPILED_CPU_LIB_DIR}/llama.lib") set(LLAMA_CPU_DLL "${PRECOMPILED_CPU_BIN_DIR}/llama.dll") if(NOT EXISTS "${LLAMA_CPU_IMPORT}") message(FATAL_ERROR "Missing ${LLAMA_CPU_IMPORT}. Run app/scripts/build_llama_windows.ps1 cuda=off vcpkgroot= first.") endif() if(NOT EXISTS "${LLAMA_CPU_DLL}") message(FATAL_ERROR "Missing ${LLAMA_CPU_DLL}. Run app/scripts/build_llama_windows.ps1 cuda=off vcpkgroot= to stage runtime DLLs.") endif() add_library(llama SHARED IMPORTED) set_target_properties(llama PROPERTIES IMPORTED_IMPLIB "${LLAMA_CPU_IMPORT}" IMPORTED_LOCATION "${LLAMA_CPU_DLL}" ) foreach(libName IN ITEMS ggml ggml-base ggml-cpu) set(import_path "${PRECOMPILED_CPU_LIB_DIR}/${libName}.lib") set(dll_path "${PRECOMPILED_CPU_BIN_DIR}/${libName}.dll") if(NOT EXISTS "${import_path}") message(FATAL_ERROR "Missing ${import_path}. Run app/scripts/build_llama_windows.ps1 cuda=off vcpkgroot= first.") endif() if(NOT EXISTS "${dll_path}") message(FATAL_ERROR "Missing ${dll_path}. Run app/scripts/build_llama_windows.ps1 cuda=off vcpkgroot= to stage runtime DLLs.") endif() string(REPLACE "-" "_" imported_target "${libName}") add_library(${imported_target} SHARED IMPORTED) set_target_properties(${imported_target} PROPERTIES IMPORTED_IMPLIB "${import_path}" IMPORTED_LOCATION "${dll_path}" ) endforeach() set(MTMD_IMPORT "${PRECOMPILED_CPU_LIB_DIR}/mtmd.lib") set(MTMD_DLL "${PRECOMPILED_CPU_BIN_DIR}/mtmd.dll") if(EXISTS "${MTMD_IMPORT}" AND EXISTS "${MTMD_DLL}") add_library(mtmd SHARED IMPORTED) set_target_properties(mtmd PROPERTIES IMPORTED_IMPLIB "${MTMD_IMPORT}" IMPORTED_LOCATION "${MTMD_DLL}" ) target_compile_definitions(aifilesorter PRIVATE AI_FILE_SORTER_HAS_MTMD) set(_aifs_saved_required_libs "${CMAKE_REQUIRED_LIBRARIES}") set(CMAKE_REQUIRED_LIBRARIES "${MTMD_IMPORT}") check_cxx_source_compiles([[ extern "C" void mtmd_helper_set_progress_callback(void*, void*); int main() { mtmd_helper_set_progress_callback(0, 0); return 0; } ]] HAVE_MTMD_HELPER_SET_PROGRESS_CALLBACK) check_cxx_source_compiles([[ extern "C" void mtmd_helper_log_set(void*, void*); int main() { mtmd_helper_log_set(0, 0); return 0; } ]] HAVE_MTMD_HELPER_LOG_SET) set(CMAKE_REQUIRED_LIBRARIES "${_aifs_saved_required_libs}") unset(_aifs_saved_required_libs) if(HAVE_MTMD_HELPER_SET_PROGRESS_CALLBACK) target_compile_definitions(aifilesorter PRIVATE AI_FILE_SORTER_MTMD_PROGRESS_CALLBACK) endif() if(HAVE_MTMD_HELPER_LOG_SET) target_compile_definitions(aifilesorter PRIVATE AI_FILE_SORTER_MTMD_LOG_CALLBACK) endif() else() message(WARNING "Visual LLM support disabled: missing mtmd.lib/mtmd.dll under app/lib/precompiled/cpu. Run app/scripts/build_llama_windows.ps1 to stage mtmd.") endif() else() # Build llama.cpp from the included submodule for non-Windows platforms set(LLAMA_BUILD_COMMON ON CACHE BOOL "llama: build common utils library" FORCE) set(BUILD_SHARED_LIBS OFF CACHE BOOL "Build shared libs" FORCE) add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/include/external/llama.cpp" "${CMAKE_CURRENT_BINARY_DIR}/llama-build") get_directory_property(_llama_install_version DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/llama-build" DEFINITION LLAMA_INSTALL_VERSION) if (NOT _llama_install_version OR _llama_install_version STREQUAL "LLAMA_INSTALL_VERSION-NOTFOUND") set(_llama_install_version "0.0.0") endif() set(LLAMA_INSTALL_VERSION "${_llama_install_version}") add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/include/external/llama.cpp/tools/mtmd" "${CMAKE_CURRENT_BINARY_DIR}/mtmd-build") target_link_libraries(aifilesorter PRIVATE llama) target_link_libraries(aifilesorter PRIVATE mtmd) target_compile_definitions(aifilesorter PRIVATE AI_FILE_SORTER_HAS_MTMD) set(CMAKE_REQUIRED_INCLUDES "${CMAKE_CURRENT_SOURCE_DIR}/include/external/llama.cpp/tools/mtmd" "${CMAKE_CURRENT_SOURCE_DIR}/include/external/llama.cpp/include" "${CMAKE_CURRENT_SOURCE_DIR}/include/external/llama.cpp/ggml/include" ) check_symbol_exists(mtmd_helper_set_progress_callback "mtmd-helper.h" HAVE_MTMD_HELPER_SET_PROGRESS_CALLBACK) check_symbol_exists(mtmd_helper_log_set "mtmd-helper.h" HAVE_MTMD_HELPER_LOG_SET) set(CMAKE_REQUIRED_INCLUDES) if(HAVE_MTMD_HELPER_SET_PROGRESS_CALLBACK) target_compile_definitions(aifilesorter PRIVATE AI_FILE_SORTER_MTMD_PROGRESS_CALLBACK) endif() if(HAVE_MTMD_HELPER_LOG_SET) target_compile_definitions(aifilesorter PRIVATE AI_FILE_SORTER_MTMD_LOG_CALLBACK) endif() if(MSVC) target_compile_options(llama PRIVATE /Zc:char8_t-) endif() endif() # Link libraries target_link_libraries(aifilesorter PRIVATE Qt6::Widgets Qt6::Gui Qt6::Core CURL::libcurl OpenSSL::SSL OpenSSL::Crypto SQLite::SQLite3 JsonCpp::JsonCpp fmt::fmt spdlog::spdlog Intl::Intl llama # imported on Windows or built from submodule on other platforms ${MEDIAINFO_DEPS_LIBS} ${DOC_DEPS_LIBS} ) if(WIN32) target_link_libraries(aifilesorter PRIVATE ggml ggml_base ggml_cpu) if(TARGET mtmd) target_link_libraries(aifilesorter PRIVATE mtmd) endif() endif() if(_aifs_pdfium_ready) if(PDFIUM_RUNTIME AND EXISTS "${PDFIUM_RUNTIME}") add_custom_command(TARGET aifilesorter POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different "${PDFIUM_RUNTIME}" "$" ) endif() if(NOT WIN32) if(APPLE) set(_pdfium_rpath "@loader_path") else() set(_pdfium_rpath "$ORIGIN") endif() set_target_properties(aifilesorter PROPERTIES BUILD_RPATH "${_pdfium_rpath}" INSTALL_RPATH "${_pdfium_rpath}" ) unset(_pdfium_rpath) endif() endif() if(WIN32) set(STARTER_TARGET StartAiFileSorter) add_executable(${STARTER_TARGET} WIN32 "${CMAKE_CURRENT_SOURCE_DIR}/startapp_windows.cpp" ) aifs_apply_update_mode(${STARTER_TARGET}) target_include_directories(${STARTER_TARGET} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/include" ) target_link_libraries(${STARTER_TARGET} PRIVATE Qt6::Widgets Qt6::Gui Qt6::Core ) target_compile_definitions(${STARTER_TARGET} PRIVATE WIN32_LEAN_AND_MEAN NOMINMAX) endif() # On Windows, ensure Unicode and lean Windows headers in deps that need it if(WIN32) target_compile_definitions(aifilesorter PRIVATE WIN32_LEAN_AND_MEAN NOMINMAX) set(WIN_SYSTEM_LIBS wininet d3d11 dxgi dxguid d3d12 mpr userenv) if(CMAKE_SIZEOF_VOID_P EQUAL 8) set(_win_sdk_arch "x64") else() set(_win_sdk_arch "x86") endif() set(_win_sdk_lib_paths "") if(DEFINED ENV{WindowsSdkDir} AND DEFINED ENV{WindowsSDKLibVersion}) file(TO_CMAKE_PATH "$ENV{WindowsSdkDir}" _sdk_dir) file(TO_CMAKE_PATH "$ENV{WindowsSDKLibVersion}" _sdk_version_raw) string(REGEX REPLACE "/$" "" _sdk_version "${_sdk_version_raw}") set(_sdk_root "${_sdk_dir}Lib/${_sdk_version}") foreach(_subdir IN ITEMS um ucrt) set(_candidate "${_sdk_root}/${_subdir}/${_win_sdk_arch}") if(EXISTS "${_candidate}") list(APPEND _win_sdk_lib_paths "${_candidate}") endif() endforeach() endif() if(NOT _win_sdk_lib_paths AND DEFINED CMAKE_RC_COMPILER AND CMAKE_RC_COMPILER) get_filename_component(_rc_dir "${CMAKE_RC_COMPILER}" DIRECTORY) get_filename_component(_bin_version_dir "${_rc_dir}" DIRECTORY) get_filename_component(_bin_dir "${_bin_version_dir}" DIRECTORY) get_filename_component(_kits_root "${_bin_dir}" DIRECTORY) get_filename_component(_sdk_version "${_bin_version_dir}" NAME) if(_kits_root AND EXISTS "${_kits_root}/Lib/${_sdk_version}") set(_sdk_root "${_kits_root}/Lib/${_sdk_version}") foreach(_subdir IN ITEMS um ucrt) set(_candidate "${_sdk_root}/${_subdir}/${_win_sdk_arch}") if(EXISTS "${_candidate}") list(APPEND _win_sdk_lib_paths "${_candidate}") endif() endforeach() endif() endif() foreach(libName IN LISTS WIN_SYSTEM_LIBS) string(TOUPPER "${libName}" upperLib) set(varName "${upperLib}_LIBRARY") unset(${varName}) if(_win_sdk_lib_paths) find_library(${varName} NAMES ${libName} PATHS ${_win_sdk_lib_paths} NO_DEFAULT_PATH ) endif() if(NOT ${varName}) find_library(${varName} NAMES ${libName}) endif() if(NOT ${varName}) message(FATAL_ERROR "Required system library '${libName}' not found. Ensure the Windows SDK is installed.") endif() target_link_libraries(aifilesorter PRIVATE "${${varName}}") endforeach() endif() if(WIN32) find_program(POWERSHELL_EXECUTABLE NAMES pwsh pwsh.exe powershell powershell.exe) if(NOT POWERSHELL_EXECUTABLE) message(FATAL_ERROR "PowerShell is required to generate Windows resources") endif() set(APP_ICON_BASE "${CMAKE_CURRENT_SOURCE_DIR}/resources/images/icon_256x256.png") set(APP_ICON_ICO "${CMAKE_CURRENT_BINARY_DIR}/generated/app_icon.ico") add_custom_command(OUTPUT "${APP_ICON_ICO}" COMMAND "${POWERSHELL_EXECUTABLE}" -NoProfile -ExecutionPolicy Bypass -File "${CMAKE_CURRENT_SOURCE_DIR}/scripts/generate_icon.ps1" -BasePng "${APP_ICON_BASE}" -Ico "${APP_ICON_ICO}" DEPENDS "${APP_ICON_BASE}" "${CMAKE_CURRENT_SOURCE_DIR}/scripts/generate_icon.ps1" COMMENT "Generating Windows icon" VERBATIM ) set(APP_ICON_RC "${CMAKE_CURRENT_BINARY_DIR}/generated/app_icon.rc") file(TO_NATIVE_PATH "${APP_ICON_ICO}" APP_ICON_ICO_NATIVE_TEMP) string(REPLACE "\\" "\\\\" APP_ICON_ICO_NATIVE "${APP_ICON_ICO_NATIVE_TEMP}") set(APP_ICON_PATH "${APP_ICON_ICO_NATIVE}") configure_file( "${CMAKE_CURRENT_SOURCE_DIR}/resources/windows/app_icon.rc.in" "${APP_ICON_RC}" @ONLY ) set_source_files_properties("${APP_ICON_ICO}" PROPERTIES GENERATED TRUE) add_custom_target(app_icon_resource ALL DEPENDS "${APP_ICON_ICO}") add_dependencies(aifilesorter app_icon_resource) add_dependencies(aifilesorter app_icon_resource) if(WIN32) add_dependencies(${STARTER_TARGET} app_icon_resource) endif() target_sources(aifilesorter PRIVATE "${APP_ICON_RC}") target_sources(aifilesorter PRIVATE "${APP_ICON_RC}") if(WIN32) target_sources(${STARTER_TARGET} PRIVATE "${APP_ICON_RC}") endif() # Version info resource generated from app_version.hpp set(APP_VERSION_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/include/app_version.hpp") file(READ "${APP_VERSION_HEADER}" APP_VERSION_CONTENTS) string(REGEX MATCH "Version\\{([0-9]+),[ \t]*([0-9]+),[ \t]*([0-9]+)" _ "${APP_VERSION_CONTENTS}") if(CMAKE_MATCH_1) set(APP_VER_MAJOR "${CMAKE_MATCH_1}") set(APP_VER_MINOR "${CMAKE_MATCH_2}") set(APP_VER_PATCH "${CMAKE_MATCH_3}") else() set(APP_VER_MAJOR "0") set(APP_VER_MINOR "0") set(APP_VER_PATCH "0") endif() configure_file( "${CMAKE_CURRENT_SOURCE_DIR}/resources/windows/version.rc.in" "${CMAKE_CURRENT_BINARY_DIR}/generated/version.rc" @ONLY ) target_sources(aifilesorter PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/generated/version.rc") target_sources(${STARTER_TARGET} PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/generated/version.rc") set(PRECOMPILED_CPU_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/lib/precompiled/cpu") set(PRECOMPILED_CUDA_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/lib/precompiled/cuda") set(PRECOMPILED_VULKAN_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/lib/precompiled/vulkan") add_custom_command(TARGET aifilesorter POST_BUILD # COMMAND ${CMAKE_COMMAND} -E remove -f "$/openblas.dll" COMMAND ${CMAKE_COMMAND} -E make_directory "$/lib/ggml/wocuda" COMMAND ${CMAKE_COMMAND} -E make_directory "$/lib/ggml/wcuda" COMMAND ${CMAKE_COMMAND} -E make_directory "$/lib/ggml/wvulkan" COMMAND ${CMAKE_COMMAND} -E copy_directory "${PRECOMPILED_CPU_ROOT}" "$/lib/ggml/wocuda" COMMAND ${CMAKE_COMMAND} -E copy_directory "${PRECOMPILED_CUDA_ROOT}" "$/lib/ggml/wcuda" COMMAND ${CMAKE_COMMAND} -E copy_directory "${PRECOMPILED_VULKAN_ROOT}" "$/lib/ggml/wvulkan" ) # set(_precompiled_libopenblas "${PRECOMPILED_CPU_ROOT}/bin/libopenblas.dll") # if(EXISTS "${_precompiled_libopenblas}") # add_custom_command(TARGET aifilesorter POST_BUILD # COMMAND ${CMAKE_COMMAND} -E copy_if_different # "${_precompiled_libopenblas}" # "$/libopenblas.dll" # ) # else() # message(WARNING "Expected ${_precompiled_libopenblas} to exist. Run app/scripts/build_llama_windows.ps1 to stage GGML artifacts.") # endif() endif() if(AI_FILE_SORTER_BUILD_TESTS) include(CTest) set(_catch2_source_dir "${CMAKE_SOURCE_DIR}/../external/Catch2") if(EXISTS "${_catch2_source_dir}/CMakeLists.txt") add_subdirectory(${_catch2_source_dir} ${CMAKE_BINARY_DIR}/catch2-build) else() message(STATUS "Catch2 submodule not found, fetching via FetchContent") include(FetchContent) FetchContent_Declare( Catch2 GIT_REPOSITORY https://github.com/catchorg/Catch2.git GIT_TAG v3.5.2 ) FetchContent_MakeAvailable(Catch2) endif() function(aifs_stage_test_runtime target_name) if(WIN32) set(_aifs_test_runtime_dlls "") add_custom_command(TARGET ${target_name} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different $ $ COMMAND_EXPAND_LISTS ) if(VCPKG_TARGET_TRIPLET) set(_aifs_vcpkg_runtime_dir "${AIFS_VCPKG_INSTALLED_ROOT}/${VCPKG_TARGET_TRIPLET}/bin") if(EXISTS "${_aifs_vcpkg_runtime_dir}") file(GLOB _aifs_vcpkg_runtime_dlls "${_aifs_vcpkg_runtime_dir}/*.dll") list(APPEND _aifs_test_runtime_dlls ${_aifs_vcpkg_runtime_dlls}) endif() endif() if(EXISTS "${PRECOMPILED_CPU_ROOT}/bin") file(GLOB _aifs_precompiled_cpu_runtime_dlls "${PRECOMPILED_CPU_ROOT}/bin/*.dll") list(APPEND _aifs_test_runtime_dlls ${_aifs_precompiled_cpu_runtime_dlls}) endif() set(_aifs_mingw_runtime_search_paths "") if(DEFINED ENV{OPENBLAS_ROOT} AND NOT "$ENV{OPENBLAS_ROOT}" STREQUAL "") list(APPEND _aifs_mingw_runtime_search_paths "$ENV{OPENBLAS_ROOT}/bin") endif() list(APPEND _aifs_mingw_runtime_search_paths "C:/msys64/mingw64/bin") foreach(_aifs_mingw_runtime_name IN ITEMS libgomp-1.dll libgcc_s_seh-1.dll libgfortran-5.dll libwinpthread-1.dll libquadmath-0.dll) foreach(_aifs_runtime_path IN LISTS _aifs_mingw_runtime_search_paths) if(EXISTS "${_aifs_runtime_path}/${_aifs_mingw_runtime_name}") list(APPEND _aifs_test_runtime_dlls "${_aifs_runtime_path}/${_aifs_mingw_runtime_name}") break() endif() endforeach() endforeach() list(REMOVE_DUPLICATES _aifs_test_runtime_dlls) if(_aifs_test_runtime_dlls) add_custom_command(TARGET ${target_name} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different ${_aifs_test_runtime_dlls} $ COMMAND_EXPAND_LISTS ) endif() if(VCPKG_TARGET_TRIPLET) set(_aifs_qt_plugin_root "${AIFS_VCPKG_INSTALLED_ROOT}/${VCPKG_TARGET_TRIPLET}/Qt6/plugins") foreach(_aifs_qt_plugin_subdir IN ITEMS platforms styles imageformats) set(_aifs_qt_plugin_src_dir "${_aifs_qt_plugin_root}/${_aifs_qt_plugin_subdir}") if(EXISTS "${_aifs_qt_plugin_src_dir}") file(GLOB _aifs_qt_plugin_dlls "${_aifs_qt_plugin_src_dir}/*.dll") if(_aifs_qt_plugin_dlls) add_custom_command(TARGET ${target_name} POST_BUILD COMMAND ${CMAKE_COMMAND} -E make_directory "$/${_aifs_qt_plugin_subdir}" COMMAND ${CMAKE_COMMAND} -E copy_if_different ${_aifs_qt_plugin_dlls} "$/${_aifs_qt_plugin_subdir}" COMMAND_EXPAND_LISTS ) endif() endif() endforeach() endif() endif() if(_aifs_pdfium_ready AND PDFIUM_RUNTIME AND EXISTS "${PDFIUM_RUNTIME}") add_custom_command(TARGET ${target_name} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different "${PDFIUM_RUNTIME}" "$" ) endif() if(_aifs_pdfium_ready AND NOT WIN32) if(APPLE) set(_pdfium_rpath "@loader_path") else() set(_pdfium_rpath "$ORIGIN") endif() set_target_properties(${target_name} PROPERTIES BUILD_RPATH "${_pdfium_rpath}" INSTALL_RPATH "${_pdfium_rpath}" ) unset(_pdfium_rpath) endif() endfunction() add_executable(ai_file_sorter_tests ${APP_LIB_SOURCES} "${CMAKE_CURRENT_SOURCE_DIR}/../tests/unit/test_utils.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/../tests/unit/test_file_scanner.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/../tests/unit/test_local_llm_backend.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/../tests/unit/test_ggml_runtime_paths.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/../tests/unit/test_llm_downloader.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/../tests/unit/test_update_feed.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/../tests/unit/test_updater.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/../tests/unit/test_updater_build_modes.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/../tests/unit/test_llm_selection_dialog_visual.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/../tests/unit/test_main_app_translation.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/../tests/unit/test_main_app_image_options.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/../tests/unit/test_main_app_visual_fallback.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/../tests/unit/test_settings_image_options.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/../tests/unit/test_ui_translator.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/../tests/unit/test_categorization_dialog.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/../tests/unit/test_checkbox_matrix.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/../tests/unit/test_review_dialog_rename_gate.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/../tests/unit/test_cli_reporter.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/../tests/unit/test_support_prompt.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/../tests/unit/test_whitelist_and_prompt.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/../tests/unit/test_database_manager_rename_only.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/../tests/unit/test_cache_interactions.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/../tests/unit/test_image_rename_metadata_service.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/../tests/unit/test_llava_image_analyzer.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/../tests/unit/test_media_rename_metadata_service.cpp" ) target_include_directories(ai_file_sorter_tests PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/include" "${CMAKE_CURRENT_SOURCE_DIR}/include/llama" "${CMAKE_CURRENT_SOURCE_DIR}/../tests/unit" ${DOC_DEPS_INCLUDE_DIRS} ) target_link_libraries(ai_file_sorter_tests PRIVATE Catch2::Catch2WithMain Qt6::Core Qt6::Widgets CURL::libcurl OpenSSL::SSL OpenSSL::Crypto SQLite::SQLite3 JsonCpp::JsonCpp spdlog::spdlog fmt::fmt Intl::Intl llama ${MEDIAINFO_DEPS_LIBS} ${DOC_DEPS_LIBS} ) aifs_add_translation_resources(ai_file_sorter_tests) target_compile_definitions(ai_file_sorter_tests PRIVATE AI_FILE_SORTER_TEST_BUILD=1 WIN32_LEAN_AND_MEAN NOMINMAX) aifs_apply_update_mode(ai_file_sorter_tests) aifs_apply_expected_update_mode(ai_file_sorter_tests "${_aifs_effective_update_mode}") if(WIN32) target_link_libraries(ai_file_sorter_tests PRIVATE ggml ggml_base ggml_cpu) foreach(libName IN LISTS WIN_SYSTEM_LIBS) string(TOUPPER "${libName}" upperLib) set(varName "${upperLib}_LIBRARY") if(DEFINED ${varName} AND ${varName}) target_link_libraries(ai_file_sorter_tests PRIVATE "${${varName}}") else() target_link_libraries(ai_file_sorter_tests PRIVATE ${libName}) endif() endforeach() endif() aifs_stage_test_runtime(ai_file_sorter_tests) if(WIN32) set(AIFS_UPDATER_MODE_TEST_APP_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/lib/IniConfig.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/lib/Logger.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/lib/Settings.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/lib/UpdateArchiveExtractor.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/lib/UpdateFeed.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/lib/UpdateInstaller.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/lib/Updater.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/lib/Utils.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/lib/Version.cpp" ) function(aifs_add_updater_mode_test target_name update_mode) add_executable(${target_name} ${AIFS_UPDATER_MODE_TEST_APP_SOURCES} "${CMAKE_CURRENT_SOURCE_DIR}/../tests/unit/test_updater_build_modes.cpp" ) target_include_directories(${target_name} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/include" "${CMAKE_CURRENT_SOURCE_DIR}/../tests/unit" ${DOC_DEPS_INCLUDE_DIRS} ) target_link_libraries(${target_name} PRIVATE Catch2::Catch2WithMain Qt6::Core Qt6::Widgets CURL::libcurl OpenSSL::SSL OpenSSL::Crypto SQLite::SQLite3 JsonCpp::JsonCpp spdlog::spdlog fmt::fmt Intl::Intl ${DOC_DEPS_LIBS} ) target_compile_definitions(${target_name} PRIVATE AI_FILE_SORTER_TEST_BUILD=1 WIN32_LEAN_AND_MEAN NOMINMAX) foreach(libName IN LISTS WIN_SYSTEM_LIBS) string(TOUPPER "${libName}" upperLib) set(varName "${upperLib}_LIBRARY") if(DEFINED ${varName} AND ${varName}) target_link_libraries(${target_name} PRIVATE "${${varName}}") else() target_link_libraries(${target_name} PRIVATE ${libName}) endif() endforeach() aifs_apply_named_update_mode(${target_name} "${update_mode}") aifs_apply_expected_update_mode(${target_name} "${update_mode}") aifs_stage_test_runtime(${target_name}) endfunction() aifs_add_updater_mode_test(ai_file_sorter_updater_notify_only_tests "NOTIFY_ONLY") aifs_add_updater_mode_test(ai_file_sorter_updater_disabled_tests "DISABLED") endif() if(BUILD_TESTING) add_test(NAME ai_file_sorter_tests COMMAND ai_file_sorter_tests) if(WIN32) add_test(NAME ai_file_sorter_updater_notify_only_tests COMMAND ai_file_sorter_updater_notify_only_tests) add_test(NAME ai_file_sorter_updater_disabled_tests COMMAND ai_file_sorter_updater_disabled_tests) endif() endif() if(NOT WIN32) add_test( NAME integration_run_all COMMAND ${CMAKE_COMMAND} -E env bash ${CMAKE_SOURCE_DIR}/../tests/run_all_tests.sh WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/.. ) set_tests_properties(integration_run_all PROPERTIES PASS_REGULAR_EXPRESSION "All tests completed successfully." ) endif() endif() ================================================ FILE: app/Makefile ================================================ # Detect platform UNAME := $(shell uname | cut -d'-' -f1) UNAME_M := $(shell uname -m) BIN_DIR := ./bin OBJ_ROOT := ./obj OBJ_DIR := $(OBJ_ROOT) SRC_DIR := ./lib APP_NAME ?= AI File Sorter # Goals that should not require toolchain/dependency discovery. NON_BUILD_GOALS := clean NEEDS_BUILD_DEPS := 1 ifneq ($(strip $(MAKECMDGOALS)),) ifeq ($(strip $(filter-out $(NON_BUILD_GOALS),$(MAKECMDGOALS))),) NEEDS_BUILD_DEPS := 0 endif endif # Optional: build llama.cpp with multi-variant CPU backends on macOS. # Usage: make LLAMA_MULTI_VARIANT=1 LLAMA_MULTI_VARIANT ?= 0 GGML_PRECOMPILED_SUBDIR ?= precompiled ifeq ($(UNAME), Linux) PLATFORM := Linux CXXFLAGS += -DLINUX CXXFLAGS += -DAI_FILE_SORTER_HAS_MTMD TARGET := $(BIN_DIR)/aifilesorter-bin INSTALL_DIR := /usr/local/bin INSTALL_LIB_DIR := /usr/local/lib/aifilesorter LD_CONF_FILE := /etc/ld.so.conf.d/aifilesorter.conf # --- Qt6 setup --- PKG_CONFIG := $(shell command -v pkg-config 2>/dev/null) QT_PACKAGES := Qt6Widgets Qt6Gui Qt6Core QT_CXXFLAGS := QT_LDFLAGS := ifneq ($(strip $(PKG_CONFIG)),) QT_CXXFLAGS := $(shell $(PKG_CONFIG) --cflags $(QT_PACKAGES) 2>/dev/null) QT_LDFLAGS := $(shell $(PKG_CONFIG) --libs $(QT_PACKAGES) 2>/dev/null) endif ifeq ($(strip $(QT_CXXFLAGS)),) QT_INCLUDE_BASE ?= /usr/include/x86_64-linux-gnu/qt6 QT_LIB_BASE ?= /usr/lib/x86_64-linux-gnu CXXFLAGS += -I$(QT_INCLUDE_BASE) -I$(QT_INCLUDE_BASE)/QtCore -I$(QT_INCLUDE_BASE)/QtGui -I$(QT_INCLUDE_BASE)/QtWidgets LDFLAGS += -L$(QT_LIB_BASE) -lQt6Widgets -lQt6Gui -lQt6Core else CXXFLAGS += $(QT_CXXFLAGS) LDFLAGS += $(QT_LDFLAGS) endif # --- Other dependencies --- LDFLAGS += -lcurl -ljsoncpp -lsqlite3 -lcrypto -lfmt -lspdlog -lssl -lllama -lggml -lggml-base -lmtmd -lX11 -pthread LDFLAGS += -Wl,-rpath,'$$ORIGIN/../lib/precompiled/cpu/bin' -Wl,-rpath,'$$ORIGIN/../lib/precompiled' LDFLAGS += -Wl,-rpath-link=./lib/precompiled/cpu/bin -Wl,-rpath-link=./lib/precompiled else ifeq ($(UNAME), Darwin) MACOS_ARCH ?= $(UNAME_M) DEFAULT_BREW_PREFIX := $(shell if [ "$(MACOS_ARCH)" = "arm64" ]; then echo /opt/homebrew; else echo /usr/local; fi) ifeq ($(origin BREW_PREFIX),undefined) ifeq ($(MACOS_ARCH),x86_64) BREW_PREFIX := /usr/local else BREW_PREFIX := $(shell if command -v brew >/dev/null 2>&1; then brew --prefix; else echo $(DEFAULT_BREW_PREFIX); fi) endif endif QT_PREFIX := $(BREW_PREFIX)/opt/qt QTBASE_PREFIX := $(BREW_PREFIX)/opt/qtbase CURL_PREFIX := $(BREW_PREFIX)/opt/curl LIBFFI_PREFIX := $(BREW_PREFIX)/opt/libffi EXPAT_PREFIX := $(BREW_PREFIX)/opt/expat SDKROOT := $(shell xcrun --sdk macosx --show-sdk-path 2>/dev/null) MACOSX_DEPLOYMENT_TARGET ?= 11.0 HOMEBREW_OS_PKG_CONFIG_DIRS := $(shell if [ -d "$(BREW_PREFIX)/Library/Homebrew/os/mac/pkgconfig" ]; then find "$(BREW_PREFIX)/Library/Homebrew/os/mac/pkgconfig" -mindepth 1 -maxdepth 1 -type d | tr '\n' ':' | sed 's/:$$//'; fi) # Homebrew exposes system pkg-config metadata like libcurl.pc here; libmediainfo depends on it. MACOS_PKG_CONFIG_DIRS := $(BREW_PREFIX)/lib/pkgconfig:$(BREW_PREFIX)/share/pkgconfig:$(LIBFFI_PREFIX)/lib/pkgconfig:$(EXPAT_PREFIX)/lib/pkgconfig:$(QT_PREFIX)/lib/pkgconfig$(if $(strip $(HOMEBREW_OS_PKG_CONFIG_DIRS)),:$(HOMEBREW_OS_PKG_CONFIG_DIRS)) export MACOSX_DEPLOYMENT_TARGET PATH := $(QTBASE_PREFIX)/share/qt/libexec:$(QT_PREFIX)/bin:$(CURL_PREFIX)/bin:$(PATH) export PATH ifeq ($(MACOS_ARCH),x86_64) export PKG_CONFIG_PATH := $(MACOS_PKG_CONFIG_DIRS) export PKG_CONFIG_LIBDIR := $(MACOS_PKG_CONFIG_DIRS) CPPFLAGS := $(filter-out -I/opt/homebrew/%,$(CPPFLAGS)) LDFLAGS := $(filter-out -L/opt/homebrew/% -F/opt/homebrew/%,$(LDFLAGS)) else export PKG_CONFIG_PATH := $(MACOS_PKG_CONFIG_DIRS):$(PKG_CONFIG_PATH) export PKG_CONFIG_LIBDIR := $(MACOS_PKG_CONFIG_DIRS) endif export LDFLAGS += -L$(LIBFFI_PREFIX)/lib export CPPFLAGS += -I$(LIBFFI_PREFIX)/include PLATFORM := MacOS CXXFLAGS += -DMACOS -DENABLE_METAL -DGGML_USE_METAL -DAI_FILE_SORTER_HAS_MTMD -Wno-deprecated -Iinclude/llama -mmacosx-version-min=$(MACOSX_DEPLOYMENT_TARGET) ifneq ($(strip $(MACOS_ARCH)),) CXXFLAGS := $(filter-out -arch arm64 -arch x86_64,$(CXXFLAGS)) LDFLAGS := $(filter-out -arch arm64 -arch x86_64,$(LDFLAGS)) CXXFLAGS += -arch $(MACOS_ARCH) LDFLAGS += -arch $(MACOS_ARCH) endif ifneq ($(strip $(SDKROOT)),) export SDKROOT CXXFLAGS += -isysroot $(SDKROOT) -stdlib=libc++ -I$(SDKROOT)/usr/include/c++/v1 LDFLAGS += -isysroot $(SDKROOT) endif LDFLAGS += -mmacosx-version-min=$(MACOSX_DEPLOYMENT_TARGET) TARGET := $(BIN_DIR)/aifilesorter INSTALL_DIR := /usr/local/bin INSTALL_LIB_DIR := /usr/local/lib/aifilesorter SPDLOG_PATH := $(BREW_PREFIX)/include CXXFLAGS += -I$(SPDLOG_PATH) ifeq ($(origin PKG_CONFIG),undefined) ifeq ($(MACOS_ARCH),x86_64) ifneq ($(wildcard /usr/local/bin/pkg-config),) PKG_CONFIG := /usr/local/bin/pkg-config else PKG_CONFIG := $(shell command -v pkg-config 2>/dev/null) endif else PKG_CONFIG := $(shell command -v pkg-config 2>/dev/null) endif endif ifeq ($(strip $(PKG_CONFIG)),) ifeq ($(NEEDS_BUILD_DEPS),1) $(error pkg-config is required to locate Qt6 frameworks on macOS. Please install it (e.g. brew install pkg-config)) endif endif QT_PACKAGES := Qt6Widgets Qt6Gui Qt6Core QT_CXXFLAGS := $(shell PKG_CONFIG_PATH="$(PKG_CONFIG_PATH)" $(PKG_CONFIG) --cflags $(QT_PACKAGES)) QT_LDFLAGS := $(shell PKG_CONFIG_PATH="$(PKG_CONFIG_PATH)" $(PKG_CONFIG) --libs $(QT_PACKAGES)) ifeq ($(strip $(QT_CXXFLAGS)),) ifeq ($(NEEDS_BUILD_DEPS),1) $(error Could not retrieve Qt6 flags via pkg-config. Ensure Qt6 is installed (brew install qt) and PKG_CONFIG_PATH includes its pkgconfig directory.) endif endif ifeq ($(MACOS_ARCH),x86_64) ifneq ($(findstring /opt/homebrew,$(QT_CXXFLAGS) $(QT_LDFLAGS)),) ifeq ($(NEEDS_BUILD_DEPS),1) $(error x86_64 build resolved Qt flags from /opt/homebrew. Install x86_64 Qt under /usr/local (Intel Homebrew) or set BREW_PREFIX/PKG_CONFIG accordingly.) endif endif endif CXXFLAGS += $(QT_CXXFLAGS) LDFLAGS += $(QT_LDFLAGS) LDFLAGS += -lcurl -ljsoncpp -lsqlite3 -lcrypto -lfmt -lspdlog -lssl -lllama -lggml -lggml-base -lmtmd -lintl -pthread LDFLAGS += -framework Metal -framework Foundation LDFLAGS += -Wl,-rpath,@loader_path/lib -Wl,-rpath,@loader_path/../lib/$(GGML_PRECOMPILED_SUBDIR) BIN_SUBDIR := $(patsubst ./bin/%,%,$(BIN_DIR)) ifneq ($(BIN_SUBDIR),$(BIN_DIR)) ifneq ($(strip $(BIN_SUBDIR)),) LDFLAGS += -Wl,-rpath,@loader_path/../../lib -Wl,-rpath,@loader_path/../../lib/$(GGML_PRECOMPILED_SUBDIR) endif endif endif ifeq ($(UNAME), Darwin) ifneq ($(strip $(MACOS_ARCH)),) BIN_SUBDIR := $(patsubst ./bin/%,%,$(BIN_DIR)) OBJ_VARIANT := $(GGML_PRECOMPILED_SUBDIR) ifneq ($(BIN_SUBDIR),$(BIN_DIR)) ifneq ($(strip $(BIN_SUBDIR)),) OBJ_VARIANT := $(BIN_SUBDIR) endif endif OBJ_DIR := $(OBJ_ROOT)/$(MACOS_ARCH)/$(OBJ_VARIANT) endif endif # MediaInfo policy: # - Must come from package managers (apt/dnf/pacman/brew/vcpkg) # - Vendored submodules / checked-in binaries are rejected MEDIAINFO_REQUIRE ?= 1 MEDIAINFO_ALLOW_VENDORED ?= 0 MEDIAINFO_PKG ?= libmediainfo MEDIAINFO_CFLAGS := MEDIAINFO_LDFLAGS := ifeq ($(NEEDS_BUILD_DEPS),1) MEDIAINFO_BLOCKED_PATHS := ../external/MediaInfoLib ../external/libmediainfo ./lib/mediainfo ./include/MediaInfo ifneq ($(MEDIAINFO_ALLOW_VENDORED),1) ifneq ($(strip $(foreach p,$(MEDIAINFO_BLOCKED_PATHS),$(wildcard $(p)))),) $(error Vendored MediaInfo content detected ($(MEDIAINFO_BLOCKED_PATHS)). Use package-managed libmediainfo only.) endif endif ifeq ($(strip $(PKG_CONFIG)),) ifeq ($(MEDIAINFO_REQUIRE),1) $(error pkg-config is required to resolve package-managed libmediainfo. Install pkg-config and libmediainfo (apt/dnf/pacman/brew/vcpkg).) endif else MEDIAINFO_CFLAGS := $(shell PKG_CONFIG_PATH="$(PKG_CONFIG_PATH)" $(PKG_CONFIG) --cflags $(MEDIAINFO_PKG) 2>/dev/null) MEDIAINFO_LDFLAGS := $(shell PKG_CONFIG_PATH="$(PKG_CONFIG_PATH)" $(PKG_CONFIG) --libs $(MEDIAINFO_PKG) 2>/dev/null) endif ifeq ($(MEDIAINFO_REQUIRE),1) ifeq ($(strip $(MEDIAINFO_LDFLAGS)),) $(error libmediainfo not found via pkg-config. Install it through apt/dnf/pacman/brew/vcpkg. Vendored copies are not supported.) endif endif endif ifneq ($(strip $(MEDIAINFO_LDFLAGS)),) CXXFLAGS += -DAI_FILE_SORTER_USE_MEDIAINFOLIB $(MEDIAINFO_CFLAGS) LDFLAGS += $(MEDIAINFO_LDFLAGS) endif WRAPPED_BINARY := $(notdir $(TARGET)) # Compiler and flags ifeq ($(UNAME), Darwin) CXX := clang++ else CXX := g++ endif CXXFLAGS += -std=c++20 -Wall -O2 -fPIC '-DAI_FILE_SORTER_APP_NAME="$(APP_NAME)"' '-DAI_FILE_SORTER_GGML_SUBDIR="$(GGML_PRECOMPILED_SUBDIR)"' CXX_VERSION_INFO := $(shell $(CXX) --version 2>/dev/null) # Suppress GCC-only diagnostics; clang (macOS) does not support some of them ifneq (,$(findstring clang,$(CXX_VERSION_INFO))) CXXFLAGS += -Wno-array-bounds else CXXFLAGS += -Wno-array-bounds -Wno-stringop-overflow -Wno-stringop-overread endif INCLUDE_DIRS = -I./include -I./include/external/llama.cpp/include -I./include/external/llama.cpp/ggml/include -I./include/external/llama.cpp/tools/mtmd LIB_DIRS = ifeq ($(UNAME), Linux) LIB_DIRS += -L./lib/precompiled/cpu/bin -L./lib/precompiled else LIB_DIRS += -L./lib/$(GGML_PRECOMPILED_SUBDIR) endif ifeq ($(UNAME), Darwin) LIB_DIRS += -L$(BREW_PREFIX)/lib endif # --- Vendored document analysis dependencies --- DOC_DEPS_DIR := ../external LIBZIP_DIR := $(DOC_DEPS_DIR)/libzip PUGIXML_DIR := $(DOC_DEPS_DIR)/pugixml PDFIUM_DIR := $(DOC_DEPS_DIR)/pdfium LIBZIP_CMAKE := $(LIBZIP_DIR)/CMakeLists.txt LIBZIP_BUILD_DIR := $(LIBZIP_DIR)/build LIBZIP_LIB := $(LIBZIP_BUILD_DIR)/lib/libzip.a LIBZIP_CONF := $(LIBZIP_BUILD_DIR)/zipconf.h LIBZIP_CMAKE_ARGS := ifeq ($(UNAME), Darwin) ifneq ($(strip $(MACOS_ARCH)),) LIBZIP_BUILD_DIR := $(LIBZIP_DIR)/build-$(MACOS_ARCH) LIBZIP_LIB := $(LIBZIP_BUILD_DIR)/lib/libzip.a LIBZIP_CMAKE_ARGS += -DCMAKE_OSX_ARCHITECTURES=$(MACOS_ARCH) endif endif PUGIXML_HDR := $(PUGIXML_DIR)/src/pugixml.hpp PDFIUM_PLATFORM_DIR := PDFIUM_INC := PDFIUM_LIB := PDFIUM_STAGED_LIB := PDFIUM_STAGED_STAMP := ifeq ($(UNAME), Linux) PDFIUM_PLATFORM_DIR := $(PDFIUM_DIR)/linux-x64 PDFIUM_INC := $(PDFIUM_PLATFORM_DIR)/include PDFIUM_LIB := $(PDFIUM_PLATFORM_DIR)/lib/libpdfium.so PDFIUM_STAGED_LIB := ./lib/$(GGML_PRECOMPILED_SUBDIR)/libpdfium.so PDFIUM_STAGED_STAMP := $(PDFIUM_STAGED_LIB).ready endif ifeq ($(UNAME), Darwin) PDFIUM_PLATFORM_DIR := $(PDFIUM_DIR)/macos-arm64 ifeq ($(MACOS_ARCH),x86_64) PDFIUM_PLATFORM_DIR := $(PDFIUM_DIR)/macos-x64 endif PDFIUM_INC := $(PDFIUM_PLATFORM_DIR)/include PDFIUM_LIB := $(PDFIUM_PLATFORM_DIR)/lib/libpdfium.dylib PDFIUM_STAGED_LIB := ./lib/$(GGML_PRECOMPILED_SUBDIR)/libpdfium.dylib PDFIUM_STAGED_STAMP := $(PDFIUM_STAGED_LIB).ready endif DOC_LIBS := DOC_DEPS_HEADERS := DOC_RUNTIME_DEPS := ifneq ($(wildcard $(PUGIXML_HDR)),) CXXFLAGS += -DPUGIXML_NO_EXCEPTIONS CXXFLAGS += -DAI_FILE_SORTER_USE_PUGIXML INCLUDE_DIRS += -I$(PUGIXML_DIR)/src endif ifneq ($(wildcard $(LIBZIP_CMAKE)),) CXXFLAGS += -DAI_FILE_SORTER_USE_LIBZIP INCLUDE_DIRS += -I$(LIBZIP_DIR)/lib -I$(LIBZIP_BUILD_DIR) LDFLAGS += -lz DOC_LIBS += $(LIBZIP_LIB) DOC_DEPS_HEADERS += $(LIBZIP_CONF) endif ifneq ($(wildcard $(PDFIUM_LIB)),) CXXFLAGS += -DAI_FILE_SORTER_USE_PDFIUM INCLUDE_DIRS += -I$(PDFIUM_INC) DOC_LIBS += $(PDFIUM_STAGED_LIB) DOC_RUNTIME_DEPS += $(PDFIUM_STAGED_STAMP) endif # Enable mtmd progress callback only when the linked libmtmd provides it. MTMD_PROGRESS_CALLBACK ?= auto MTMD_LIB_CANDIDATES := ifeq ($(UNAME), Linux) MTMD_LIB_CANDIDATES := ./lib/precompiled/cpu/bin/libmtmd.so ./lib/precompiled/libmtmd.so endif ifeq ($(UNAME), Darwin) MTMD_LIB_CANDIDATES := ./lib/$(GGML_PRECOMPILED_SUBDIR)/libmtmd.dylib $(BREW_PREFIX)/lib/libmtmd.dylib endif ifeq ($(MTMD_PROGRESS_CALLBACK),auto) MTMD_PROGRESS_CALLBACK := $(shell \ if command -v nm >/dev/null 2>&1; then \ for lib in $(MTMD_LIB_CANDIDATES); do \ if [ -e "$$lib" ] && nm -D --defined-only "$$lib" 2>/dev/null | grep -q "mtmd_helper_set_progress_callback"; then \ echo 1; exit 0; \ fi; \ if [ -e "$$lib" ] && nm -g "$$lib" 2>/dev/null | grep -q "[Tt] _mtmd_helper_set_progress_callback"; then \ echo 1; exit 0; \ fi; \ done; \ elif command -v objdump >/dev/null 2>&1; then \ for lib in $(MTMD_LIB_CANDIDATES); do \ if [ -e "$$lib" ] && objdump -T "$$lib" 2>/dev/null | grep -q "mtmd_helper_set_progress_callback"; then \ echo 1; exit 0; \ fi; \ done; \ fi; \ echo 0) endif ifeq ($(MTMD_PROGRESS_CALLBACK),1) CXXFLAGS += -DAI_FILE_SORTER_MTMD_PROGRESS_CALLBACK else CXXFLAGS += -UAI_FILE_SORTER_MTMD_PROGRESS_CALLBACK endif # Enable mtmd log callback only when the linked libmtmd provides it. MTMD_LOG_CALLBACK ?= auto ifeq ($(MTMD_LOG_CALLBACK),auto) MTMD_LOG_CALLBACK := $(shell \ if command -v nm >/dev/null 2>&1; then \ for lib in $(MTMD_LIB_CANDIDATES); do \ if [ -e "$$lib" ] && nm -D --defined-only "$$lib" 2>/dev/null | grep -q "mtmd_helper_log_set"; then \ echo 1; exit 0; \ fi; \ if [ -e "$$lib" ] && nm -g "$$lib" 2>/dev/null | grep -q "[Tt] _mtmd_helper_log_set"; then \ echo 1; exit 0; \ fi; \ done; \ elif command -v objdump >/dev/null 2>&1; then \ for lib in $(MTMD_LIB_CANDIDATES); do \ if [ -e "$$lib" ] && objdump -T "$$lib" 2>/dev/null | grep -q "mtmd_helper_log_set"; then \ echo 1; exit 0; \ fi; \ done; \ fi; \ echo 0) endif ifeq ($(MTMD_LOG_CALLBACK),1) CXXFLAGS += -DAI_FILE_SORTER_MTMD_LOG_CALLBACK else CXXFLAGS += -UAI_FILE_SORTER_MTMD_LOG_CALLBACK endif QRC_FILE := resources/app.qrc QRC_CPP := $(OBJ_DIR)/qrc_app.cpp QRC_OBJ := $(OBJ_DIR)/qrc_app.o QRC_DIR := $(dir $(QRC_FILE)) QRC_RESOURCES := $(shell sed -n -E 's|.*([^<]*).*|\1|p' $(QRC_FILE)) QRC_RESOURCES := $(addprefix $(QRC_DIR),$(QRC_RESOURCES)) MAKEFILE_SELF := $(lastword $(MAKEFILE_LIST)) TS_DIR := resources/i18n TS_FILES := \ $(TS_DIR)/aifilesorter_fr.ts \ $(TS_DIR)/aifilesorter_de.ts \ $(TS_DIR)/aifilesorter_it.ts \ $(TS_DIR)/aifilesorter_es.ts \ $(TS_DIR)/aifilesorter_nl.ts \ $(TS_DIR)/aifilesorter_tr.ts \ $(TS_DIR)/aifilesorter_ko.ts QM_DIR := $(OBJ_DIR)/i18n QM_FILES := $(patsubst $(TS_DIR)/%.ts,$(QM_DIR)/%.qm,$(TS_FILES)) TRANSLATIONS_QRC := $(OBJ_DIR)/translations.qrc TRANSLATIONS_QRC_CPP := $(OBJ_DIR)/qrc_translations.cpp TRANSLATIONS_QRC_OBJ := $(OBJ_DIR)/qrc_translations.o QMAKE6 := $(shell \ if command -v qmake6 >/dev/null 2>&1; then \ command -v qmake6; \ elif [ -x /usr/lib/qt6/bin/qmake6 ]; then \ printf '%s\n' /usr/lib/qt6/bin/qmake6; \ fi) QTPATHS6 := $(shell \ if command -v qtpaths6 >/dev/null 2>&1; then \ command -v qtpaths6; \ elif [ -x /usr/lib/qt6/bin/qtpaths6 ]; then \ printf '%s\n' /usr/lib/qt6/bin/qtpaths6; \ fi) ifndef RCC RCC := $(shell command -v qt6-rcc 2>/dev/null) ifeq ($(strip $(RCC)),) RCC := $(wildcard /usr/lib/qt6/libexec/rcc) endif ifeq ($(strip $(RCC)),) RCC := $(shell command -v rcc 2>/dev/null) endif ifeq ($(strip $(RCC)),) RCC := $(wildcard /opt/homebrew/opt/qt/bin/qt6-rcc) endif ifeq ($(strip $(RCC)),) RCC := $(wildcard /usr/lib/qt6/libexec/rcc) endif ifeq ($(strip $(RCC)),) RCC := $(wildcard /opt/homebrew/opt/qtbase/share/qt/libexec/rcc) endif ifeq ($(strip $(RCC)),) RCC := $(wildcard /usr/local/opt/qtbase/share/qt/libexec/rcc) endif endif ifeq ($(strip $(RCC)),) ifeq ($(NEEDS_BUILD_DEPS),1) $(error Could not find Qt resource compiler (qt6-rcc or rcc)) endif endif ifndef LRELEASE LRELEASE := $(shell \ for candidate in lrelease6 lrelease-qt6; do \ if command -v "$$candidate" >/dev/null 2>&1; then \ command -v "$$candidate"; \ exit 0; \ fi; \ done; \ if [ -n "$(QTPATHS6)" ]; then \ for qt_host_dir in "$$($(QTPATHS6) --query QT_HOST_LIBEXECS 2>/dev/null)" "$$($(QTPATHS6) --query QT_HOST_BINS 2>/dev/null)"; do \ if [ -n "$$qt_host_dir" ] && [ -x "$$qt_host_dir/lrelease" ]; then \ printf '%s\n' "$$qt_host_dir/lrelease"; \ exit 0; \ fi; \ done; \ fi; \ if [ -n "$(QMAKE6)" ]; then \ for qt_host_dir in "$$($(QMAKE6) -query QT_HOST_LIBEXECS 2>/dev/null)" "$$($(QMAKE6) -query QT_HOST_BINS 2>/dev/null)" "$$($(QMAKE6) -query QT_INSTALL_BINS 2>/dev/null)"; do \ if [ -n "$$qt_host_dir" ] && [ -x "$$qt_host_dir/lrelease" ]; then \ printf '%s\n' "$$qt_host_dir/lrelease"; \ exit 0; \ fi; \ done; \ fi; \ for candidate in \ /usr/lib/qt6/libexec/lrelease \ /usr/lib/qt6/bin/lrelease \ /opt/homebrew/bin/lrelease \ /opt/homebrew/opt/qt/share/qt/libexec/lrelease \ /opt/homebrew/opt/qtbase/share/qt/libexec/lrelease \ /usr/local/opt/qtbase/share/qt/libexec/lrelease; do \ if [ -x "$$candidate" ]; then \ printf '%s\n' "$$candidate"; \ exit 0; \ fi; \ done; \ if command -v lrelease >/dev/null 2>&1; then \ candidate="$$(command -v lrelease)"; \ if "$$candidate" -version 2>&1 | grep -Eq 'Qt[^0-9]*6|version 6'; then \ printf '%s\n' "$$candidate"; \ fi; \ fi) endif ifeq ($(strip $(LRELEASE)),) ifeq ($(NEEDS_BUILD_DEPS),1) $(error Could not find a Qt 6 translation compiler (install qt6-l10n-tools / qt6-tools-dev-tools, or set LRELEASE=/path/to/qt6/lrelease)) endif endif # Source files SRCS = main.cpp $(wildcard $(SRC_DIR)/*.cpp) OBJS = $(patsubst %.cpp, $(OBJ_DIR)/%.o, $(notdir $(SRCS))) DEPS = $(OBJS:.o=.d) $(QRC_OBJ:.o=.d) $(TRANSLATIONS_QRC_OBJ:.o=.d) BUILD_CONFIG_STAMP := $(OBJ_DIR)/.build-config PRECOMPILED_LLAMA := ifeq ($(UNAME), Darwin) ifneq ($(LLAMA_MULTI_VARIANT),0) PRECOMPILED_LLAMA := precompiled_llama endif endif .PHONY: all clean install uninstall doc_runtime_libs precompiled_llama MACOS_LLAMA_M1 MACOS_LLAMA_M2 MACOS_LLAMA_INTEL # Main rules all: $(PRECOMPILED_LLAMA) doc_runtime_libs $(TARGET) @printf "\nFinished building AI File Sorter for %s\n" "$(PLATFORM)" $(TARGET): $(OBJS) $(QRC_OBJ) $(TRANSLATIONS_QRC_OBJ) $(DOC_LIBS) | doc_runtime_libs $(DOC_RUNTIME_DEPS) mkdir -p $(BIN_DIR) $(CXX) $(CXXFLAGS) -o $@ $^ $(LIB_DIRS) $(LDFLAGS) ifeq ($(PLATFORM), Linux) @$(MAKE) create_run_wrapper endif $(BUILD_CONFIG_STAMP): Makefile mkdir -p $(OBJ_DIR) @tmp="$(BUILD_CONFIG_STAMP).tmp.$$"; \ printf '%s\n' \ 'CXX=$(CXX)' \ 'CXXFLAGS=$(CXXFLAGS)' \ 'INCLUDE_DIRS=$(INCLUDE_DIRS)' \ 'APP_NAME=$(APP_NAME)' \ 'GGML_PRECOMPILED_SUBDIR=$(GGML_PRECOMPILED_SUBDIR)' \ 'MACOS_ARCH=$(MACOS_ARCH)' \ 'BIN_DIR=$(BIN_DIR)' \ > "$$tmp"; \ if [ ! -f "$@" ] || ! cmp -s "$$tmp" "$@"; then \ mv "$$tmp" "$@"; \ else \ rm -f "$$tmp"; \ fi $(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp $(DOC_DEPS_HEADERS) $(BUILD_CONFIG_STAMP) mkdir -p $(OBJ_DIR) $(CXX) $(CXXFLAGS) $(INCLUDE_DIRS) -MMD -MP -MF $(@:.o=.d) -c $< -o $@ $(LIBZIP_CONF): $(LIBZIP_LIB) $(LIBZIP_LIB): @echo "Building libzip (vendored)..." mkdir -p $(LIBZIP_BUILD_DIR) LDFLAGS= cmake -S $(LIBZIP_DIR) -B $(LIBZIP_BUILD_DIR) \ $(LIBZIP_CMAKE_ARGS) \ -DCMAKE_EXE_LINKER_FLAGS= \ -DCMAKE_SHARED_LINKER_FLAGS= \ -DCMAKE_MODULE_LINKER_FLAGS= \ -DBUILD_SHARED_LIBS=OFF \ -DENABLE_BZIP2=OFF \ -DENABLE_LZMA=OFF \ -DENABLE_ZSTD=OFF \ -DENABLE_OPENSSL=OFF \ -DENABLE_GNUTLS=OFF \ -DENABLE_MBEDTLS=OFF \ -DENABLE_COMMONCRYPTO=OFF \ -DENABLE_WINDOWS_CRYPTO=OFF LDFLAGS= cmake --build $(LIBZIP_BUILD_DIR) doc_runtime_libs: ifneq ($(wildcard $(PDFIUM_LIB)),) $(PDFIUM_STAGED_LIB): $(PDFIUM_LIB) @echo "Staging PDFium runtime library..." mkdir -p $(dir $(PDFIUM_STAGED_LIB)) cp $(PDFIUM_LIB) $(PDFIUM_STAGED_LIB) ifeq ($(UNAME), Darwin) chmod u+w $(PDFIUM_STAGED_LIB) 2>/dev/null || true install_name_tool -id @rpath/libpdfium.dylib $(PDFIUM_STAGED_LIB) endif $(PDFIUM_STAGED_STAMP): $(PDFIUM_STAGED_LIB) touch $@ doc_runtime_libs: $(PDFIUM_STAGED_STAMP) endif precompiled_llama: ifeq ($(UNAME), Darwin) @echo "Checking llama.cpp precompiled libraries (multi-variant=$(LLAMA_MULTI_VARIANT))..." @if [ -f "./lib/$(GGML_PRECOMPILED_SUBDIR)/libllama.dylib" ]; then \ echo "Using existing precompiled libs in ./lib/$(GGML_PRECOMPILED_SUBDIR)"; \ else \ echo "Building llama.cpp precompiled libraries (multi-variant=$(LLAMA_MULTI_VARIANT))..."; \ LLAMA_MACOS_MULTI_VARIANT=$(LLAMA_MULTI_VARIANT) LLAMA_PRECOMPILED_DIR=./lib/$(GGML_PRECOMPILED_SUBDIR) ./scripts/build_llama_macos.sh; \ fi else @echo "precompiled_llama is only supported on macOS." endif MACOS_LLAMA_M1: ifeq ($(UNAME), Darwin) @echo "Checking llama.cpp for M1-safe multi-variant CPU backends..." @if [ -f "./lib/precompiled-m1/libllama.dylib" ]; then \ echo "Using existing precompiled libs in ./lib/precompiled-m1"; \ else \ echo "Building llama.cpp for M1-safe multi-variant CPU backends..."; \ LLAMA_MACOS_MULTI_VARIANT=1 LLAMA_PRECOMPILED_DIR=./lib/precompiled-m1 ./scripts/build_llama_macos.sh; \ fi $(MAKE) LLAMA_MULTI_VARIANT=0 GGML_PRECOMPILED_SUBDIR=precompiled-m1 APP_NAME="AI File Sorter for Mac M1" BIN_DIR=./bin/m1 all else @echo "MACOS_LLAMA_M1 is only supported on macOS." endif MACOS_LLAMA_M2: ifeq ($(UNAME), Darwin) @echo "Checking llama.cpp for native (fast) Apple Silicon backends..." @if [ -f "./lib/precompiled-m2/libllama.dylib" ]; then \ echo "Using existing precompiled libs in ./lib/precompiled-m2"; \ else \ echo "Building llama.cpp for native (fast) Apple Silicon backends..."; \ LLAMA_MACOS_MULTI_VARIANT=0 LLAMA_PRECOMPILED_DIR=./lib/precompiled-m2 ./scripts/build_llama_macos.sh; \ fi $(MAKE) LLAMA_MULTI_VARIANT=0 GGML_PRECOMPILED_SUBDIR=precompiled-m2 APP_NAME="AI File Sorter for Mac M2-M5" BIN_DIR=./bin/m2 all else @echo "MACOS_LLAMA_M2 is only supported on macOS." endif MACOS_LLAMA_INTEL: ifeq ($(UNAME), Darwin) @echo "Checking llama.cpp for Intel (x86_64) macOS backends..." @if [ -f "./lib/precompiled-intel/libllama.dylib" ]; then \ echo "Using existing precompiled libs in ./lib/precompiled-intel"; \ else \ echo "Building llama.cpp for Intel (x86_64) macOS backends..."; \ LLAMA_MACOS_ARCH=x86_64 LLAMA_MACOS_ENABLE_METAL=1 LLAMA_MACOS_MULTI_VARIANT=0 LLAMA_PRECOMPILED_DIR=./lib/precompiled-intel ./scripts/build_llama_macos.sh; \ fi $(MAKE) LLAMA_MULTI_VARIANT=0 GGML_PRECOMPILED_SUBDIR=precompiled-intel APP_NAME="AI File Sorter for Mac Intel" BIN_DIR=./bin/intel MACOS_ARCH=x86_64 all else @echo "MACOS_LLAMA_INTEL is only supported on macOS." endif $(OBJ_DIR)/main.o: main.cpp $(DOC_DEPS_HEADERS) $(BUILD_CONFIG_STAMP) mkdir -p $(OBJ_DIR) $(CXX) $(CXXFLAGS) $(INCLUDE_DIRS) -MMD -MP -MF $(@:.o=.d) -c $< -o $@ $(QRC_CPP): $(QRC_FILE) $(QRC_RESOURCES) $(MAKEFILE_SELF) mkdir -p $(OBJ_DIR) $(RCC) -name app -o $@ $< $(QRC_OBJ): $(QRC_CPP) $(DOC_DEPS_HEADERS) $(BUILD_CONFIG_STAMP) $(CXX) $(CXXFLAGS) $(INCLUDE_DIRS) -MMD -MP -MF $(@:.o=.d) -c $< -o $@ $(QM_DIR)/%.qm: $(TS_DIR)/%.ts mkdir -p $(dir $@) $(LRELEASE) $< -qm $@ $(TRANSLATIONS_QRC): $(QM_FILES) mkdir -p $(OBJ_DIR) @tmp="$@.tmp"; \ printf '%s\n' '' ' ' > "$$tmp"; \ for qm in $(QM_FILES); do \ printf ' i18n/%s\n' "$$(basename "$$qm")" "$$(basename "$$qm")" >> "$$tmp"; \ done; \ printf '%s\n' ' ' '' >> "$$tmp"; \ mv "$$tmp" "$@" $(TRANSLATIONS_QRC_CPP): $(TRANSLATIONS_QRC) $(QM_FILES) $(MAKEFILE_SELF) mkdir -p $(OBJ_DIR) $(RCC) -name translations -o $@ $< $(TRANSLATIONS_QRC_OBJ): $(TRANSLATIONS_QRC_CPP) $(DOC_DEPS_HEADERS) $(BUILD_CONFIG_STAMP) $(CXX) $(CXXFLAGS) $(INCLUDE_DIRS) -MMD -MP -MF $(@:.o=.d) -c $< -o $@ clean: rm -rf $(OBJ_ROOT) $(BIN_DIR) create_run_wrapper: @mkdir -p $(BIN_DIR) @python3 scripts/gen_run_wrapper.py \ --mode dev \ --binary '$(WRAPPED_BINARY)' \ --output '$(BIN_DIR)/run_aifilesorter.sh' @chmod 755 $(BIN_DIR)/run_aifilesorter.sh install: $(TARGET) ifeq ($(PLATFORM), Linux) @echo "Installing runtime payload into $(INSTALL_LIB_DIR)..." mkdir -p $(INSTALL_LIB_DIR)/bin mkdir -p $(INSTALL_LIB_DIR)/lib cp $(TARGET) $(INSTALL_LIB_DIR)/bin/$(WRAPPED_BINARY) rm -rf $(INSTALL_LIB_DIR)/lib/$(GGML_PRECOMPILED_SUBDIR) cp -a lib/$(GGML_PRECOMPILED_SUBDIR) $(INSTALL_LIB_DIR)/lib/ if [ -f ../external/pdfium/linux-x64/lib/libpdfium.so ]; then \ cp ../external/pdfium/linux-x64/lib/libpdfium.so $(INSTALL_LIB_DIR)/lib/$(GGML_PRECOMPILED_SUBDIR)/; \ fi if [ -f resources/certs/cacert.pem ]; then \ mkdir -p $(INSTALL_LIB_DIR)/certs; \ cp resources/certs/cacert.pem $(INSTALL_LIB_DIR)/certs/cacert.pem; \ fi @echo "Installing launcher script to $(INSTALL_DIR)..." mkdir -p $(INSTALL_DIR) @python3 scripts/gen_run_wrapper.py \ --mode install \ --install-app-dir '$(INSTALL_LIB_DIR)' \ --binary '$(WRAPPED_BINARY)' \ --output '$(INSTALL_DIR)/run_aifilesorter.sh' chmod 755 $(INSTALL_DIR)/run_aifilesorter.sh ln -sf $(INSTALL_DIR)/run_aifilesorter.sh $(INSTALL_DIR)/aifilesorter @echo "Installation complete." else ifeq ($(PLATFORM), MacOS) @echo "Installing binary to $(INSTALL_DIR)..." mkdir -p $(INSTALL_DIR) cp $(TARGET) $(INSTALL_DIR)/aifilesorter @echo "Installing libraries to $(INSTALL_LIB_DIR)..." mkdir -p $(INSTALL_LIB_DIR) cp lib/$(GGML_PRECOMPILED_SUBDIR)/libggml-base.dylib $(INSTALL_LIB_DIR) cp lib/$(GGML_PRECOMPILED_SUBDIR)/libggml-blas.dylib $(INSTALL_LIB_DIR) cp lib/$(GGML_PRECOMPILED_SUBDIR)/libggml-cpu.dylib $(INSTALL_LIB_DIR) cp lib/$(GGML_PRECOMPILED_SUBDIR)/libggml-metal.dylib $(INSTALL_LIB_DIR) cp lib/$(GGML_PRECOMPILED_SUBDIR)/libggml.dylib $(INSTALL_LIB_DIR) cp lib/$(GGML_PRECOMPILED_SUBDIR)/libmtmd.dylib $(INSTALL_LIB_DIR) cp lib/$(GGML_PRECOMPILED_SUBDIR)/libllama.dylib $(INSTALL_LIB_DIR) if [ -n "$(PDFIUM_LIB)" ] && [ -f "$(PDFIUM_LIB)" ]; then \ cp "$(PDFIUM_LIB)" $(INSTALL_LIB_DIR); \ fi install_name_tool -add_rpath $(INSTALL_LIB_DIR) $(INSTALL_DIR)/aifilesorter @echo "macOS installation complete." endif uninstall: ifeq ($(PLATFORM), Linux) @echo "Uninstalling aifilesorter binary and libraries..." @echo "Removing binary from /usr/local/bin..." rm -f /usr/local/bin/aifilesorter @echo "Removing libraries from /usr/local/lib/aifilesorter..." rm -rf /usr/local/lib/aifilesorter @echo "Removing ld config file..." rm -f /etc/ld.so.conf.d/aifilesorter.conf @echo "Running ldconfig..." ldconfig @echo "Core uninstallation complete." @bash -c 'read -p "Do you also want to delete the downloaded local LLM models in ~/.local/share/aifilesorter/llms/? [y/N] " ans; \ if [ "$$ans" = "y" ] || [ "$$ans" = "Y" ]; then \ echo "Deleting ~/.local/share/aifilesorter/llms/..."; \ rm -rf "$$HOME/.local/share/aifilesorter/llms"; \ else \ echo "Keeping downloaded models."; \ fi' else ifeq ($(PLATFORM), MacOS) @echo "Uninstalling aifilesorter binary and libraries on macOS..." @echo "Removing binary from $(INSTALL_DIR)..." rm -f $(INSTALL_DIR)/aifilesorter @echo "Removing installed libraries..." rm -rf $(INSTALL_LIB_DIR) @echo "Core uninstallation complete." @read -p "Do you also want to delete the downloaded local LLM models in ~/Library/Application\ Support/aifilesorter/llms/? [y/N] " ans; \ if [ "$$ans" = "y" ] || [ "$$ans" = "Y" ]; then \ echo "Deleting ~/Library/Application Support/aifilesorter/llms/..."; \ rm -rf "$$HOME/Library/Application Support/aifilesorter/llms"; \ else \ echo "Keeping downloaded models."; \ fi endif -include $(DEPS) ================================================ FILE: app/build_windows.ps1 ================================================ param( [string]$VcpkgRoot, [ValidateSet("Debug", "Release")] [string]$Configuration = "Release", [switch]$Clean, [string]$Generator, [switch]$SkipDeploy, [switch]$BuildTests, [switch]$RunTests, [ValidateRange(1, 512)] [int]$Parallel = [System.Environment]::ProcessorCount, [ValidateSet("Standard", "MsStore", "Standalone")] [string[]]$Variants = @("Standard", "MsStore", "Standalone") ) $ErrorActionPreference = "Stop" $scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Definition $appDir = $scriptDir $llamaDir = Join-Path $appDir "include/external/llama.cpp" $legacySharedVcpkgInstalledDir = Join-Path $appDir "build-windows\\vcpkg_installed" $dedicatedSharedVcpkgInstalledDir = Join-Path $appDir "build-windows-vcpkg_installed" $sharedVcpkgInstalledDir = if (Test-Path $legacySharedVcpkgInstalledDir) { $legacySharedVcpkgInstalledDir } else { $dedicatedSharedVcpkgInstalledDir } $variantDefinitions = @{ Standard = [pscustomobject]@{ Name = "Standard" BuildDir = (Join-Path $appDir "build-windows") UpdateMode = "AUTO_INSTALL" Description = "Auto-install updates" } MsStore = [pscustomobject]@{ Name = "MsStore" BuildDir = (Join-Path $appDir "build-windows-store") UpdateMode = "DISABLED" Description = "No update checks" } Standalone = [pscustomobject]@{ Name = "Standalone" BuildDir = (Join-Path $appDir "build-windows-standalone") UpdateMode = "NOTIFY_ONLY" Description = "Notification-only updates" } } function Resolve-VcpkgRootFromPath { param([string]$Path) if (-not $Path) { return $null } try { $candidate = (Resolve-Path $Path -ErrorAction Stop).Path } catch { return $null } if ((Get-Item $candidate).PSIsContainer) { $dir = $candidate } else { $dir = (Get-Item $candidate).Directory.FullName } while ($dir -and (Test-Path $dir)) { $toolchain = Join-Path $dir "scripts/buildsystems/vcpkg.cmake" if (Test-Path $toolchain) { return $dir } $parent = Split-Path -Parent $dir if (-not $parent -or $parent -eq $dir) { break } $dir = $parent } return $null } function Copy-VcpkgRuntimeDlls { param( [string[]]$SourceDirectories, [string]$Destination ) $copied = @() foreach ($dir in $SourceDirectories) { if (-not $dir) { continue } if (-not (Test-Path $dir)) { continue } $dlls = Get-ChildItem -Path $dir -Filter "*.dll" -File -ErrorAction SilentlyContinue | Where-Object { $_.Name -notmatch '^Qt6' } foreach ($dll in $dlls) { Copy-Item $dll.FullName -Destination $Destination -Force $copied += $dll.Name } } return $copied | Sort-Object -Unique } function Get-ConfigureArguments { param( [pscustomobject]$Variant, [string]$ToolchainFile, [switch]$EnableTests, [int]$CMakeMajor, [int]$CMakeMinor ) $configureArgs = @("-S", $appDir, "-B", $Variant.BuildDir) $configureArgs += @("-G", $Generator) $configureArgs += "-DCMAKE_TOOLCHAIN_FILE=$ToolchainFile" $configureArgs += "-DVCPKG_TARGET_TRIPLET=x64-windows" $configureArgs += "-DVCPKG_MANIFEST_DIR=$appDir" $configureArgs += "-DVCPKG_INSTALLED_DIR=$sharedVcpkgInstalledDir" $configureArgs += "-DAI_FILE_SORTER_UPDATE_MODE=$($Variant.UpdateMode)" if ($EnableTests) { $configureArgs += "-DAI_FILE_SORTER_BUILD_TESTS=ON" } if ($env:AI_FILE_SORTER_STARTER_CONSOLE) { $configureArgs += "-DAI_FILE_SORTER_STARTER_CONSOLE=$($env:AI_FILE_SORTER_STARTER_CONSOLE)" } if ($CMakeMajor -lt 3 -or ($CMakeMajor -eq 3 -and $CMakeMinor -lt 22)) { $cmakeMajorMinor = "$CMakeMajor.$CMakeMinor" Write-Warning "Detected CMake $cmakeMajorMinor < 3.22; passing QT_FORCE_MIN_CMAKE_VERSION_FOR_USING_QT=$cmakeMajorMinor to satisfy Qt 6.9 requirements." $configureArgs += "-DQT_FORCE_MIN_CMAKE_VERSION_FOR_USING_QT=$cmakeMajorMinor" } if ($Generator -eq "Ninja" -or $Generator -eq "Ninja Multi-Config") { $configureArgs += "-DCMAKE_BUILD_TYPE=$Configuration" } else { $configureArgs += "-A" $configureArgs += "x64" } return ,$configureArgs } function Resolve-OutputExecutable { param( [string]$BuildDir, [string]$ConfigurationName ) $binDir = Join-Path $appDir "bin" $buildConfigDir = Join-Path $BuildDir $ConfigurationName $outputCandidates = @( (Join-Path $buildConfigDir "aifilesorter.exe"), (Join-Path $BuildDir "aifilesorter.exe"), (Join-Path (Join-Path $binDir $ConfigurationName) "aifilesorter.exe"), (Join-Path $binDir "aifilesorter.exe") ) foreach ($candidate in $outputCandidates) { if ($candidate -and (Test-Path $candidate)) { return $candidate } } Write-Warning "Expected executable was not found in standard locations. Reported path may not exist: $($outputCandidates[0])" return $outputCandidates[0] } function Stage-BuildOutput { param( [string]$OutputExe, [string]$BuildDir ) $outputDir = Split-Path -Parent $OutputExe $pdfiumDll = Join-Path $appDir "..\\external\\pdfium\\windows-x64\\bin\\pdfium.dll" $pdfiumDllPath = Resolve-Path -Path $pdfiumDll -ErrorAction SilentlyContinue if ($pdfiumDllPath) { Copy-Item $pdfiumDllPath.Path -Destination $outputDir -Force } else { Write-Warning "PDFium DLL not found under external/pdfium/windows-x64/bin. Run app\\scripts\\vendor_doc_deps.ps1 (or app/scripts/vendor_doc_deps.sh) to populate it." } $precompiledCpuBin = Join-Path $appDir "lib/precompiled/cpu/bin" $precompiledCudaBin = Join-Path $appDir "lib/precompiled/cuda/bin" $precompiledVulkanBin = Join-Path $appDir "lib/precompiled/vulkan/bin" $destWocuda = Join-Path $outputDir "lib/ggml/wocuda" $destWcuda = Join-Path $outputDir "lib/ggml/wcuda" $destWvulkan = Join-Path $outputDir "lib/ggml/wvulkan" foreach ($destDir in @($destWocuda, $destWcuda, $destWvulkan)) { if (-not (Test-Path $destDir)) { New-Item -ItemType Directory -Path $destDir -Force | Out-Null } } if (Test-Path $precompiledCpuBin) { Get-ChildItem -Path $precompiledCpuBin -Filter "*.dll" -File -ErrorAction SilentlyContinue | ForEach-Object { if ($_.Name -ieq "libcurl.dll") { return } Copy-Item $_.FullName -Destination $destWocuda -Force } } $mingwRuntimeNames = @("libgomp-1.dll", "libgcc_s_seh-1.dll", "libgfortran-5.dll", "libwinpthread-1.dll", "libquadmath-0.dll") $runtimeSearchPaths = @() if ($env:OPENBLAS_ROOT) { $runtimeSearchPaths += (Join-Path $env:OPENBLAS_ROOT "bin") } $runtimeSearchPaths += "C:\msys64\mingw64\bin" foreach ($dllName in $mingwRuntimeNames) { $found = $false foreach ($path in $runtimeSearchPaths) { if (-not (Test-Path $path)) { continue } $candidate = Join-Path $path $dllName if (Test-Path $candidate) { Copy-Item $candidate -Destination $destWocuda -Force Copy-Item $candidate -Destination $outputDir -Force $found = $true break } } if (-not $found) { Write-Warning "Could not locate $dllName in any runtime path. Add it manually to $destWocuda if needed." } } if (Test-Path $precompiledCudaBin) { Get-ChildItem -Path $precompiledCudaBin -Filter "*.dll" -File -ErrorAction SilentlyContinue | ForEach-Object { if ($_.Name -ieq "libcurl.dll") { return } Copy-Item $_.FullName -Destination $destWcuda -Force } } if (Test-Path $precompiledVulkanBin) { Get-ChildItem -Path $precompiledVulkanBin -Filter "*.dll" -File -ErrorAction SilentlyContinue | ForEach-Object { if ($_.Name -ieq "libcurl.dll") { return } Copy-Item $_.FullName -Destination $destWvulkan -Force } } foreach ($destDir in @($destWocuda, $destWcuda, $destWvulkan)) { if (Test-Path $destDir) { Get-ChildItem -Path $destDir -Filter "*.lib" -File -Recurse -ErrorAction SilentlyContinue | Remove-Item -Force Get-ChildItem -Path $destDir -Directory -Recurse -ErrorAction SilentlyContinue | Where-Object { $_.Name -in @("bin", "lib") } | ForEach-Object { Remove-Item $_.FullName -Recurse -Force } } } if (-not $SkipDeploy) { $isWindowsHost = [System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform([System.Runtime.InteropServices.OSPlatform]::Windows) if ($isWindowsHost) { $windeployCandidates = @( (Join-Path $sharedVcpkgInstalledDir "x64-windows/tools/Qt6/bin/windeployqt.exe"), (Join-Path $BuildDir "vcpkg_installed/x64-windows/tools/Qt6/bin/windeployqt.exe"), (Join-Path $VcpkgRoot "installed/x64-windows/tools/Qt6/bin/windeployqt.exe"), (Join-Path $appDir "vcpkg_installed/x64-windows/tools/Qt6/bin/windeployqt.exe") ) $windeploy = $null foreach ($candidate in $windeployCandidates) { if ($candidate -and (Test-Path $candidate)) { $windeploy = $candidate break } } if ($windeploy) { Write-Output "Running windeployqt to stage Qt/runtime DLLs for $OutputExe..." & $windeploy --no-translations $OutputExe if ($LASTEXITCODE -ne 0) { throw "windeployqt failed with exit code $LASTEXITCODE" } } else { Write-Warning "windeployqt.exe not found under vcpkg install roots. Install qtbase via vcpkg or run windeployqt manually." } } else { Write-Warning "Skipping runtime deployment; windeployqt is only available on Windows." } } else { Write-Output "Skipping windeployqt step (per -SkipDeploy)." } $vcpkgRuntimeSources = @( (Join-Path $sharedVcpkgInstalledDir "x64-windows/bin"), (Join-Path $BuildDir "vcpkg_installed/x64-windows/bin"), (Join-Path $VcpkgRoot "installed/x64-windows/bin") ) $copiedVcpkgDlls = Copy-VcpkgRuntimeDlls -SourceDirectories $vcpkgRuntimeSources -Destination $outputDir if ($copiedVcpkgDlls.Count -gt 0) { Write-Output ("Staged vcpkg runtime DLLs to {0}:" -f $outputDir) Write-Output " $($copiedVcpkgDlls -join ', ')" } else { Write-Warning "No vcpkg runtime DLLs were copied; ensure curl/openssl/sqlite runtimes are present beside the executable before distributing." } } if (-not (Test-Path (Join-Path $llamaDir "CMakeLists.txt"))) { throw "llama.cpp submodule not found. Run 'git submodule update --init --recursive' before building." } if ($RunTests) { $BuildTests = $true } $selectedVariantNames = @($Variants | Select-Object -Unique) $selectedVariants = foreach ($variantName in $selectedVariantNames) { $variantDefinitions[$variantName] } if ($BuildTests -and ($selectedVariantNames -notcontains "Standard")) { throw "-BuildTests and -RunTests currently require the Standard variant because tests are only configured in the auto-update build." } if (-not $VcpkgRoot) { $envCandidates = @($env:VCPKG_ROOT, $env:VPKG_ROOT) foreach ($envCandidate in $envCandidates) { $resolved = Resolve-VcpkgRootFromPath -Path $envCandidate if ($resolved) { $VcpkgRoot = $resolved break } } } if (-not $VcpkgRoot) { $commandCandidates = @("vcpkg", "vpkg") foreach ($candidate in $commandCandidates) { $cmd = Get-Command $candidate -ErrorAction SilentlyContinue if (-not $cmd) { continue } $possiblePaths = @($cmd.Source, $cmd.Path, $cmd.Definition) foreach ($cPath in $possiblePaths) { $resolved = Resolve-VcpkgRootFromPath -Path $cPath if ($resolved) { $VcpkgRoot = $resolved break } } if ($VcpkgRoot) { break } } } if (-not $VcpkgRoot) { throw "Could not locate vcpkg. Provide -VcpkgRoot or set the VCPKG_ROOT environment variable. If vcpkg is installed via winget, pass -VcpkgRoot explicitly (e.g. C:\dev\vcpkg)." } $cmakeCommand = Get-Command cmake -ErrorAction SilentlyContinue if (-not $cmakeCommand) { throw "cmake executable not found in PATH. Install CMake (3.22+) or add it to PATH." } $cmakeExe = $cmakeCommand.Path $cmakeVersionOutput = & $cmakeExe --version $cmakeVersionPattern = [regex]'cmake version (?\d+)\.(?\d+)(\.(?\d+))?' $cmakeVersionMatch = $cmakeVersionPattern.Match($cmakeVersionOutput) if (-not $cmakeVersionMatch.Success) { Write-Warning "Unable to parse CMake version from output:`n$cmakeVersionOutput" $cmakeMajor = 0 $cmakeMinor = 0 } else { $cmakeMajor = [int]$cmakeVersionMatch.Groups['major'].Value $cmakeMinor = [int]$cmakeVersionMatch.Groups['minor'].Value if ($cmakeMajor -lt 3 -or ($cmakeMajor -eq 3 -and $cmakeMinor -lt 16)) { throw "CMake 3.16 or newer is required. Detected version $($cmakeVersionMatch.Value)." } } $toolchainFile = Join-Path $VcpkgRoot "scripts/buildsystems/vcpkg.cmake" if (-not (Test-Path $toolchainFile)) { throw "The provided vcpkg root '$VcpkgRoot' does not contain scripts/buildsystems/vcpkg.cmake." } if (-not $Generator) { $Generator = "Visual Studio 17 2022" } if ($Generator -eq "Ninja" -or $Generator -eq "Ninja Multi-Config") { $ninjaEnvArch = $env:VSCMD_ARG_TGT_ARCH if ($ninjaEnvArch -and ($ninjaEnvArch -ne "x64")) { Write-Warning "Ninja generator selected while MSVC environment targets '$ninjaEnvArch'. Qt packages are built for x64; run from an x64 Native Tools prompt or choose -Generator ""Visual Studio 17 2022""." } elseif (-not $ninjaEnvArch) { Write-Warning "Using Ninja generator without an initialized MSVC environment. Ensure you run from an x64 Native Tools command prompt so the 64-bit compiler is available." } } if ($Parallel -lt 1) { $Parallel = [Math]::Max([System.Environment]::ProcessorCount, 1) } if ($Clean) { foreach ($variant in $selectedVariants) { if (Test-Path $variant.BuildDir) { Write-Output "Removing existing build directory '$($variant.BuildDir)'..." Remove-Item -Recurse -Force $variant.BuildDir } } if (Test-Path $sharedVcpkgInstalledDir) { Write-Output "Removing shared vcpkg install directory '$sharedVcpkgInstalledDir'..." Remove-Item -Recurse -Force $sharedVcpkgInstalledDir } } if (-not (Test-Path $sharedVcpkgInstalledDir)) { New-Item -ItemType Directory -Path $sharedVcpkgInstalledDir | Out-Null } Write-Output "Using $Parallel parallel job(s) for builds." Write-Output "Shared vcpkg installed directory: $sharedVcpkgInstalledDir" $builtOutputs = New-Object System.Collections.Generic.List[object] foreach ($variant in $selectedVariants) { if (-not (Test-Path $variant.BuildDir)) { New-Item -ItemType Directory -Path $variant.BuildDir | Out-Null } $enableTests = $BuildTests -and $variant.Name -eq "Standard" $configureArgs = Get-ConfigureArguments -Variant $variant ` -ToolchainFile $toolchainFile ` -EnableTests:$enableTests ` -CMakeMajor $cmakeMajor ` -CMakeMinor $cmakeMinor Write-Output "" Write-Output "==== Building $($variant.Name) Variant ====" Write-Output "Description : $($variant.Description)" Write-Output "Build dir : $($variant.BuildDir)" Write-Output "Update mode : $($variant.UpdateMode)" Write-Output "Configure : cmake $($configureArgs -join ' ')" Write-Output "=====================================" & $cmakeExe @configureArgs if ($LASTEXITCODE -ne 0) { throw "cmake configure failed for the $($variant.Name) variant." } $buildArgs = @("--build", $variant.BuildDir, "--config", $Configuration, "--parallel", $Parallel) Write-Output "Building $($variant.Name) variant..." & $cmakeExe @buildArgs if ($LASTEXITCODE -ne 0) { throw "cmake build failed for the $($variant.Name) variant." } if ($enableTests) { Write-Output "Building unit tests in the Standard variant..." $testBuildArgs = @("--build", $variant.BuildDir, "--config", $Configuration, "--target", "ai_file_sorter_tests", "--parallel", $Parallel) & $cmakeExe @testBuildArgs if ($LASTEXITCODE -ne 0) { throw "Failed to build unit tests in the Standard variant." } if ($RunTests) { $ctestExe = Join-Path (Split-Path $cmakeExe) "ctest.exe" if (-not (Test-Path $ctestExe)) { $ctestExe = "ctest" } Push-Location $variant.BuildDir try { Write-Output "Running ctest in the Standard variant..." & $ctestExe "-C" $Configuration "--output-on-failure" "-j" $Parallel if ($LASTEXITCODE -ne 0) { throw "ctest reported failures." } } finally { Pop-Location } } } $outputExe = Resolve-OutputExecutable -BuildDir $variant.BuildDir -ConfigurationName $Configuration Write-Output "Executable located at: $outputExe" Stage-BuildOutput -OutputExe $outputExe -BuildDir $variant.BuildDir $builtOutputs.Add([pscustomobject]@{ Variant = $variant.Name UpdateMode = $variant.UpdateMode Executable = $outputExe }) | Out-Null } Write-Output "" Write-Output "Build summary:" foreach ($output in $builtOutputs) { Write-Output (" - {0} [{1}]: {2}" -f $output.Variant, $output.UpdateMode, $output.Executable) } ================================================ FILE: app/include/AppInfo.hpp ================================================ #pragma once #include #ifndef AI_FILE_SORTER_APP_NAME #define AI_FILE_SORTER_APP_NAME "AI File Sorter" #endif inline QString app_display_name() { return QStringLiteral(AI_FILE_SORTER_APP_NAME); } ================================================ FILE: app/include/CategorizationDialog.hpp ================================================ #ifndef CATEGORIZATIONDIALOG_HPP #define CATEGORIZATIONDIALOG_HPP #include "CategoryLanguage.hpp" #include "Types.hpp" #include #include #include #include #include #include #include #include class DatabaseManager; class QCloseEvent; class QEvent; class QPushButton; class QTableView; class QCheckBox; class QStandardItem; class CategorizationDialog : public QDialog { Q_DECLARE_TR_FUNCTIONS(CategorizationDialog) public: CategorizationDialog(DatabaseManager* db_manager, bool show_subcategory_col, const std::string& undo_dir, CategoryLanguage category_language = CategoryLanguage::English, QWidget* parent = nullptr); void set_show_subcategory_column(bool enabled); bool show_subcategory_column_enabled() const { return show_subcategory_column; } #ifdef AI_FILE_SORTER_TEST_BUILD void test_set_entries(const std::vector& files); void test_trigger_confirm(); void test_trigger_undo(); bool test_undo_enabled() const; #endif bool is_dialog_valid() const; void show_results(const std::vector& categorized_files, const std::string& base_dir_override = std::string(), bool include_subdirectories = false, bool allow_image_renames = true, bool allow_document_renames = true); protected: void closeEvent(QCloseEvent* event) override; void changeEvent(QEvent* event) override; private: enum class RowStatus { None = 0, Moved, Renamed, RenamedAndMoved, Skipped, NotSelected, Preview }; static constexpr int kStatusRole = Qt::UserRole + 100; static constexpr int kFilePathRole = Qt::UserRole + 1; static constexpr int kUsedConsistencyRole = Qt::UserRole + 2; static constexpr int kRenameOnlyRole = Qt::UserRole + 3; static constexpr int kFileTypeRole = Qt::UserRole + 4; static constexpr int kRenameAppliedRole = Qt::UserRole + 5; static constexpr int kRenameLockedRole = Qt::UserRole + 6; static constexpr int kHiddenCategoryRole = Qt::UserRole + 7; static constexpr int kHiddenSubcategoryRole = Qt::UserRole + 8; static constexpr int kOriginalFileNameRole = Qt::UserRole + 9; static constexpr int kOriginalCategoryRole = Qt::UserRole + 10; static constexpr int kOriginalSubcategoryRole = Qt::UserRole + 11; static constexpr int kCanonicalCategoryRole = Qt::UserRole + 12; static constexpr int kCanonicalSubcategoryRole = Qt::UserRole + 13; enum Column { ColumnSelect = 0, ColumnFile = 1, ColumnType = 2, ColumnSuggestedName = 3, ColumnCategory = 4, ColumnSubcategory = 5, ColumnStatus = 6, ColumnPreview = 7 }; struct MoveRecord { int row_index; std::string source_path; std::string destination_path; std::uintmax_t size_bytes{0}; std::time_t mtime{0}; }; struct PreviewRecord { std::string source; std::string destination; std::string source_file_name; std::string destination_file_name; std::string category; std::string subcategory; bool use_subcategory{false}; bool rename_only{false}; }; void setup_ui(); void populate_model(); void ensure_unique_suggested_names_in_model(); void record_categorization_to_db(); void on_confirm_and_sort_button_clicked(); void on_continue_later_button_clicked(); void on_undo_button_clicked(); void show_close_button(); void restore_action_buttons(); void update_status_column(int row, bool success, bool attempted = true, bool renamed = false, bool moved = false); void on_select_all_toggled(bool checked); /** * @brief Selects all highlighted rows for processing. */ void on_select_highlighted_clicked(); void apply_select_all(bool checked); /** * @brief Applies a check state to the given rows in the Process column. */ void apply_check_state_to_rows(const std::vector& rows, Qt::CheckState state); void on_item_changed(QStandardItem* item); void update_select_all_state(); void update_type_icon(QStandardItem* item); void retranslate_ui(); void apply_status_text(QStandardItem* item) const; RowStatus status_from_item(const QStandardItem* item) const; void on_show_subcategories_toggled(bool checked); void apply_subcategory_visibility(); void clear_move_history(); void record_move_for_undo(int row, const std::string& source, const std::string& destination, std::uintmax_t size_bytes, std::time_t mtime); void handle_selected_row(int row_index, const std::string& file_name, const std::string& rename_candidate, const std::string& category, const std::string& subcategory, const std::string& source_dir, const std::string& base_dir, std::vector& files_not_moved, FileType file_type, bool rename_only, bool used_consistency_hints, bool dry_run); void persist_move_plan(); bool undo_move_history(); void update_status_after_undo(); bool move_file_back(const std::string& source, const std::string& destination); void remove_empty_parent_directories(const std::string& destination); void set_preview_status(int row, const std::string& destination); void update_preview_column(int row); std::optional compute_preview_path(int row) const; std::optional build_preview_record_for_row(int row, std::string* debug_reason = nullptr) const; std::string resolve_destination_name(const std::string& original_name, const std::string& rename_candidate) const; bool validate_filename(const std::string& name, std::string& error) const; bool resolve_row_flags(int row, bool& rename_only, bool& used_consistency_hints, FileType& file_type) const; void set_show_rename_column(bool enabled); void apply_rename_visibility(); void apply_category_visibility(); /** * @brief Hides rows that are rename-only when required by the dialog mode. */ void apply_rename_only_row_visibility(); /** * @brief Syncs the rename-only checkbox state to current UI options. */ void update_rename_only_checkbox_state(); /** * @brief Enables/disables the subcategory checkbox based on rename-only mode. */ void update_subcategory_checkbox_state(); /** * @brief Marks image rows as rename-only when toggled. * @param checked True when image rename-only is enabled. */ void on_rename_images_only_toggled(bool checked); /** * @brief Marks document rows as rename-only when toggled. * @param checked True when document rename-only is enabled. */ void on_rename_documents_only_toggled(bool checked); bool row_is_already_renamed_with_category(int row) const; /** * @brief Returns true if the row points to a supported image file. * @param row Row index in the model. * @return True when the row is an image file supported by the visual analyzer. */ bool row_is_supported_image(int row) const; /** * @brief Returns true if the row points to a supported document file. * @param row Row index in the model. * @return True when the row is a supported document file. */ bool row_is_supported_document(int row) const; /** * @brief Returns unique row indices that are highlighted in the table view. */ std::vector selected_row_indices() const; /** * @brief Opens a dialog to bulk edit categories for highlighted rows. */ void on_bulk_edit_clicked(); DatabaseManager* db_manager; CategoryLanguage category_language_{CategoryLanguage::English}; bool show_subcategory_column; bool include_subdirectories_{false}; bool allow_image_renames_{true}; bool allow_document_renames_{true}; bool show_rename_column{false}; std::vector categorized_files; std::shared_ptr core_logger; std::shared_ptr db_logger; std::shared_ptr ui_logger; QTableView* table_view{nullptr}; QStandardItemModel* model{nullptr}; QPushButton* confirm_button{nullptr}; QPushButton* continue_button{nullptr}; QPushButton* close_button{nullptr}; QCheckBox* select_all_checkbox{nullptr}; QPushButton* select_highlighted_button{nullptr}; QPushButton* bulk_edit_button{nullptr}; QCheckBox* show_subcategories_checkbox{nullptr}; QCheckBox* dry_run_checkbox{nullptr}; QCheckBox* rename_images_only_checkbox{nullptr}; QCheckBox* rename_documents_only_checkbox{nullptr}; QPushButton* undo_button{nullptr}; std::vector move_history_; std::vector dry_run_plan_; bool updating_select_all{false}; bool suppress_item_changed_{false}; std::string undo_dir_; std::string base_dir_; }; #endif // CATEGORIZATIONDIALOG_HPP ================================================ FILE: app/include/CategorizationProgressDialog.hpp ================================================ #ifndef CATEGORIZATIONPROGRESSDIALOG_HPP #define CATEGORIZATIONPROGRESSDIALOG_HPP #include "Types.hpp" #include #include #include #include #include #include #include #include class MainApp; class QLabel; class QPlainTextEdit; class QPushButton; class QTableWidget; class QTimer; class QEvent; class CategorizationProgressDialog : public QDialog { Q_DECLARE_TR_FUNCTIONS(CategorizationProgressDialog) public: enum class StageId { ImageAnalysis, DocumentAnalysis, Categorization }; struct StagePlan { StageId id; std::vector items; }; CategorizationProgressDialog(QWidget* parent, MainApp* main_app, bool show_subcategory_col); void show(); void hide(); void append_text(const std::string& text); void configure_stages(const std::vector& stages); void set_stage_items(StageId stage_id, const std::vector& items); void set_active_stage(StageId stage_id); void mark_stage_item_pending(StageId stage_id, const FileEntry& entry); void mark_stage_item_in_progress(StageId stage_id, const FileEntry& entry); void mark_stage_item_completed(StageId stage_id, const FileEntry& entry); protected: void changeEvent(QEvent* event) override; private: enum class ItemStatus { NotApplicable, Pending, InProgress, Completed }; enum class DisplayType { Directory, File, Image, Document }; struct StageState { bool enabled{false}; std::unordered_set item_keys; }; struct ItemState { int row{-1}; DisplayType display_type{DisplayType::File}; std::array stage_statuses{ ItemStatus::NotApplicable, ItemStatus::NotApplicable, ItemStatus::NotApplicable }; }; static constexpr int kStageCount = 3; void setup_ui(bool show_subcategory_col); void retranslate_ui(); void request_stop(); static std::string make_item_key(const std::string& full_path, FileType type); static std::size_t stage_index(StageId stage_id); QString stage_label(StageId stage_id) const; static DisplayType classify_display_type(const FileEntry& entry); QString display_type_label(DisplayType display_type) const; int column_for_stage(StageId stage_id) const; void ensure_stage_enabled(StageId stage_id); void upsert_stage_item(StageId stage_id, const FileEntry& entry); void upsert_item(const FileEntry& entry); void set_stage_item_status(StageId stage_id, const FileEntry& entry, ItemStatus status); void rebuild_headers(); void refresh_stage_overview(); void refresh_row(int row); void refresh_summary(); void refresh_spinner(); bool has_in_progress_item() const; ItemStatus stage_status_for_row(const ItemState& state, StageId stage_id) const; std::optional find_stage_row(StageId stage_id, ItemStatus status) const; void ensure_row_visible(int row); MainApp* main_app; QLabel* stage_list_label{nullptr}; QLabel* summary_label{nullptr}; QLabel* log_label{nullptr}; QTableWidget* status_table{nullptr}; QPlainTextEdit* text_view{nullptr}; QPushButton* stop_button{nullptr}; QTimer* spinner_timer{nullptr}; std::array stage_states_{}; std::vector active_stage_order_; std::optional active_stage_; std::unordered_map item_states_; int spinner_frame_index_{0}; }; #endif // CATEGORIZATIONPROGRESSDIALOG_HPP ================================================ FILE: app/include/CategorizationService.hpp ================================================ #ifndef CATEGORIZATION_SERVICE_HPP #define CATEGORIZATION_SERVICE_HPP #include "Types.hpp" #include "DatabaseManager.hpp" #include #include #include #include #include #include #include #include #include #include class Settings; class ILLMClient; namespace spdlog { class logger; } /** * @brief Provides LLM-backed file categorization with caching and validation. */ class CategorizationService { public: using ProgressCallback = std::function; using QueueCallback = std::function; using CompletionCallback = std::function; using RecategorizationCallback = std::function; /** * @brief Overrides the name/path used in LLM prompts for a file entry. */ struct PromptOverride { std::string name; std::string path; }; using PromptOverrideProvider = std::function(const FileEntry&)>; /** Supplies an optional suggested rename for an entry during categorization. */ using SuggestedNameProvider = std::function; /** * @brief Constructs the service with settings, database access, and logging. * @param settings Application settings reference. * @param db_manager Database manager used for cache access. * @param core_logger Logger for core activity. */ CategorizationService(Settings& settings, DatabaseManager& db_manager, std::shared_ptr core_logger); /** * @brief Verifies that required remote credentials are configured. * @param error_message Optional output for a user-facing error message. * @return True when credentials are present or not required. */ bool ensure_remote_credentials(std::string* error_message = nullptr) const; /** * @brief Removes cached entries that have empty categories for a directory. * @param directory_path Directory to clean. * @return Entries that were removed. */ std::vector prune_empty_cached_entries(const std::string& directory_path); /** * @brief Loads cached categorizations for the provided directory. * @param directory_path Directory to load. * @return Cached entries for the directory. */ std::vector load_cached_entries(const std::string& directory_path) const; /** * @brief Categorizes a list of file entries using the configured LLM workflow. * @param files Entries to categorize. * @param is_local_llm True when using a local LLM backend. * @param stop_flag Cancellation flag. * @param progress_callback Progress updates callback. * @param queue_callback Called when an entry is queued. * @param completion_callback Called when an entry has finished processing. * @param recategorization_callback Called when an entry must be re-categorized. * @param llm_factory Factory for creating an LLM client. * @param prompt_override Optional prompt override provider. * @param suggested_name_provider Optional suggested-name provider. * @return Categorized entries that were successfully processed. */ std::vector categorize_entries( const std::vector& files, bool is_local_llm, std::atomic& stop_flag, const ProgressCallback& progress_callback, const QueueCallback& queue_callback, const CompletionCallback& completion_callback, const RecategorizationCallback& recategorization_callback, std::function()> llm_factory, const PromptOverrideProvider& prompt_override = {}, const SuggestedNameProvider& suggested_name_provider = {}) const; private: using CategoryPair = std::pair; using HintHistory = std::deque; using SessionHistoryMap = std::unordered_map; /** * @brief Returns a cached categorization when available, otherwise calls the LLM. * @param llm LLM client used for the request. * @param is_local_llm True when using a local LLM backend. * @param display_name Display name for logging. * @param display_path Display path for logging. * @param dir_path Full directory path for cache lookup. * @param prompt_name Name used in the prompt. * @param prompt_path Path used in the prompt. * @param file_type File or directory. * @param progress_callback Progress updates callback. * @param consistency_context Consistency hints block. * @return Resolved category for the item. */ DatabaseManager::ResolvedCategory categorize_with_cache( ILLMClient& llm, bool is_local_llm, const std::string& display_name, const std::string& display_path, const std::string& dir_path, const std::string& prompt_name, const std::string& prompt_path, FileType file_type, const ProgressCallback& progress_callback, const std::string& consistency_context) const; /** * @brief Categorizes a single entry and persists the result. * @param llm LLM client used for the request. * @param is_local_llm True when using a local LLM backend. * @param entry File entry to categorize. * @param prompt_override Optional prompt override. * @param suggested_name Optional suggested name for renaming. * @param stop_flag Cancellation flag. * @param progress_callback Progress updates callback. * @param recategorization_callback Callback for re-categorization events. * @param session_history Mutable session history for consistency hints. * @return Categorized entry when successful. */ std::optional categorize_single_entry( ILLMClient& llm, bool is_local_llm, const FileEntry& entry, const std::optional& prompt_override, const std::string& suggested_name, std::atomic& stop_flag, const ProgressCallback& progress_callback, const RecategorizationCallback& recategorization_callback, SessionHistoryMap& session_history) const; /** * @brief Combines language, whitelist, and hint blocks into a single prompt context. * @param hint_block Consistency hint block. * @return Combined prompt context. */ std::string build_combined_context(const std::string& hint_block) const; DatabaseManager::ResolvedCategory localize_resolved_category( ILLMClient& llm, const DatabaseManager::ResolvedCategory& resolved) const; std::optional translate_resolved_category( ILLMClient& llm, const DatabaseManager::ResolvedCategory& resolved) const; /** * @brief Runs the categorization flow with cache handling for a single entry. * @param llm LLM client used for the request. * @param is_local_llm True when using a local LLM backend. * @param entry File entry to categorize. * @param display_path Display path for logging. * @param dir_path Full directory path for cache lookup. * @param prompt_name Name used in the prompt. * @param prompt_path Path used in the prompt. * @param progress_callback Progress updates callback. * @param combined_context Combined prompt context. * @return Resolved category for the item. */ DatabaseManager::ResolvedCategory run_categorization_with_cache( ILLMClient& llm, bool is_local_llm, const FileEntry& entry, const std::string& display_path, const std::string& dir_path, const std::string& prompt_name, const std::string& prompt_path, const ProgressCallback& progress_callback, const std::string& combined_context) const; /** * @brief Handles empty or invalid categorization results. * @param entry File entry being categorized. * @param dir_path Directory path of the entry. * @param resolved Resolved category data. * @param used_consistency_hints True if hints were applied. * @param is_local_llm True when using a local LLM backend. * @param recategorization_callback Callback for re-categorization events. * @return Optional replacement categorization when a retry is needed. */ std::optional handle_empty_result( const FileEntry& entry, const std::string& dir_path, const DatabaseManager::ResolvedCategory& resolved, bool used_consistency_hints, bool is_local_llm, const RecategorizationCallback& recategorization_callback) const; /** * @brief Persists categorization results and updates session hint history. * @param entry File entry being categorized. * @param dir_path Directory path of the entry. * @param resolved Resolved category data. * @param used_consistency_hints True if hints were applied. * @param suggested_name Suggested rename value. * @param session_history Session history for consistency hints. */ void update_storage_with_result(const FileEntry& entry, const std::string& dir_path, const DatabaseManager::ResolvedCategory& resolved, bool used_consistency_hints, const std::string& suggested_name, SessionHistoryMap& session_history) const; /** * @brief Runs the LLM request with a timeout for the given item. * @param llm LLM client used for the request. * @param item_name Display name for the item. * @param item_path Display path for the item. * @param file_type File or directory. * @param is_local_llm True when using a local LLM backend. * @param consistency_context Consistency hints block. * @return Raw LLM response string. */ std::string run_llm_with_timeout( ILLMClient& llm, const std::string& item_name, const std::string& item_path, FileType file_type, bool is_local_llm, const std::string& consistency_context) const; /** * @brief Resolves the LLM timeout based on runtime and environment settings. * @param is_local_llm True when using a local LLM backend. * @return Timeout in seconds. */ int resolve_llm_timeout(bool is_local_llm) const; /** * @brief Launches an asynchronous LLM categorization request. * @param llm LLM client used for the request. * @param item_name Display name for the item. * @param item_path Display path for the item. * @param file_type File or directory. * @param consistency_context Consistency hints block. * @return Future that yields the raw LLM response. */ std::future start_llm_future(ILLMClient& llm, const std::string& item_name, const std::string& item_path, FileType file_type, const std::string& consistency_context) const; /** * @brief Builds a whitelist context block for the prompt. * @return Whitelist prompt section. */ std::string build_whitelist_context() const; /** * @brief Builds a prompt instruction for non-English category languages. * @return Language instruction block or empty string. */ std::string build_category_language_context() const; /** * @brief Collects recent category assignments to provide consistency hints. * @param signature Signature key for the file type/extension. * @param session_history In-memory history of assignments. * @param extension File extension. * @param file_type File or directory. * @return List of up to kMaxConsistencyHints pairs. */ std::vector collect_consistency_hints( const std::string& signature, const SessionHistoryMap& session_history, const std::string& extension, FileType file_type) const; /** * @brief Returns a cached categorization if it is valid for the entry. * @param item_name Display name for the item. * @param current_path Display path for the current on-disk location. * @param categorization_path Effective path used for categorization context. * @param dir_path Full directory path for cache lookup. * @param file_type File or directory. * @param progress_callback Progress updates callback. * @return Resolved category when cache is valid. */ std::optional try_cached_categorization( const std::string& item_name, const std::string& current_path, const std::string& categorization_path, const std::string& dir_path, FileType file_type, const ProgressCallback& progress_callback) const; /** * @brief Ensures remote credentials are present and reports errors via progress callback. * @param item_name Display name for the item. * @param progress_callback Progress updates callback. * @return True when credentials are present or not required. */ bool ensure_remote_credentials_for_request( const std::string& item_name, const ProgressCallback& progress_callback) const; /** * @brief Categorizes a single item by calling the LLM and validating the response. * @param llm LLM client used for the request. * @param is_local_llm True when using a local LLM backend. * @param display_name Display name for logging. * @param display_path Display path for logging. * @param prompt_name Name used in the prompt. * @param prompt_path Path used in the prompt. * @param file_type File or directory. * @param progress_callback Progress updates callback. * @param consistency_context Consistency hints block. * @return Resolved category for the item. */ DatabaseManager::ResolvedCategory categorize_via_llm( ILLMClient& llm, bool is_local_llm, const std::string& display_name, const std::string& display_path, const std::string& prompt_name, const std::string& prompt_path, FileType file_type, const ProgressCallback& progress_callback, const std::string& consistency_context) const; /** * @brief Emits a formatted progress message for a categorization event. * @param progress_callback Progress updates callback. * @param source Label for the progress source. * @param item_name Display name for the item. * @param resolved Resolved category data. * @param current_path Display path for the current on-disk location. * @param categorization_path Effective path used for categorization context. */ void emit_progress_message(const ProgressCallback& progress_callback, std::string_view source, const std::string& item_name, const DatabaseManager::ResolvedCategory& resolved, const std::string& current_path, const std::string& categorization_path) const; /** * @brief Builds a signature key for consistency hints. * @param file_type File or directory. * @param extension File extension. * @return Signature key for consistency lookup. */ static std::string make_file_signature(FileType file_type, const std::string& extension); /** * @brief Extracts a lowercase file extension (including the dot). * @param file_name File name to inspect. * @return Lowercase extension with dot, or empty string when none exists. */ static std::string extract_extension(const std::string& file_name); /** * @brief Appends a unique, sanitized hint to the target list. * @param target Hint list to update. * @param candidate Candidate pair to append. * @return True when the hint was added. */ static bool append_unique_hint(std::vector& target, const CategoryPair& candidate); /** * @brief Updates in-memory hint history with the latest assignment. * @param history Hint history to update. * @param assignment Category/subcategory assignment to record. */ static void record_session_assignment(HintHistory& history, const CategoryPair& assignment); /** * @brief Formats consistency hints into a prompt block. * @param hints Consistency hints to format. * @return Prompt block string. */ std::string format_hint_block(const std::vector& hints) const; #ifdef AI_FILE_SORTER_TEST_BUILD friend class CategorizationServiceTestAccess; #endif Settings& settings; DatabaseManager& db_manager; std::shared_ptr core_logger; }; #endif ================================================ FILE: app/include/CategorizationServiceTestAccess.hpp ================================================ #pragma once #ifdef AI_FILE_SORTER_TEST_BUILD #include "CategorizationService.hpp" /** * @brief Test-only accessors for CategorizationService internals. */ class CategorizationServiceTestAccess { public: /** * @brief Returns the whitelist context string used in prompts. * @param service CategorizationService instance under test. * @return Prompt snippet describing allowed categories/subcategories. */ static std::string build_whitelist_context(const CategorizationService& service) { return service.build_whitelist_context(); } /** * @brief Returns the category-language context string used in prompts. * @param service CategorizationService instance under test. * @return Prompt snippet describing the required category language. */ static std::string build_category_language_context(const CategorizationService& service) { return service.build_category_language_context(); } }; #endif // AI_FILE_SORTER_TEST_BUILD ================================================ FILE: app/include/CategorizationSession.hpp ================================================ #ifndef CATEGORIZATIONSESSION_HPP #define CATEGORIZATIONSESSION_HPP #include #include class CategorizationSession { std::string key; std::string model; std::string base_url; public: /** * @brief Construct a session for OpenAI-compatible requests. */ CategorizationSession(std::string api_key, std::string model, std::string base_url = std::string()); ~CategorizationSession(); LLMClient create_llm_client() const; }; #endif ================================================ FILE: app/include/CategoryLanguage.hpp ================================================ #ifndef CATEGORYLANGUAGE_HPP #define CATEGORYLANGUAGE_HPP #include #include #include enum class CategoryLanguage { Dutch, English, French, German, Italian, Polish, Portuguese, Spanish, Turkish }; inline QString categoryLanguageToString(CategoryLanguage language) { static const std::array names = { "Dutch", "English", "French", "German", "Italian", "Polish", "Portuguese", "Spanish", "Turkish" }; const auto idx = static_cast(language); if (idx < names.size()) { return QString::fromUtf8(names[idx]); } return QStringLiteral("English"); } inline CategoryLanguage categoryLanguageFromString(const QString& value) { const QString lowered = value.toLower(); static const std::array, 9> mapping = {{ {QStringLiteral("dutch"), CategoryLanguage::Dutch}, {QStringLiteral("english"), CategoryLanguage::English}, {QStringLiteral("french"), CategoryLanguage::French}, {QStringLiteral("german"), CategoryLanguage::German}, {QStringLiteral("italian"), CategoryLanguage::Italian}, {QStringLiteral("polish"), CategoryLanguage::Polish}, {QStringLiteral("portuguese"), CategoryLanguage::Portuguese}, {QStringLiteral("spanish"), CategoryLanguage::Spanish}, {QStringLiteral("turkish"), CategoryLanguage::Turkish}, }}; for (const auto& entry : mapping) { if (lowered == entry.first) { return entry.second; } } return CategoryLanguage::English; } inline std::string categoryLanguageDisplay(CategoryLanguage lang) { return categoryLanguageToString(lang).toStdString(); } #endif // CATEGORYLANGUAGE_HPP ================================================ FILE: app/include/ConsistencyPassService.hpp ================================================ #ifndef CONSISTENCY_PASS_SERVICE_HPP #define CONSISTENCY_PASS_SERVICE_HPP #include "CategoryLanguage.hpp" #include "DatabaseManager.hpp" #include "Types.hpp" #include #include #include #include #include #include #include class ILLMClient; namespace spdlog { class logger; } class ConsistencyPassService { public: using ProgressCallback = std::function; ConsistencyPassService(DatabaseManager& db_manager, std::shared_ptr logger); void set_prompt_logging_enabled(bool enabled); void run(std::vector& categorized_files, std::vector& newly_categorized_files, std::function()> llm_factory, std::atomic& stop_flag, CategoryLanguage category_language, const ProgressCallback& progress_callback) const; private: std::unique_ptr create_llm(std::function()> llm_factory) const; void process_chunks(ILLMClient& llm, const std::vector>& taxonomy, std::vector& categorized_files, std::unordered_map& items_by_key, std::unordered_map& new_items_by_key, std::atomic& stop_flag, CategoryLanguage category_language, const ProgressCallback& progress_callback) const; void process_chunk(const std::vector& chunk, size_t start_index, size_t end_index, size_t total_items, ILLMClient& llm, const std::vector>& taxonomy, std::unordered_map& items_by_key, std::unordered_map& new_items_by_key, CategoryLanguage category_language, const ProgressCallback& progress_callback) const; void log_chunk_items(const std::vector& chunk, const char* stage) const; bool apply_harmonized_response(const std::string& response, const std::vector& chunk, std::unordered_map& items_by_key, std::unordered_map& new_items_by_key, const ProgressCallback& progress_callback, DatabaseManager& db_manager, CategoryLanguage category_language) const; DatabaseManager& db_manager; std::shared_ptr logger; mutable bool prompt_logging_enabled{false}; }; #endif ================================================ FILE: app/include/CustomApiDialog.hpp ================================================ #ifndef CUSTOMAPIDIALOG_HPP #define CUSTOMAPIDIALOG_HPP #include "Types.hpp" #include #include class QCheckBox; class QLineEdit; class QPushButton; class QTextEdit; /** * @brief Dialog for creating or editing custom OpenAI-compatible API entries. */ class CustomApiDialog : public QDialog { Q_DECLARE_TR_FUNCTIONS(CustomApiDialog) public: /** * @brief Construct a dialog for a new custom API entry. * @param parent Parent widget. */ explicit CustomApiDialog(QWidget* parent = nullptr); /** * @brief Construct a dialog pre-populated with an existing entry. * @param parent Parent widget. * @param existing Existing custom API values to edit. */ explicit CustomApiDialog(QWidget* parent, const CustomApiEndpoint& existing); /** * @brief Return the dialog values as a CustomApiEndpoint entry. */ CustomApiEndpoint result() const; private: /** * @brief Build the dialog layout and widgets. */ void setup_ui(); /** * @brief Connect widget signals to validation and handlers. */ void wire_signals(); /** * @brief Apply existing values to the input fields. * @param existing Existing custom API values to load. */ void apply_existing(const CustomApiEndpoint& existing); /** * @brief Validate inputs and update the ok button state. */ void validate_inputs(); QLineEdit* name_edit{nullptr}; QTextEdit* description_edit{nullptr}; QLineEdit* base_url_edit{nullptr}; QLineEdit* model_edit{nullptr}; QLineEdit* api_key_edit{nullptr}; QCheckBox* show_api_key_checkbox{nullptr}; QPushButton* ok_button{nullptr}; }; #endif // CUSTOMAPIDIALOG_HPP ================================================ FILE: app/include/CustomLLMDialog.hpp ================================================ #ifndef CUSTOMLLMDIALOG_HPP #define CUSTOMLLMDIALOG_HPP #include "Types.hpp" #include #include class QLineEdit; class QPushButton; class QTextEdit; /** * @brief Dialog for creating or editing custom local LLM entries. */ class CustomLLMDialog : public QDialog { Q_DECLARE_TR_FUNCTIONS(CustomLLMDialog) public: /** * @brief Construct a dialog for a new custom LLM entry. * @param parent Parent widget. */ explicit CustomLLMDialog(QWidget* parent = nullptr); /** * @brief Construct a dialog pre-populated with an existing entry. * @param parent Parent widget. * @param existing Existing custom LLM values to edit. */ explicit CustomLLMDialog(QWidget* parent, const CustomLLM& existing); /** * @brief Return the dialog values as a CustomLLM entry. */ CustomLLM result() const; private: /** * @brief Build the dialog layout and widgets. */ void setup_ui(); /** * @brief Connect widget signals to validation and handlers. */ void wire_signals(); /** * @brief Apply existing values to the input fields. * @param existing Existing custom LLM values to load. */ void apply_existing(const CustomLLM& existing); /** * @brief Validate inputs and update the ok button state. */ void validate_inputs(); /** * @brief Open a file picker to select a local model file. */ void browse_for_file(); QLineEdit* name_edit{nullptr}; QTextEdit* description_edit{nullptr}; QLineEdit* path_edit{nullptr}; QPushButton* browse_button{nullptr}; QPushButton* ok_button{nullptr}; }; #endif // CUSTOMLLMDIALOG_HPP ================================================ FILE: app/include/DatabaseManager.hpp ================================================ #ifndef DATABASEMANAGER_HPP #define DATABASEMANAGER_HPP #include "CategoryLanguage.hpp" #include "Types.hpp" #include #include #include #include #include #include class DatabaseManager { public: explicit DatabaseManager(std::string config_dir); ~DatabaseManager(); bool is_file_already_categorized(const std::string &file_name); struct ResolvedCategory { int taxonomy_id; std::string category; std::string subcategory; }; ResolvedCategory resolve_category(const std::string& category, const std::string& subcategory); ResolvedCategory resolve_category_for_language(const std::string& category, const std::string& subcategory, CategoryLanguage language); std::optional get_category_translation(int taxonomy_id, CategoryLanguage language) const; ResolvedCategory localize_category(const ResolvedCategory& resolved, CategoryLanguage language) const; CategorizedFile localize_categorized_file(const CategorizedFile& entry, CategoryLanguage language) const; bool upsert_category_translation(int taxonomy_id, CategoryLanguage language, const std::string& category, const std::string& subcategory); bool insert_or_update_file_with_categorization(const std::string& file_name, const std::string& file_type, const std::string& dir_path, const ResolvedCategory& resolved, bool used_consistency_hints, const std::string& suggested_name = "", bool rename_only = false, bool rename_applied = false); std::vector get_dir_contents_from_db(const std::string &dir_path); bool remove_file_categorization(const std::string& dir_path, const std::string& file_name, const FileType file_type); std::vector remove_empty_categorizations(const std::string& dir_path); std::vector get_categorized_files(const std::string &directory_path); std::vector get_categorized_files_recursive(const std::string& directory_path); std::optional get_categorized_file(const std::string& dir_path, const std::string& file_name, FileType file_type); /** * @brief Looks up a cached category/subcategory for a specific directory+file. * @param dir_path Directory path used for cache scoping. * @param file_name File name to resolve. * @param file_type File or directory. * @return Pair of category/subcategory strings when present; empty when not found. */ std::vector get_categorization_from_db(const std::string& dir_path, const std::string& file_name, FileType file_type); void increment_taxonomy_frequency(int taxonomy_id); std::vector> get_taxonomy_snapshot(std::size_t max_entries, CategoryLanguage language = CategoryLanguage::English) const; std::vector> get_recent_categories_for_extension(const std::string& extension, FileType file_type, std::size_t limit) const; bool clear_directory_categorizations(const std::string& dir_path, bool recursive = false); bool has_categorization_style_conflict(const std::string& dir_path, bool desired_style, bool recursive = false) const; std::optional get_directory_categorization_style(const std::string& dir_path) const; private: struct TaxonomyEntry { int id; std::string category; std::string subcategory; std::string normalized_category; std::string normalized_subcategory; }; void initialize_schema(); void initialize_taxonomy_schema(); void load_taxonomy_cache(); void load_translation_cache(); std::string normalize_label(const std::string& input) const; static double string_similarity(const std::string& a, const std::string& b); static std::string make_key(const std::string& norm_category, const std::string& norm_subcategory); static std::string make_translation_entry_key(int taxonomy_id, CategoryLanguage language); static std::string make_translation_lookup_key(CategoryLanguage language, const std::string& norm_category, const std::string& norm_subcategory); std::pair find_fuzzy_match(const std::string& norm_category, const std::string& norm_subcategory) const; int resolve_existing_taxonomy(const std::string& key, const std::string& norm_category, const std::string& norm_subcategory) const; ResolvedCategory build_resolved_category(int taxonomy_id, const std::string& fallback_category, const std::string& fallback_subcategory, const std::string& norm_category, const std::string& norm_subcategory); int create_taxonomy_entry(const std::string& category, const std::string& subcategory, const std::string& norm_category, const std::string& norm_subcategory); int find_existing_taxonomy_id(const std::string& norm_category, const std::string& norm_subcategory) const; void ensure_alias_mapping(int taxonomy_id, const std::string& norm_category, const std::string& norm_subcategory); const TaxonomyEntry* find_taxonomy_entry(int taxonomy_id) const; std::map cached_results; std::string get_cached_category(const std::string &file_name); void load_cache(); bool file_exists_in_db(const std::string &file_name, const std::string &file_path); sqlite3* db; const std::string config_dir; const std::string db_file; std::vector taxonomy_entries; std::unordered_map canonical_lookup; std::unordered_map alias_lookup; std::unordered_map taxonomy_index; std::unordered_map translation_entries; std::unordered_map translation_lookup; static bool is_duplicate_category( const std::vector>& results, const std::pair& candidate); std::optional> build_recent_category_candidate( const char* file_name_text, const char* category_text, const char* subcategory_text, const std::string& normalized_extension, bool has_extension) const; }; #endif ================================================ FILE: app/include/DialogUtils.hpp ================================================ #ifndef DIALOGUTILS_HPP #define DIALOGUTILS_HPP #include class QWidget; class DialogUtils { public: static void show_error_dialog(QWidget* parent, const std::string& message); }; #endif // DIALOGUTILS_HPP ================================================ FILE: app/include/DocumentTextAnalyzer.hpp ================================================ #pragma once #include #include #include class ILLMClient; struct DocumentAnalysisResult { /** * @brief Short summary extracted from the document text. */ std::string summary; /** * @brief Suggested filename based on the analyzed content (including extension). */ std::string suggested_name; }; /** * @brief Extracts document text and produces LLM-based summaries and rename suggestions. */ class DocumentTextAnalyzer { public: /** * @brief Tuning knobs for document excerpting and filename cleanup. */ struct Settings { /** * @brief Maximum characters to include in the excerpt sent to the LLM. */ size_t max_characters = 8000; /** * @brief Maximum number of words to keep in the suggested filename. */ size_t max_filename_words = 3; /** * @brief Maximum length of the suggested filename stem. */ size_t max_filename_length = 50; /** * @brief Maximum number of tokens to generate for the response. */ int max_tokens = 256; }; /** * @brief Construct with default settings. */ DocumentTextAnalyzer(); /** * @brief Construct with custom settings. */ explicit DocumentTextAnalyzer(Settings settings); /** * @brief Analyze the document and return a summary + suggested filename. * @param document_path Path to the document to analyze. * @param llm LLM client used to generate the summary and filename. * @return Analysis result containing summary and suggested filename. */ DocumentAnalysisResult analyze(const std::filesystem::path& document_path, ILLMClient& llm) const; /** * @brief Returns true if the file extension is supported for document analysis. * @param path Document path to inspect. * @return True when the document extension is supported. */ static bool is_supported_document(const std::filesystem::path& path); /** * @brief Attempts to read a creation date from supported document metadata. * @param path Document path to inspect. * @return Creation date formatted as YYYY-MM when available. */ static std::optional extract_creation_date(const std::filesystem::path& path); private: std::string extract_text(const std::filesystem::path& path) const; std::string build_prompt(const std::string& excerpt, const std::string& file_name) const; std::string sanitize_filename(const std::string& value, size_t max_words, size_t max_length) const; static std::string normalize_filename(const std::string& base, const std::filesystem::path& original_path); static std::string trim(std::string value); static std::string slugify(const std::string& value); Settings settings_; }; ================================================ FILE: app/include/DryRunPreviewDialog.hpp ================================================ #pragma once #include #include #include #include #include class DryRunPreviewDialog : public QDialog { Q_DECLARE_TR_FUNCTIONS(DryRunPreviewDialog) public: struct Entry { std::string from_label; std::string to_label; std::string source_tooltip; std::string destination_tooltip; }; explicit DryRunPreviewDialog(const std::vector& entries, QWidget* parent = nullptr); private: void setup_ui(const std::vector& entries); QTableWidget* table_{nullptr}; }; ================================================ FILE: app/include/EmbeddedEnv.hpp ================================================ #ifndef EMBEDDED_ENV_H #define EMBEDDED_ENV_H #include #include class EmbeddedEnv { public: explicit EmbeddedEnv(const std::string& resource_path); void load_env(); private: std::string resource_path_; std::string extract_env_content(); void parse_env(const std::string& env_content); std::string trim(const std::string& str); }; #endif ================================================ FILE: app/include/ErrorMessages.hpp ================================================ /** * @file ErrorMessages.hpp * @brief Translatable error message constants used throughout the UI. */ #ifndef ERRORMESSAGES_H #define ERRORMESSAGES_H #include /** * @brief Translate a string using gettext. * @param String String literal to translate. * @return Translated string (const char* managed by gettext). */ #define _(String) gettext(String) /** * @brief Error message shown when no files are available for categorization. */ #define ERR_NO_FILES_TO_CATEGORIZE _("There are no files or directories to categorize.") /** * @brief Error message shown when the user provides an invalid path. */ #define ERR_INVALID_PATH _("Invalid directory path.") /** * @brief Error message shown when no internet connection is detected. */ #define ERR_NO_INTERNET_CONNECTION _("No internet connection. Please check your network and try again.") #endif ================================================ FILE: app/include/FileScanner.hpp ================================================ #ifndef FILE_SCANNER_HPP #define FILE_SCANNER_HPP #include #include #include #include #include "Types.hpp" namespace fs = std::filesystem; class FileScanner { public: FileScanner() = default; std::vector get_directory_entries(const std::string &directory_path, FileScanOptions options); private: struct ScanContext; void scan_non_recursive(const fs::path& scan_path, const ScanContext& context, std::vector& results); void scan_recursive(const fs::path& scan_path, const ScanContext& context, std::vector& results); void log_scan_warning(const ScanContext& context, const fs::path& path, const std::error_code& error, const char* action) const; std::optional build_entry(const fs::directory_entry& entry, const ScanContext& context); bool should_skip_entry(const fs::path& entry_path, const std::string& file_name, const ScanContext& context, const std::string& full_path) const; std::optional classify_entry(const fs::directory_entry& entry, bool bundle, bool is_directory, const ScanContext& context) const; bool is_file_hidden(const fs::path &path) const; bool is_junk_file(const std::string& name) const; bool is_file_bundle(const fs::path& path, bool is_directory) const; }; #endif ================================================ FILE: app/include/GeminiClient.hpp ================================================ #ifndef GEMINICLIENT_HPP #define GEMINICLIENT_HPP #include "ILLMClient.hpp" #include #include class GeminiClient : public ILLMClient { public: GeminiClient(std::string api_key, std::string model); ~GeminiClient() override = default; std::string categorize_file(const std::string& file_name, const std::string& file_path, FileType file_type, const std::string& consistency_context) override; std::string complete_prompt(const std::string& prompt, int max_tokens) override; void set_prompt_logging_enabled(bool enabled) override; private: std::string api_key_; std::string model_; bool prompt_logging_enabled_{false}; std::string last_prompt_; std::string send_api_request(const std::string& json_payload); std::string make_categorization_payload(const std::string& file_name, const std::string& file_path, FileType file_type, const std::string& consistency_context); std::string make_generic_payload(const std::string& system_prompt, const std::string& user_prompt, int max_tokens) const; std::string effective_model() const; }; #endif // GEMINICLIENT_HPP ================================================ FILE: app/include/GgmlRuntimePaths.hpp ================================================ #pragma once #include #include #include #include namespace GgmlRuntimePaths { bool has_payload(const std::filesystem::path& dir); std::vector macos_candidate_dirs( const std::filesystem::path& exe_path, std::string_view ggml_subdir); std::optional resolve_macos_backend_dir( const std::optional& current_dir, const std::filesystem::path& exe_path, std::string_view ggml_subdir); } // namespace GgmlRuntimePaths ================================================ FILE: app/include/ILLMClient.hpp ================================================ #pragma once #include "Types.hpp" #include class ILLMClient { public: virtual ~ILLMClient() = default; virtual std::string categorize_file(const std::string& file_name, const std::string& file_path, FileType file_type, const std::string& consistency_context) = 0; virtual std::string complete_prompt(const std::string& prompt, int max_tokens) = 0; virtual void set_prompt_logging_enabled(bool enabled) = 0; }; ================================================ FILE: app/include/ImageRenameMetadataService.hpp ================================================ #ifndef IMAGE_RENAME_METADATA_SERVICE_HPP #define IMAGE_RENAME_METADATA_SERVICE_HPP #include #include #include #include struct sqlite3; /** * @brief Enriches image rename suggestions using EXIF date + reverse-geocoded place. * * Metadata sources: * - JPEG APP1 EXIF * - TIFF native EXIF * - PNG eXIf chunk * - HEIC/HEIF via exiftool fallback (when available in PATH) */ class ImageRenameMetadataService { public: /** * @brief Creates a metadata enrichment service rooted in the given config directory. * * The directory is used to store the local reverse-geocode cache database. * * @param config_dir Base configuration directory for metadata cache files. */ explicit ImageRenameMetadataService(std::string config_dir); /** * @brief Destroys the service and releases any open cache database resources. */ ~ImageRenameMetadataService(); ImageRenameMetadataService(const ImageRenameMetadataService&) = delete; ImageRenameMetadataService& operator=(const ImageRenameMetadataService&) = delete; /** * @brief Adds metadata prefixes to a suggested image filename when available. * * Prefix order is date first, then place, e.g. `2014-03-10_venice_black_ducks.jpg`. * If EXIF metadata is missing or place lookup cannot be done, the original * suggestion is returned unchanged. * * @param image_path Absolute or relative image file path. * @param suggested_name Suggested filename generated by image analysis. * @return Suggested filename with metadata prefixes when available. */ std::string enrich_suggested_name(const std::filesystem::path& image_path, const std::string& suggested_name); /** * @brief Extracts the normalized capture date (`YYYY-MM-DD`) from image metadata. * * Returns `std::nullopt` when no supported metadata date is available. * * @param image_path Absolute or relative image file path. * @return Normalized capture date, or `std::nullopt` if unavailable. */ std::optional extract_capture_date( const std::filesystem::path& image_path) const; /** * @brief Utility used by tests and callers to compose prefixed filenames. * * @param suggested_name Base suggested filename. * @param date_prefix Optional date prefix (typically `YYYY-MM-DD`). * @param place_prefix Optional place prefix. * @return Filename prefixed with available metadata components. */ static std::string apply_prefix_to_filename(const std::string& suggested_name, const std::optional& date_prefix, const std::optional& place_prefix); private: struct ExifMetadata { std::optional capture_date; std::optional latitude; std::optional longitude; }; struct CacheLookup { bool found{false}; std::optional place; }; struct ReverseGeocodeResult { bool success{false}; std::optional place; }; /** * @brief Opens or creates the reverse-geocode cache database. * @return True when the cache database is available for use. */ bool open_cache_db(); /** * @brief Extracts supported EXIF metadata fields from an image file. * @param image_path Absolute or relative image file path. * @return Parsed metadata fields used for date/place prefixing. */ ExifMetadata extract_exif_metadata(const std::filesystem::path& image_path) const; /** * @brief Resolves a place prefix from GPS coordinates using cache and reverse geocoding. * @param latitude GPS latitude in decimal degrees. * @param longitude GPS longitude in decimal degrees. * @return Slugified place prefix, or `std::nullopt` when unavailable. */ std::optional resolve_place_prefix(double latitude, double longitude); /** * @brief Looks up a cached place prefix by coordinate keys. * @param lat_key Normalized latitude cache key. * @param lon_key Normalized longitude cache key. * @return Cache lookup result indicating hit/miss and optional place value. */ CacheLookup lookup_cache(const std::string& lat_key, const std::string& lon_key) const; /** * @brief Inserts or updates a cached place prefix for coordinate keys. * @param lat_key Normalized latitude cache key. * @param lon_key Normalized longitude cache key. * @param place Optional place prefix to store. */ void upsert_cache(const std::string& lat_key, const std::string& lon_key, const std::optional& place) const; /** * @brief Performs reverse geocoding for GPS coordinates. * @param latitude GPS latitude in decimal degrees. * @param longitude GPS longitude in decimal degrees. * @return Reverse-geocode result with success flag and optional place prefix. */ ReverseGeocodeResult reverse_geocode(double latitude, double longitude); /** * @brief Checks whether the network is available for reverse geocoding. * @return True when online requests can be attempted. */ bool network_available(); /** * @brief Converts arbitrary text into a filesystem-safe lowercase slug. * @param value Input text. * @return Sanitized slug string. */ static std::string slugify(const std::string& value); /** * @brief Normalizes EXIF date values to `YYYY-MM-DD`. * @param value Raw EXIF date text. * @return Normalized date, or `std::nullopt` if parsing fails. */ static std::optional normalize_exif_date(const std::string& value); /** * @brief Formats a floating-point coordinate into a stable cache key. * @param value Coordinate value in decimal degrees. * @return Normalized coordinate key string. */ static std::string format_coord_key(double value); std::string config_dir_; sqlite3* cache_db_{nullptr}; std::chrono::steady_clock::time_point last_geocode_request_{}; bool network_checked_{false}; bool network_available_{false}; }; #endif // IMAGE_RENAME_METADATA_SERVICE_HPP ================================================ FILE: app/include/IniConfig.hpp ================================================ #ifndef INICONFIG_HPP #define INICONFIG_HPP #include #include #include #include class IniConfig { public: bool load(const std::string &filename); std::string getValue(const std::string §ion, const std::string &key, const std::string &default_value = "") const; void setValue(const std::string §ion, const std::string &key, const std::string &value); bool save(const std::string &filename) const; bool hasValue(const std::string& section, const std::string& key) const; private: std::map> data; }; #endif ================================================ FILE: app/include/LLMClient.hpp ================================================ #ifndef LLMCLIENT_HPP #define LLMCLIENT_HPP #include "ILLMClient.hpp" #include #include class LLMClient : public ILLMClient { public: /** * @brief Create an OpenAI-compatible client, optionally targeting a custom base URL. */ LLMClient(std::string api_key, std::string model, std::string base_url = std::string()); ~LLMClient() override; std::string categorize_file(const std::string& file_name, const std::string& file_path, FileType file_type, const std::string& consistency_context) override; std::string complete_prompt(const std::string& prompt, int max_tokens) override; void set_prompt_logging_enabled(bool enabled) override; private: std::string api_key; std::string send_api_request(std::string json_payload); std::string make_payload(const std::string &file_name, const std::string &file_path, const FileType file_type, const std::string& consistency_context); std::string make_generic_payload(const std::string& system_prompt, const std::string& user_prompt, int max_tokens) const; std::string effective_model() const; /** * @brief Resolve the final /chat/completions URL from the base URL or default. */ std::string resolve_api_url() const; bool prompt_logging_enabled{false}; std::string last_prompt; std::string model; std::string base_url; }; #endif ================================================ FILE: app/include/LLMDownloader.hpp ================================================ #pragma once #include "Settings.hpp" #include #include #include #include #include #include #include #include /** * @brief Handles downloading local LLM model files with resume support. */ class LLMDownloader { public: /** * @brief Constructs a downloader for the given URL. * @param download_url URL of the model to download. */ explicit LLMDownloader(const std::string& download_url); /** * @brief Initializes curl state if not already initialized. */ void init_if_needed(); /** * @brief Returns true if initialization has completed. * @return True when initialized. */ bool is_inited(); /** * @brief Starts an async download with callbacks. * @param progress_cb Called with progress percentage (0-100). * @param on_complete_cb Called when download completes successfully. * @param on_status_text Called with status text updates. * @param on_error_cb Called with error message on failure. */ void start_download(std::function progress_cb, std::function on_complete_cb, std::function on_status_text, std::function on_error_cb); /** * @brief Attempts to resume a partial download. */ void try_resume_download(); /** * @brief Returns true if the current download can be resumed. * @return True when the download is resumable. */ bool is_download_resumable() const; /** * @brief Returns true when the file is fully downloaded. * @return True if download is complete. */ bool is_download_complete() const; /** * @brief Returns the server-reported content length. * @return Content length in bytes, or 0 if unknown. */ long long get_real_content_length() const; /** * @brief Returns the resolved destination path for the download. * @return Full path to the downloaded file. */ std::string get_download_destination() const; /** * @brief Returns the temporary path used for in-progress downloads. * @return Full path to the partial download artifact. */ std::string get_partial_download_destination() const; /** * @brief Starts a download with simpler callbacks. * @param on_progress Called with progress percentage (0-100). * @param on_complete Called with success flag and message. */ void start(std::function on_progress, std::function on_complete); /** * @brief Timestamp of last progress update (exposed for UI refresh). */ std::chrono::steady_clock::time_point last_progress_update; /** * @brief Destructor; cancels any active download thread. */ ~LLMDownloader(); /** * @brief Download status for local or remote states. */ enum class DownloadStatus { NotStarted, InProgress, Complete }; /** * @brief Returns status based on local filesystem state. * @return Local download status. */ DownloadStatus get_local_download_status() const; /** * @brief Returns the live download status. * @return Current download status. */ DownloadStatus get_download_status() const; /** * @brief Cancels an in-progress download. */ void cancel_download(); /** * @brief Updates the download URL (resets internal state). * @param new_url New URL to download from. */ void set_download_url(const std::string& new_url); /** * @brief Returns the current download URL. * @return Download URL string. */ std::string get_download_url(); #ifdef AI_FILE_SORTER_TEST_BUILD class LLMDownloaderTestAccess { public: /** * @brief Overrides the cached content length for tests. * @param downloader Downloader instance under test. * @param length Content length in bytes. */ static void set_real_content_length(LLMDownloader& downloader, long long length); /** * @brief Overrides the download destination path for tests. * @param downloader Downloader instance under test. * @param path Destination file path. */ static void set_download_destination(LLMDownloader& downloader, const std::string& path); /** * @brief Seeds resume headers for tests. * @param downloader Downloader instance under test. * @param content_length Content length in bytes. */ static void set_resume_headers(LLMDownloader& downloader, long long content_length); }; #endif private: #ifdef AI_FILE_SORTER_TEST_BUILD friend class LLMDownloaderTestAccess; #endif bool initialized{false}; std::string url; std::string destination_dir; std::thread download_thread; std::map curl_headers; mutable std::mutex mutex; std::function progress_callback; std::function on_download_complete; std::function on_status_text; std::function on_download_error; bool resumable{false}; long long real_content_length{0}; std::string download_destination; /** * @brief Curl write callback for file download. * @param ptr Data buffer. * @param size Element size. * @param nmemb Element count. * @param stream Output file stream. * @return Bytes written. */ static size_t write_data(void* ptr, size_t size, size_t nmemb, FILE* stream); /** * @brief Curl callback that discards data (used for head requests). * @param ptr Data buffer. * @param size Element size. * @param nmemb Element count. * @param userdata User data. * @return Bytes processed. */ static size_t discard_callback(char *ptr, size_t size, size_t nmemb, void *userdata); /** * @brief Curl header callback to parse response headers. * @param buffer Header buffer. * @param size Element size. * @param nitems Element count. * @param userdata User data. * @return Bytes processed. */ static size_t header_callback(char *buffer, size_t size, size_t nitems, void *userdata); /** * @brief Curl progress callback for download updates. * @param clientp User data. * @param dltotal Total bytes. * @param dlnow Bytes downloaded. * @return 0 to continue, non-zero to abort. */ static int progress_func(void* clientp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t, curl_off_t); /** * @brief Returns the default directory for storing downloaded LLMs. * @return Path to default LLM download directory. */ std::string get_default_llm_destination(); /** * @brief Computes and stores the download destination file path. */ void set_download_destination(); /** * @brief Path to cached metadata file. * @return Metadata file path. */ std::string metadata_path() const; /** * @brief Path to the partial download file used during transfer/resume. * @return Temporary file path. */ std::string partial_download_path() const; /** * @brief Loads cached metadata for resume and progress. */ void load_cached_metadata(); /** * @brief Persists metadata to disk. */ void persist_cached_metadata() const; /** * @brief Moves legacy partial downloads from the final path into the temp path. */ void migrate_legacy_partial_download_if_needed(); /** * @brief Parses cached or response headers for resume support. */ void parse_headers(); /** * @brief Executes the download in the worker thread. */ void perform_download(); /** * @brief Marks the download as resumable. */ void mark_download_resumable(); /** * @brief Notifies subscribers that the download finished. */ void notify_download_complete(); /** * @brief Applies common curl options shared across requests. * @param curl Curl handle. */ void setup_common_curl_options(CURL *curl); /** * @brief Applies curl options for header probing. * @param curl Curl handle. */ void setup_header_curl_options(CURL *curl); /** * @brief Applies curl options for the download request. * @param curl Curl handle. * @param fp File pointer for output. * @param resume_offset Resume offset in bytes. */ void setup_download_curl_options(CURL *curl, FILE *fp, long resume_offset); /** * @brief Determines the byte offset for resuming downloads. * @return Resume offset in bytes. */ long determine_resume_offset() const; /** * @brief Opens the output file at the given resume offset. * @param resume_offset Resume offset in bytes. * @return File pointer or nullptr on failure. */ FILE *open_output_file(long resume_offset) const; /** * @brief Returns true if a partial download exists. * @return True when a partial download exists. */ bool has_existing_partial_download() const; /** * @brief Returns true when the server supports resuming downloads. * @return True when resume is supported. */ bool server_supports_resume_locked() const; /** * @brief Validates a content-length header value. * @param value Header string. * @return True when the value is a valid content length. */ bool has_valid_content_length(const std::string& value) const; std::atomic cancel_requested{false}; long resume_offset = 0; }; ================================================ FILE: app/include/LLMErrors.hpp ================================================ #ifndef LLM_ERRORS_HPP #define LLM_ERRORS_HPP #include #include class BackoffError : public std::runtime_error { public: BackoffError(const std::string& message, int retry_seconds) : std::runtime_error(message), retry_after_seconds_(retry_seconds) {} int retry_after_seconds() const { return retry_after_seconds_; } private: int retry_after_seconds_{0}; }; #endif // LLM_ERRORS_HPP ================================================ FILE: app/include/LLMSelectionDialog.hpp ================================================ #ifndef LLMSELECTIONDIALOG_HPP #define LLMSELECTIONDIALOG_HPP #include "LLMDownloader.hpp" #include "Types.hpp" #include #include #include #include #include #include class QLabel; class QProgressBar; class QPushButton; class QRadioButton; class QDialogButtonBox; class QWidget; class QString; class QComboBox; class QListWidget; class QLineEdit; class QCheckBox; class QToolButton; class QScrollArea; class QShowEvent; class Settings; #ifdef AI_FILE_SORTER_TEST_BUILD class LLMSelectionDialogTestAccess; #endif class LLMSelectionDialog : public QDialog { Q_DECLARE_TR_FUNCTIONS(LLMSelectionDialog) public: explicit LLMSelectionDialog(Settings& settings, QWidget* parent = nullptr); ~LLMSelectionDialog() override; LLMChoice get_selected_llm_choice() const; std::string get_selected_custom_llm_id() const; /** * @brief Return the active custom API endpoint id. */ std::string get_selected_custom_api_id() const; std::string get_openai_api_key() const; std::string get_openai_model() const; std::string get_gemini_api_key() const; std::string get_gemini_model() const; bool get_llm_downloads_expanded() const; private: #ifdef AI_FILE_SORTER_TEST_BUILD friend class LLMSelectionDialogTestAccess; #endif struct VisualLlmDownloadEntry { std::string env_var; std::string display_name; QWidget* container{nullptr}; QLabel* title_label{nullptr}; QLabel* remote_url_label{nullptr}; QLabel* local_path_label{nullptr}; QLabel* file_size_label{nullptr}; QLabel* status_label{nullptr}; QProgressBar* progress_bar{nullptr}; QPushButton* download_button{nullptr}; QPushButton* delete_button{nullptr}; std::unique_ptr downloader; std::atomic is_downloading{false}; }; void setup_ui(); void connect_signals(); void showEvent(QShowEvent* event) override; void update_ui_for_choice(); void update_legacy_local_3b_visibility(); void update_radio_selection(); void update_custom_choice_ui(); /** * @brief Update UI state for the custom API selection. */ void update_custom_api_choice_ui(); void update_openai_fields_state(); void update_gemini_fields_state(); bool openai_inputs_valid() const; bool gemini_inputs_valid() const; void update_local_choice_ui(); void update_download_info(); void start_download(); /** * @brief Delete the downloaded local LLM file after confirmation. */ void handle_delete_download(); void refresh_downloader(); void set_status_message(const QString& message); std::string current_download_env_var() const; void refresh_custom_lists(); /** * @brief Refresh the custom API dropdown list. */ void refresh_custom_api_lists(); void handle_add_custom(); void handle_edit_custom(); void handle_delete_custom(); void update_custom_buttons(); void select_custom_by_id(const std::string& id); /** * @brief Open the dialog to add a custom API entry. */ void handle_add_custom_api(); /** * @brief Open the dialog to edit the selected custom API entry. */ void handle_edit_custom_api(); /** * @brief Remove the selected custom API entry. */ void handle_delete_custom_api(); /** * @brief Update enabled states for custom API controls. */ void update_custom_api_buttons(); /** * @brief Select a custom API entry by id. */ void select_custom_api_by_id(const std::string& id); /** * @brief Recalculate the dialog size based on visible content. */ void adjust_dialog_size(); void setup_visual_llm_download_entry(VisualLlmDownloadEntry& entry, QWidget* parent, const QString& title, const std::string& env_var); void refresh_visual_llm_download_entry(VisualLlmDownloadEntry& entry); void update_visual_llm_download_entry(VisualLlmDownloadEntry& entry); void update_visual_llm_downloads(); void start_visual_llm_download(VisualLlmDownloadEntry& entry); /** * @brief Delete a downloaded visual LLM bundle after confirmation. * @param entry Visual LLM entry to delete. */ void handle_delete_visual_download(VisualLlmDownloadEntry& entry); void set_visual_status_message(VisualLlmDownloadEntry& entry, const QString& message); bool legacy_local_3b_available() const; Settings& settings; LLMChoice selected_choice{LLMChoice::Unset}; std::string selected_custom_id; std::string selected_custom_api_id; std::string openai_api_key; std::string openai_model; std::string gemini_api_key; std::string gemini_model; bool downloads_expanded_{true}; QRadioButton* openai_radio{nullptr}; QRadioButton* gemini_radio{nullptr}; QRadioButton* custom_api_radio{nullptr}; QRadioButton* local3_radio{nullptr}; QRadioButton* local3_legacy_radio{nullptr}; QRadioButton* local7_radio{nullptr}; QRadioButton* custom_radio{nullptr}; QToolButton* download_toggle_button{nullptr}; QScrollArea* scroll_area_{nullptr}; QComboBox* custom_combo{nullptr}; QPushButton* add_custom_button{nullptr}; QPushButton* edit_custom_button{nullptr}; QPushButton* delete_custom_button{nullptr}; QComboBox* custom_api_combo{nullptr}; QPushButton* add_custom_api_button{nullptr}; QPushButton* edit_custom_api_button{nullptr}; QPushButton* delete_custom_api_button{nullptr}; QLabel* remote_url_label{nullptr}; QLabel* local_path_label{nullptr}; QLabel* file_size_label{nullptr}; QLabel* status_label{nullptr}; QLabel* local3_legacy_desc{nullptr}; QProgressBar* progress_bar{nullptr}; QPushButton* download_button{nullptr}; QPushButton* delete_download_button{nullptr}; QPushButton* ok_button{nullptr}; QDialogButtonBox* button_box{nullptr}; QWidget* downloads_container{nullptr}; QWidget* download_section{nullptr}; QWidget* visual_llm_download_section{nullptr}; QWidget* openai_inputs{nullptr}; QWidget* gemini_inputs{nullptr}; QLineEdit* openai_api_key_edit{nullptr}; QLineEdit* openai_model_edit{nullptr}; QLineEdit* gemini_api_key_edit{nullptr}; QLineEdit* gemini_model_edit{nullptr}; QCheckBox* show_openai_api_key_checkbox{nullptr}; QCheckBox* show_gemini_api_key_checkbox{nullptr}; QLabel* openai_help_label{nullptr}; QLabel* openai_link_label{nullptr}; QLabel* gemini_help_label{nullptr}; QLabel* gemini_link_label{nullptr}; std::unique_ptr downloader; std::atomic is_downloading{false}; std::mutex download_mutex; VisualLlmDownloadEntry llava_model_download; VisualLlmDownloadEntry llava_mmproj_download; #if defined(AI_FILE_SORTER_TEST_BUILD) bool use_network_available_override_{false}; bool network_available_override_{true}; #endif }; #endif // LLMSELECTIONDIALOG_HPP ================================================ FILE: app/include/LLMSelectionDialogTestAccess.hpp ================================================ #pragma once #ifdef AI_FILE_SORTER_TEST_BUILD #include #include #include #include class LLMDownloader; class LLMSelectionDialog; class LLMSelectionDialogTestAccess { public: struct VisualEntryRefs { QLabel* status_label{nullptr}; QPushButton* download_button{nullptr}; QProgressBar* progress_bar{nullptr}; LLMDownloader* downloader{nullptr}; }; static VisualEntryRefs llava_model_entry(LLMSelectionDialog& dialog); static VisualEntryRefs llava_mmproj_entry(LLMSelectionDialog& dialog); static void refresh_visual_downloads(LLMSelectionDialog& dialog); static void update_llava_model_entry(LLMSelectionDialog& dialog); static void start_llava_model_download(LLMSelectionDialog& dialog); static void set_network_available_override(LLMSelectionDialog& dialog, std::optional value); }; #endif // AI_FILE_SORTER_TEST_BUILD ================================================ FILE: app/include/Language.hpp ================================================ #ifndef LANGUAGE_HPP #define LANGUAGE_HPP #include enum class Language { English, French, German, Italian, Spanish, Turkish, Korean, Dutch }; inline QString languageToString(Language language) { switch (language) { case Language::German: return QStringLiteral("German"); case Language::Italian: return QStringLiteral("Italian"); case Language::Spanish: return QStringLiteral("Spanish"); case Language::Turkish: return QStringLiteral("Turkish"); case Language::Korean: return QStringLiteral("Korean"); case Language::Dutch: return QStringLiteral("Dutch"); case Language::French: return QStringLiteral("French"); case Language::English: default: return QStringLiteral("English"); } } inline Language languageFromString(const QString& value) { const QString lowered = value.toLower(); if (lowered == QStringLiteral("french") || lowered == QStringLiteral("fr")) { return Language::French; } if (lowered == QStringLiteral("german") || lowered == QStringLiteral("de")) { return Language::German; } if (lowered == QStringLiteral("italian") || lowered == QStringLiteral("it")) { return Language::Italian; } if (lowered == QStringLiteral("spanish") || lowered == QStringLiteral("es")) { return Language::Spanish; } if (lowered == QStringLiteral("turkish") || lowered == QStringLiteral("tr")) { return Language::Turkish; } if (lowered == QStringLiteral("korean") || lowered == QStringLiteral("ko")) { return Language::Korean; } if (lowered == QStringLiteral("dutch") || lowered == QStringLiteral("nl")) { return Language::Dutch; } return Language::English; } #endif // LANGUAGE_HPP ================================================ FILE: app/include/LlamaModelParams.hpp ================================================ #pragma once #include "llama.h" #include #include namespace spdlog { class logger; } llama_model_params build_model_params_for_path(const std::string& model_path, const std::shared_ptr& logger); ================================================ FILE: app/include/LlavaImageAnalyzer.hpp ================================================ #pragma once #include #include #include #include #include #include #ifdef AI_FILE_SORTER_HAS_MTMD #include "ggml.h" struct llama_model; struct llama_context; struct llama_vocab; struct mtmd_context; struct mtmd_bitmap; #endif /** * @brief Result returned by LlavaImageAnalyzer. */ struct LlavaImageAnalysisResult { /** * @brief Natural language description of the image contents. */ std::string description; /** * @brief Suggested filename derived from the description. */ std::string suggested_name; }; /** * @brief Runs local LLaVA inference to describe images and suggest filenames. */ class LlavaImageAnalyzer { public: /** * @brief Analyzer configuration for LLaVA inference. */ struct Settings { /** @brief Context length (tokens). */ int32_t n_ctx = 4096; /** @brief Maximum tokens to predict. */ int32_t n_predict = 80; /** @brief Number of CPU threads to use (0 = auto). */ int32_t n_threads = 0; /** @brief Sampling temperature. */ float temperature = 0.2f; /** @brief Whether to use GPU acceleration. */ bool use_gpu = true; /** @brief Enable verbose visual model logging. */ bool log_visual_output = false; /** * @brief Optional callback for image batch progress. * @param current_batch Batch index (1-based). * @param total_batches Total number of batches. */ std::function batch_progress; }; /** * @brief Constructs the analyzer with explicit settings. * @param model_path Path to the LLaVA text model (GGUF). * @param mmproj_path Path to the LLaVA mmproj file (GGUF). * @param settings Inference settings. */ LlavaImageAnalyzer(const std::filesystem::path& model_path, const std::filesystem::path& mmproj_path, Settings settings); /** * @brief Constructs the analyzer with default settings. * @param model_path Path to the LLaVA text model (GGUF). * @param mmproj_path Path to the LLaVA mmproj file (GGUF). */ LlavaImageAnalyzer(const std::filesystem::path& model_path, const std::filesystem::path& mmproj_path); /** * @brief Destructor; releases model resources. */ ~LlavaImageAnalyzer(); LlavaImageAnalyzer(const LlavaImageAnalyzer&) = delete; LlavaImageAnalyzer& operator=(const LlavaImageAnalyzer&) = delete; /** * @brief Analyze an image and return description + filename suggestion. * @param image_path Path to the image file. * @return Analysis result with description and suggested name. */ LlavaImageAnalysisResult analyze(const std::filesystem::path& image_path); /** * @brief Returns true if the image path has a supported extension. * @param path Path to inspect. * @return True when the file is supported. */ static bool is_supported_image(const std::filesystem::path& path); private: /** * @brief Builds the description prompt for the visual model. * @return Prompt string. */ std::string build_description_prompt() const; /** * @brief Builds the filename prompt from an image description. * @param description Model-generated description. * @return Prompt string. */ std::string build_filename_prompt(const std::string& description) const; #ifdef AI_FILE_SORTER_HAS_MTMD /** * @brief Runs inference on the given bitmap. * @param bitmap Input bitmap. * @param prompt Prompt to run. * @param max_tokens Maximum tokens to generate. * @return Model response text. */ std::string infer_text(mtmd_bitmap* bitmap, const std::string& prompt, int32_t max_tokens); #else /** * @brief Runs inference on the given bitmap (stub for non-MTMD builds). * @param bitmap Input bitmap. * @param prompt Prompt to run. * @param max_tokens Maximum tokens to generate. * @return Model response text. */ std::string infer_text(void* bitmap, const std::string& prompt, int32_t max_tokens); #endif /** * @brief Sanitizes a suggested filename. * @param value Raw suggested filename. * @param max_words Max number of words. * @param max_length Max character length. * @return Sanitized filename. */ std::string sanitize_filename(const std::string& value, size_t max_words, size_t max_length) const; /** * @brief Trims whitespace from both ends of a string. * @param value Input string. * @return Trimmed string. */ static std::string trim(std::string value); /** * @brief Converts a string into a slug safe for filenames. * @param value Input string. * @return Slugified string. */ static std::string slugify(const std::string& value); /** * @brief Normalizes a filename based on the original image path. * @param base Base filename. * @param original_path Path to the original image. * @return Normalized filename. */ static std::string normalize_filename(const std::string& base, const std::filesystem::path& original_path); #ifdef AI_FILE_SORTER_HAS_MTMD llama_model* model_{nullptr}; llama_context* context_{nullptr}; mtmd_context* vision_ctx_{nullptr}; const llama_vocab* vocab_{nullptr}; std::filesystem::path model_path_; std::filesystem::path mmproj_path_; std::optional visual_gpu_override_; int32_t context_tokens_{0}; int32_t batch_size_{512}; bool text_gpu_enabled_{false}; bool mmproj_gpu_enabled_{false}; void initialize_context(); void reset_context_state(); static void mtmd_progress_callback(const char* name, int32_t current_batch, int32_t total_batches, void* user_data); #if defined(AI_FILE_SORTER_MTMD_LOG_CALLBACK) /** * @brief Optional MTMD log callback. * @param level Log level. * @param text Log message. * @param user_data User data pointer. */ static void mtmd_log_callback(enum ggml_log_level level, const char* text, void* user_data); #endif #endif /** * @brief Stored analyzer settings. */ Settings settings_; }; #ifdef AI_FILE_SORTER_TEST_BUILD namespace LlavaImageAnalyzerTestAccess { int32_t default_visual_batch_size(bool gpu_enabled, std::string_view backend_name); int32_t visual_model_n_gpu_layers_for_model(const std::string& model_path); } #endif ================================================ FILE: app/include/LlmCatalog.hpp ================================================ #ifndef LLMCATALOG_HPP #define LLMCATALOG_HPP #include "Settings.hpp" #include #include /** * @brief Metadata for default local LLM downloads and labels. */ struct DefaultLlmEntry { LLMChoice choice; const char* url_env; const char* name_env; const char* fallback_name; }; /** * @brief Returns the default local LLM entries in priority order. * @return List of default local LLM entries. */ const std::vector& default_llm_entries(); /** * @brief Builds the UI label for a default local LLM entry. * @param entry Default LLM entry definition. * @return Localized label for display in UI/benchmark output. */ QString default_llm_label(const DefaultLlmEntry& entry); /** * @brief Builds the UI label for a default local LLM choice. * @param choice LLM choice identifier. * @return Localized label, or a generic label when not found. */ QString default_llm_label_for_choice(LLMChoice choice); #endif // LLMCATALOG_HPP ================================================ FILE: app/include/LocalLLMClient.hpp ================================================ #pragma once #include "ILLMClient.hpp" #include "Types.hpp" #include "llama.h" #include #include #include namespace spdlog { class logger; } class LocalLLMClient : public ILLMClient { public: /** * @brief Status events emitted by the local LLM client. */ enum class Status { /** * @brief GPU backend initialization failed; the client fell back to CPU. */ GpuFallbackToCpu }; /** * @brief Callback invoked when the local LLM client emits a status event. * @param status Status event emitted by the client. */ using StatusCallback = std::function; /** * @brief Callback invoked when a GPU failure occurs to decide whether to retry on CPU. * @param reason Short description of the failure cause. * @return True to retry on CPU; false to abort. */ using FallbackDecisionCallback = std::function; explicit LocalLLMClient(const std::string& model_path, FallbackDecisionCallback fallback_decision_callback = {}); ~LocalLLMClient(); std::string make_prompt(const std::string& file_name, const std::string& file_path, FileType file_type, const std::string& consistency_context); std::string generate_response(const std::string& prompt, int n_predict, bool apply_sanitizer = true, const std::string& system_prompt = {}); std::string categorize_file(const std::string& file_name, const std::string& file_path, FileType file_type, const std::string& consistency_context) override; std::string complete_prompt(const std::string& prompt, int max_tokens) override; void set_prompt_logging_enabled(bool enabled) override; /** * @brief Registers a status callback for runtime events. * @param callback Callback to invoke when status events occur. */ void set_status_callback(StatusCallback callback); /** * @brief Registers a callback to decide whether GPU failures should fall back to CPU. * @param callback Callback to invoke when a GPU failure is detected. */ void set_fallback_decision_callback(FallbackDecisionCallback callback); private: void load_model_if_needed(); void configure_llama_logging(const std::shared_ptr& logger) const; llama_model_params prepare_model_params(const std::shared_ptr& logger); llama_model_params load_model_or_throw(llama_model_params model_params, const std::shared_ptr& logger); void configure_context(int context_length, const llama_model_params& model_params); /** * @brief Emits a status event to the registered callback. * @param status Status event to emit. */ void notify_status(Status status) const; std::string model_path; llama_model* model; llama_context* ctx; const llama_vocab *vocab; llama_sampler* smpl; std::string sanitize_output(const std::string& output); llama_context_params ctx_params; bool prompt_logging_enabled{false}; StatusCallback status_callback_; FallbackDecisionCallback fallback_decision_callback_; }; ================================================ FILE: app/include/LocalLLMTestAccess.hpp ================================================ #pragma once #ifdef AI_FILE_SORTER_TEST_BUILD #include #include "llama.h" namespace LocalLLMTestAccess { enum class BackendPreference { Auto, Cpu, Cuda, Vulkan }; BackendPreference detect_preferred_backend(); bool apply_cpu_backend(llama_model_params& params, BackendPreference preference); bool apply_vulkan_backend(const std::string& model_path, llama_model_params& params); bool handle_cuda_forced_off(bool cuda_forced_off, BackendPreference preference, llama_model_params& params); bool configure_cuda_backend(const std::string& model_path, llama_model_params& params); llama_model_params prepare_model_params_for_testing(const std::string& model_path); std::string sanitize_output_for_testing(const std::string& output); } // namespace LocalLLMTestAccess #endif // AI_FILE_SORTER_TEST_BUILD ================================================ FILE: app/include/Logger.hpp ================================================ #ifndef LOGGER_HPP #define LOGGER_HPP #include #include #include #include #include class Logger { public: static std::string get_log_directory(); static void setup_loggers(); static std::shared_ptr get_logger(const std::string &name); static std::string get_log_file_path(const std::string &log_dir, const std::string &log_name); private: static std::string get_xdg_cache_home(); static std::string get_windows_log_directory(); Logger() = delete; }; #endif ================================================ FILE: app/include/MainApp.hpp ================================================ #ifndef MAINAPP_HPP #define MAINAPP_HPP #include "CategorizationDialog.hpp" #include "CategorizationProgressDialog.hpp" #include "DatabaseManager.hpp" #include "CategorizationService.hpp" #include "ConsistencyPassService.hpp" #include "ResultsCoordinator.hpp" #include "FileScanner.hpp" #include "ILLMClient.hpp" #include "Settings.hpp" #include "WhitelistStore.hpp" #include "UiTranslator.hpp" #include "UndoManager.hpp" #include #include #include #include #include #include #include #include "Language.hpp" #include #include #include #include #include #include #include #include class QAction; class QCheckBox; class QRadioButton; class QComboBox; class QLabel; class QDockWidget; class QFileSystemModel; class QLineEdit; class QString; class QPushButton; class QToolButton; class QTreeView; class QStackedWidget; class QWidget; class QLabel; class QEvent; class MainAppUiBuilder; class WhitelistManagerDialog; class SuitabilityBenchmarkDialog; struct CategorizedFile; struct FileEntry; #ifdef AI_FILE_SORTER_TEST_BUILD class MainAppTestAccess; #endif /** * @brief Main Qt window coordinating scanning, categorization, and review flows. */ class MainApp : public QMainWindow { Q_DECLARE_TR_FUNCTIONS(MainApp) public: /** * @brief Outcome returned from the optional support prompt flow. */ enum class SupportPromptResult { Support, NotSure }; /** * @brief Constructs the main application window. * @param settings Persistent settings store used by the window. * @param development_mode True to enable development-only UI features. * @param parent Optional parent widget. */ explicit MainApp(Settings& settings, bool development_mode, QWidget* parent = nullptr); /** * @brief Destroys the main window and releases owned resources. */ ~MainApp() override; /** * @brief Shows the main window and starts normal interactive use. */ void run(); /** * @brief Requests application shutdown and stops any active analysis work. */ void shutdown(); /** * @brief Opens the results review dialog for a completed categorization batch. * @param categorized_files Files to display in the review dialog. */ void show_results_dialog(const std::vector& categorized_files); /** * @brief Shows a user-facing error dialog. * @param message Error text to display. */ void show_error_dialog(const std::string& message); /** * @brief Appends a progress message to the active progress UI. * @param message Progress text to report. */ void report_progress(const std::string& message); /** * @brief Requests cancellation of the currently running analysis, if any. */ void request_stop_analysis(); /** * @brief Returns the currently selected folder path from the UI. * @return Folder path as UTF-8 text. */ std::string get_folder_path() const; /** * @brief Returns whether the window is running in development mode. * @return True when development-only features are enabled. */ bool is_development_mode() const { return development_mode_; } protected: /** * @brief Persists window state and handles shutdown when the window closes. * @param event Qt close event being processed. */ void closeEvent(QCloseEvent* event) override; private: void setup_file_explorer(); void create_file_explorer_dock(); void setup_file_system_model(); void setup_file_explorer_view(); void connect_file_explorer_signals(); void apply_file_explorer_preferences(); void restore_tree_settings(); void restore_sort_folder_state(); void restore_file_scan_options(); void restore_file_explorer_visibility(); void restore_development_preferences(); void connect_signals(); void connect_folder_contents_signals(); void connect_checkbox_signals(); void connect_whitelist_signals(); void connect_edit_actions(); void start_updater(); void set_app_icon(); void load_settings(); void save_settings(); void sync_settings_to_ui(); void sync_ui_to_settings(); void retranslate_ui(); void on_language_selected(Language language); void on_category_language_selected(CategoryLanguage language); void initialize_whitelists(); void on_analyze_clicked(); void on_directory_selected(const QString& path, bool user_initiated = false); void ensure_one_checkbox_active(QCheckBox* changed_checkbox); void update_file_scan_option(FileScanOptions option, bool enabled); bool visual_llm_files_available() const; /** * @brief Enables/disables image analysis-related UI controls based on settings/state. */ void update_image_analysis_controls(); /** * @brief Updates the "process images only" toggle behavior and dependent controls. */ void update_image_only_controls(); /** * @brief Enables/disables document analysis-related UI controls based on settings/state. */ void update_document_analysis_controls(); /** * @brief Handles the main image-analysis checkbox toggling. * @param checked True when image analysis is enabled. */ void handle_image_analysis_toggle(bool checked); /** * @brief Opens the LLM selection dialog focused on visual model downloads. */ void run_llm_selection_dialog_for_visual(); void update_analyze_button_state(bool analyzing); void update_results_view_mode(); void update_folder_contents(const QString& directory); void focus_file_explorer_on_path(const QString& path); void handle_analysis_finished(); void handle_analysis_cancelled(); void handle_analysis_failure(const std::string& message); void handle_no_files_to_sort(); void populate_tree_view(const std::vector& files); void perform_analysis(); void stop_running_analysis(); void show_llm_selection_dialog(); void on_about_activate(); void append_progress(const std::string& message); void configure_progress_stages(const std::vector& stages); void set_progress_stage_items(CategorizationProgressDialog::StageId stage_id, const std::vector& items); void set_progress_active_stage(CategorizationProgressDialog::StageId stage_id); void mark_progress_stage_item_in_progress(CategorizationProgressDialog::StageId stage_id, const FileEntry& entry); void mark_progress_stage_item_completed(CategorizationProgressDialog::StageId stage_id, const FileEntry& entry); bool should_abort_analysis() const; void prune_empty_cached_entries_for(const std::string& directory_path); void log_cached_highlights(); void log_pending_queue(); void run_consistency_pass(); void handle_development_prompt_logging(bool checked); void record_categorized_metrics(int count); SupportPromptResult show_support_prompt_dialog(int categorized_files); void undo_last_run(); bool perform_undo_from_plan(const QString& plan_path); void show_suitability_benchmark_dialog(bool auto_start); void maybe_show_suitability_benchmark(); std::unique_ptr make_llm_client(); void notify_recategorization_reset(const std::vector& entries, const std::string& reason); void notify_recategorization_reset(const CategorizedFile& entry, const std::string& reason); void set_categorization_style(bool use_consistency); bool ensure_folder_categorization_style(const std::string& folder_path); void show_whitelist_manager(); void apply_whitelist_to_selector(); void run_on_ui(std::function func); void run_on_ui_blocking(std::function func); void changeEvent(QEvent* event) override; FileScanOptions effective_scan_options() const; bool prompt_text_cpu_fallback(const std::string& reason); friend class MainAppUiBuilder; #ifdef AI_FILE_SORTER_TEST_BUILD friend class MainAppTestAccess; #endif Settings& settings; DatabaseManager db_manager; FileScanner dirscanner; bool using_local_llm{false}; std::vector already_categorized_files; std::vector new_files_with_categories; std::vector files_to_categorize; std::vector new_files_to_sort; QPointer path_entry; QPointer analyze_button; QPointer browse_button; QPointer path_label; QPointer use_subcategories_checkbox; QPointer categorization_style_heading; QPointer categorization_style_refined_radio; QPointer categorization_style_consistent_radio; QPointer use_whitelist_checkbox; QPointer whitelist_selector; QPointer categorize_files_checkbox; QPointer categorize_directories_checkbox; QPointer include_subdirectories_checkbox; QPointer analyze_images_checkbox; QPointer process_images_only_checkbox; QPointer add_image_date_to_category_checkbox; QPointer add_image_date_place_to_filename_checkbox; QPointer add_audio_video_metadata_to_filename_checkbox; QPointer offer_rename_images_checkbox; QPointer rename_images_only_checkbox; QPointer image_options_toggle_button; QPointer image_options_container; QPointer analyze_documents_checkbox; QPointer process_documents_only_checkbox; QPointer offer_rename_documents_checkbox; QPointer rename_documents_only_checkbox; QPointer add_document_date_to_category_checkbox; QPointer document_options_toggle_button; QPointer document_options_container; QPointer tree_view; QPointer tree_model; QPointer results_stack; QPointer folder_contents_view; QPointer folder_contents_model; int tree_view_page_index_{-1}; int folder_view_page_index_{-1}; QPointer file_explorer_dock; QPointer file_explorer_view; QPointer file_system_model; QAction* file_explorer_menu_action{nullptr}; QMenu* file_menu{nullptr}; QMenu* edit_menu{nullptr}; QMenu* view_menu{nullptr}; QMenu* settings_menu{nullptr}; QMenu* development_menu{nullptr}; QMenu* development_settings_menu{nullptr}; QMenu* language_menu{nullptr}; QMenu* category_language_menu{nullptr}; QMenu* help_menu{nullptr}; QAction* file_quit_action{nullptr}; QAction* run_benchmark_action{nullptr}; QAction* copy_action{nullptr}; QAction* cut_action{nullptr}; QAction* paste_action{nullptr}; QAction* delete_action{nullptr}; QAction* undo_last_run_action{nullptr}; QAction* toggle_explorer_action{nullptr}; QAction* toggle_llm_action{nullptr}; QAction* manage_whitelists_action{nullptr}; QAction* development_prompt_logging_action{nullptr}; QAction* consistency_pass_action{nullptr}; QActionGroup* language_group{nullptr}; QAction* english_action{nullptr}; QAction* dutch_action{nullptr}; QAction* french_action{nullptr}; QAction* german_action{nullptr}; QAction* italian_action{nullptr}; QAction* spanish_action{nullptr}; QAction* turkish_action{nullptr}; QAction* korean_action{nullptr}; QActionGroup* category_language_group{nullptr}; QAction* category_language_dutch{nullptr}; QAction* category_language_english{nullptr}; QAction* category_language_french{nullptr}; QAction* category_language_german{nullptr}; QAction* category_language_italian{nullptr}; QAction* category_language_polish{nullptr}; QAction* category_language_portuguese{nullptr}; QAction* category_language_spanish{nullptr}; QAction* category_language_turkish{nullptr}; QAction* about_action{nullptr}; QAction* about_qt_action{nullptr}; QAction* about_agpl_action{nullptr}; QAction* support_project_action{nullptr}; std::unique_ptr categorization_dialog; std::unique_ptr progress_dialog; std::unique_ptr benchmark_dialog; std::shared_ptr core_logger; std::shared_ptr ui_logger; WhitelistStore whitelist_store; std::unique_ptr whitelist_dialog; CategorizationService categorization_service; ConsistencyPassService consistency_pass_service; ResultsCoordinator results_coordinator; UndoManager undo_manager_; bool development_mode_{false}; bool development_prompt_logging_enabled_{false}; FileScanOptions file_scan_options{FileScanOptions::None}; std::thread analyze_thread; std::atomic stop_analysis{false}; bool analysis_in_progress_{false}; bool status_is_ready_{true}; bool suppress_explorer_sync_{false}; bool suppress_folder_view_sync_{false}; bool donation_prompt_active_{false}; std::optional text_cpu_fallback_choice_; bool should_log_prompts() const; void apply_development_logging(); std::unique_ptr ui_translator_; #if defined(AI_FILE_SORTER_TEST_BUILD) std::function visual_llm_available_probe_; std::function llm_selection_runner_override_; std::function image_analysis_prompt_override_; #endif }; #endif // MAINAPP_HPP class WhitelistManagerDialog; ================================================ FILE: app/include/MainAppEditActions.hpp ================================================ #ifndef MAIN_APP_EDIT_ACTIONS_HPP #define MAIN_APP_EDIT_ACTIONS_HPP #include class QLineEdit; class MainAppEditActions { public: static void on_paste(QLineEdit* line_edit); static void on_copy(QLineEdit* line_edit); static void on_cut(QLineEdit* line_edit); static void on_delete(QLineEdit* line_edit); private: static void copy_to_clipboard(const QString& text); static QString get_selection(QLineEdit* line_edit, bool delete_selection); }; #endif ================================================ FILE: app/include/MainAppHelpActions.hpp ================================================ #ifndef MAIN_APP_HELP_ACTIONS_HPP #define MAIN_APP_HELP_ACTIONS_HPP #include class QWidget; class MainAppHelpActions { public: static void show_about(QWidget* parent); static void show_agpl_info(QWidget* parent); static QString support_page_url(); static bool open_support_page(); }; #endif // MAIN_APP_HELP_ACTIONS_HPP ================================================ FILE: app/include/MainAppTestAccess.hpp ================================================ /** * @file MainAppTestAccess.hpp * @brief Test-only accessors and helpers for MainApp. */ #pragma once #ifdef AI_FILE_SORTER_TEST_BUILD #include "Types.hpp" #include #include #include #include #include #include #include class MainApp; class Settings; /** * @brief Provides test access to MainApp internals and helpers. */ class MainAppTestAccess { public: /** * @brief Simulated responses for the support prompt flow. */ enum class SimulatedSupportResult { /// User entered a valid donation code and hid the prompt. Support, /// User is unsure. NotSure }; /** * @brief Read the analyze button label text. * @param app MainApp instance. * @return Current analyze button text. */ static QString analyze_button_text(const MainApp& app); /** * @brief Read the folder/path label text. * @param app MainApp instance. * @return Current path label text. */ static QString path_label_text(const MainApp& app); /** * @brief Access the \"Categorize files\" checkbox. * @param app MainApp instance. * @return Pointer to the checkbox, or nullptr if unavailable. */ static QCheckBox* categorize_files_checkbox(MainApp& app); /** * @brief Access the \"Analyze picture files\" checkbox. * @param app MainApp instance. * @return Pointer to the checkbox, or nullptr if unavailable. */ static QCheckBox* analyze_images_checkbox(MainApp& app); /** * @brief Access the \"Process picture files only\" checkbox. * @param app MainApp instance. * @return Pointer to the checkbox, or nullptr if unavailable. */ static QCheckBox* process_images_only_checkbox(MainApp& app); /** * @brief Access the \"Add image creation date to category name\" checkbox. * @param app MainApp instance. * @return Pointer to the checkbox, or nullptr if unavailable. */ static QCheckBox* add_image_date_to_category_checkbox(MainApp& app); /** * @brief Access the \"Add photo date and place to filename\" checkbox. * @param app MainApp instance. * @return Pointer to the checkbox, or nullptr if unavailable. */ static QCheckBox* add_image_date_place_to_filename_checkbox(MainApp& app); /** * @brief Access the \"Add audio/video metadata to file name\" checkbox. * @param app MainApp instance. * @return Pointer to the checkbox, or nullptr if unavailable. */ static QCheckBox* add_audio_video_metadata_to_filename_checkbox(MainApp& app); /** * @brief Access the \"Offer to rename picture files\" checkbox. * @param app MainApp instance. * @return Pointer to the checkbox, or nullptr if unavailable. */ static QCheckBox* offer_rename_images_checkbox(MainApp& app); /** * @brief Access the \"Do not categorize picture files\" checkbox. * @param app MainApp instance. * @return Pointer to the checkbox, or nullptr if unavailable. */ static QCheckBox* rename_images_only_checkbox(MainApp& app); /** * @brief Access the \"Analyze document files\" checkbox. * @param app MainApp instance. * @return Pointer to the checkbox, or nullptr if unavailable. */ static QCheckBox* analyze_documents_checkbox(MainApp& app); /** * @brief Access the \"Process document files only\" checkbox. * @param app MainApp instance. * @return Pointer to the checkbox, or nullptr if unavailable. */ static QCheckBox* process_documents_only_checkbox(MainApp& app); /** * @brief Access the \"Do not categorize document files\" checkbox. * @param app MainApp instance. * @return Pointer to the checkbox, or nullptr if unavailable. */ static QCheckBox* rename_documents_only_checkbox(MainApp& app); /** * @brief Access the picture-analysis disclosure toggle. * @param app MainApp instance. * @return Pointer to the toggle button, or nullptr if unavailable. */ static QToolButton* image_options_toggle_button(MainApp& app); /** * @brief Access the document-analysis disclosure toggle. * @param app MainApp instance. * @return Pointer to the toggle button, or nullptr if unavailable. */ static QToolButton* document_options_toggle_button(MainApp& app); /** * @brief Split file entries into image/document/other buckets for analysis. * @param files Input entries to split. * @param analyze_images Whether to analyze images by content. * @param analyze_documents Whether to analyze documents by content. * @param process_images_only Whether only images should be processed. * @param process_documents_only Whether only documents should be processed. * @param rename_images_only Whether images should be rename-only. * @param rename_documents_only Whether documents should be rename-only. * @param categorize_files Whether non-analyzed files are eligible for categorization. * @param use_full_path_keys Whether to key renamed files by full path. * @param renamed_files Set of already-renamed file keys. * @param image_entries Output vector of image entries. * @param document_entries Output vector of document entries. * @param other_entries Output vector of other entries. */ static void split_entries_for_analysis(const std::vector& files, bool analyze_images, bool analyze_documents, bool process_images_only, bool process_documents_only, bool rename_images_only, bool rename_documents_only, bool categorize_files, bool use_full_path_keys, const std::unordered_set& renamed_files, std::vector& image_entries, std::vector& document_entries, std::vector& other_entries); /** * @brief Override the probe used to detect visual LLM availability. * @param app MainApp instance. * @param probe Callback returning availability state. */ static void set_visual_llm_available_probe(MainApp& app, std::function probe); /** * @brief Override the visual LLM selection dialog runner. * @param app MainApp instance. * @param runner Callback invoked instead of showing the dialog. */ static void set_llm_selection_runner(MainApp& app, std::function runner); /** * @brief Override the image analysis prompt flow. * @param app MainApp instance. * @param prompt Callback that returns whether to proceed. */ static void set_image_analysis_prompt_override(MainApp& app, std::function prompt); /** * @brief Returns whether a visual-analysis failure should offer CPU retry. * @param reason Exception text produced by the failed visual analysis step. * @return True when the failure looks like GPU memory pressure. */ static bool should_offer_visual_cpu_fallback(const std::string& reason); /** * @brief Resolve the prompt filename used for document categorization. * @param original_name Original file name. * @param suggested_name Suggested file name, when available. * @return Suggested name when present; otherwise the original name. */ static std::string resolve_document_prompt_name(const std::string& original_name, const std::string& suggested_name); /** * @brief Build the document prompt path shown in categorization progress. * @param full_path Original full path to the document. * @param prompt_name File name to use in the categorization prompt. * @param summary Optional summary appended for the LLM prompt. * @return Prompt path string used for categorization. */ static std::string build_document_prompt_path(const std::string& full_path, const std::string& prompt_name, const std::string& summary); /** * @brief Trigger a UI retranslate on the MainApp instance. * @param app MainApp instance. */ static void trigger_retranslate(MainApp& app); /** * @brief Record a count of categorized files for metrics. * @param app MainApp instance. * @param count Number of files to add. */ static void add_categorized_files(MainApp& app, int count); /** * @brief Simulate the support prompt logic for tests. * @param settings Settings instance to update. * @param prompt_state Prompt state flag to mutate. * @param count Number of files categorized in this increment. * @param callback Callback to supply a simulated response. */ static void simulate_support_prompt(Settings& settings, bool& prompt_state, int count, std::function callback); }; #endif // AI_FILE_SORTER_TEST_BUILD ================================================ FILE: app/include/MainAppUiBuilder.hpp ================================================ #ifndef MAIN_APP_UI_BUILDER_HPP #define MAIN_APP_UI_BUILDER_HPP #include #include #include "UiTranslator.hpp" class MainApp; /** * @brief Builds the MainApp widget tree, menus, and translation dependencies. */ class MainAppUiBuilder { public: /** * @brief Builds the main window UI for the provided application instance. * @param app Main application window to populate. */ void build(MainApp& app); /** * @brief Collects the translator dependency bundle from the current UI state. * @param app Main application window whose controls are referenced. * @return Dependency bundle used by UiTranslator. */ UiTranslator::Dependencies build_translator_dependencies(MainApp& app) const; private: void build_central_panel(MainApp& app); void build_menus(MainApp& app); void build_file_menu(MainApp& app); void build_edit_menu(MainApp& app); void build_view_menu(MainApp& app); void build_settings_menu(MainApp& app); void build_development_menu(MainApp& app); void build_help_menu(MainApp& app); static QIcon icon_for(MainApp& app, const char* name, QStyle::StandardPixmap fallback); }; #endif ================================================ FILE: app/include/MediaRenameMetadataService.hpp ================================================ /** * @file MediaRenameMetadataService.hpp * @brief Builds audio/video filename suggestions from embedded media metadata. */ #pragma once #include #include #include /** * @brief Suggests audio/video filenames using conventional metadata ordering. * * The composed format is `year_artist_album_title.ext` (missing fields are omitted, * while preserving order). */ class MediaRenameMetadataService { public: /** * @brief Parsed metadata fields used for audio/video filename composition. */ struct MetadataFields { std::optional year; std::optional artist; std::optional album; std::optional title; }; /** * @brief Proposes a filename for a supported audio/video file. * @param media_path Full path to the media file. * @return Suggested filename (including extension), or `std::nullopt` when no metadata-based * improvement is available. */ std::optional suggest_name(const std::filesystem::path& media_path) const; /** * @brief Returns true when the file extension is recognized as audio/video media. * @param path Candidate media path. * @return True for supported audio/video extensions. */ static bool is_supported_media(const std::filesystem::path& path); /** * @brief Composes `year_artist_album_title.ext` using normalized metadata fragments. * @param original_path Original file path used for extension + fallback stem. * @param metadata Metadata fields used for composition. * @return Composed filename, or the original filename when composition data is unavailable. */ static std::string compose_filename(const std::filesystem::path& original_path, const MetadataFields& metadata); private: /** * @brief Extracts audio/video metadata fields from the given media file. * @param media_path Full path to the media file. * @return Metadata fields on success; `std::nullopt` when unavailable. */ static std::optional extract_metadata(const std::filesystem::path& media_path); /** * @brief Normalizes a metadata token into lowercase underscore-separated text. * @param value Raw metadata text. * @return Normalized slug, or empty string when no valid characters remain. */ static std::string slugify(const std::string& value); /** * @brief Extracts a year in `YYYY` form from an arbitrary date string. * @param value Raw metadata date value. * @return Four-digit year when available. */ static std::optional normalize_year(const std::string& value); }; ================================================ FILE: app/include/MovableCategorizedFile.hpp ================================================ #ifndef MOVABLECATEGORIZEDFILE_HPP #define MOVABLECATEGORIZEDFILE_HPP #include #include class MovableCategorizedFile { public: struct PreviewPaths { std::string source; std::string destination; }; MovableCategorizedFile(); MovableCategorizedFile(const std::string& dir_path, const std::string& cat, const std::string& subcat, const std::string& file_name, const std::string& destination_name = std::string()); MovableCategorizedFile(const std::string& source_dir, const std::string& destination_root, const std::string& cat, const std::string& subcat, const std::string& file_name, const std::string& destination_name); ~MovableCategorizedFile(); void create_cat_dirs(bool use_subcategory); bool move_file(bool use_subcategory); PreviewPaths preview_move_paths(bool use_subcategory) const; std::string get_subcategory_path() const; std::string get_category_path() const; std::string get_destination_path() const; std::string get_file_name() const; std::string get_dir_path() const; std::string get_category() const; std::string get_subcategory() const; void set_category(std::string& category); void set_subcategory(std::string& subcategory); private: struct MovePaths { std::filesystem::path source; std::filesystem::path destination; }; MovePaths build_move_paths(bool use_subcategory) const; bool source_is_available(const std::filesystem::path& source_path) const; bool destination_is_available(const std::filesystem::path& destination_path) const; bool perform_move(const std::filesystem::path& source_path, const std::filesystem::path& destination_path) const; std::string file_name; std::string destination_file_name; std::string source_dir; std::string dir_path; std::string category; std::string subcategory; std::filesystem::path category_path; std::filesystem::path subcategory_path; std::filesystem::path destination_path; }; #endif ================================================ FILE: app/include/ResultsCoordinator.hpp ================================================ #ifndef RESULTS_COORDINATOR_HPP #define RESULTS_COORDINATOR_HPP #include "Types.hpp" #include "FileScanner.hpp" #include #include /** * @brief Coordinates scan results and determines which files should be categorized or sorted. * * The coordinator relies on a FileScanner to list directory contents and then * filters/merges those results against cached or newly categorized entries. */ class ResultsCoordinator { public: /** * @brief Constructs a coordinator that uses the provided scanner. * @param scanner FileScanner used to enumerate directory entries. */ explicit ResultsCoordinator(FileScanner& scanner); /** * @brief Lists entries in a directory using the provided scan options. * @param directory Directory path to scan. * @param options File scan options (files, directories, hidden files). * @return Vector of FileEntry objects for items found in the directory. */ std::vector list_directory(const std::string& directory, FileScanOptions options) const; /** * @brief Returns directory entries that are not present in the cached set. * @param directory_path Directory path to scan. * @param options File scan options (files, directories, hidden files). * @param cached_files Set of cached file names to exclude. * @return Vector of FileEntry objects that are not in the cache. */ std::vector find_files_to_categorize(const std::string& directory_path, FileScanOptions options, const std::unordered_set& cached_files, bool use_full_path_keys) const; /** * @brief Filters categorized results to those still present on disk. * @param directory_path Base directory path (kept for symmetry with caller context). * @param options File scan options (files, directories, hidden files). * @param actual_files Current directory entries to validate against. * @param categorized_files Categorized entries from cache or analysis. * @return Vector of CategorizedFile entries that still exist in the directory. */ std::vector compute_files_to_sort(const std::string& directory_path, FileScanOptions options, const std::vector& actual_files, const std::vector& categorized_files, bool use_full_path_keys) const; /** * @brief Extracts file names from categorized entries into a set. * @param categorized_files Categorized entries to process. * @return Set of file names contained in the categorized list. */ std::unordered_set extract_file_names(const std::vector& categorized_files, bool use_full_path_keys) const; private: /** * @brief Scanner used to read directory entries. */ FileScanner& scanner; }; #endif ================================================ FILE: app/include/Settings.hpp ================================================ #ifndef SETTINGS_HPP #define SETTINGS_HPP #include #include #include #include #include #include #include #include /** * @brief Stores and persists application configuration for UI and runtime behavior. */ class Settings { public: /** * @brief Constructs a settings object with platform-appropriate defaults. */ Settings(); /** * @brief Loads configuration values from the active config file. * @return True when an existing config file was loaded successfully. */ bool load(); /** * @brief Persists current configuration values to the active config file. * @return True when the config file was written successfully. */ bool save(); /** * @brief Returns the selected LLM choice. * @return Current LLM choice enum. */ LLMChoice get_llm_choice() const; /** * @brief Sets the selected LLM choice. * @param choice LLM choice to store. */ void set_llm_choice(LLMChoice choice); /** * @brief Returns the stored OpenAI API key. * @return OpenAI API key string. */ std::string get_openai_api_key() const; /** * @brief Stores the OpenAI API key. * @param key OpenAI API key text. */ void set_openai_api_key(const std::string& key); /** * @brief Returns the configured OpenAI model identifier. * @return OpenAI model name. */ std::string get_openai_model() const; /** * @brief Sets the OpenAI model identifier. * @param model OpenAI model name to store. */ void set_openai_model(const std::string& model); /** * @brief Returns the stored Gemini API key. * @return Gemini API key string. */ std::string get_gemini_api_key() const; /** * @brief Stores the Gemini API key. * @param key Gemini API key text. */ void set_gemini_api_key(const std::string& key); /** * @brief Returns the configured Gemini model identifier. * @return Gemini model name. */ std::string get_gemini_model() const; /** * @brief Sets the Gemini model identifier. * @param model Gemini model name to store. */ void set_gemini_model(const std::string& model); /** * @brief Returns whether the LLM download UI section should remain expanded. * @return True when the downloads section is expanded. */ bool get_llm_downloads_expanded() const; /** * @brief Sets whether the LLM download UI section should remain expanded. * @param value True to keep the downloads section expanded. */ void set_llm_downloads_expanded(bool value); /** * @brief Returns the configured output language for categories. * @return Selected category language. */ CategoryLanguage get_category_language() const; /** * @brief Sets the output language for categories. * @param language Category language to store. */ void set_category_language(CategoryLanguage language); /** * @brief Returns the active custom local LLM identifier. * @return Custom LLM id, or empty when none is selected. */ std::string get_active_custom_llm_id() const; /** * @brief Sets the active custom local LLM identifier. * @param id Custom LLM id to store. */ void set_active_custom_llm_id(const std::string& id); /** * @brief Returns the configured custom local LLM entries. * @return Immutable list of configured custom LLMs. */ const std::vector& get_custom_llms() const; /** * @brief Adds or updates a custom local LLM entry. * @param llm Custom LLM definition to upsert. * @return Identifier of the saved custom LLM entry. */ std::string upsert_custom_llm(const CustomLLM& llm); /** * @brief Removes a custom local LLM entry by id. * @param id Custom LLM identifier to remove. */ void remove_custom_llm(const std::string& id); /** * @brief Finds a custom local LLM entry by id. * @param id Custom LLM identifier to resolve. * @return Matching custom LLM entry, or a default-initialized value when not found. */ CustomLLM find_custom_llm(const std::string& id) const; /** * @brief Return the active custom API endpoint id. * @return Custom API endpoint id, or empty when none is selected. */ std::string get_active_custom_api_id() const; /** * @brief Set the active custom API endpoint id. * @param id Custom API endpoint id to store. */ void set_active_custom_api_id(const std::string& id); /** * @brief Return the configured custom API endpoints. * @return Immutable list of configured custom API endpoints. */ const std::vector& get_custom_api_endpoints() const; /** * @brief Add or update a custom API endpoint entry. * @param endpoint Custom endpoint definition to upsert. * @return Identifier of the saved custom endpoint entry. */ std::string upsert_custom_api_endpoint(const CustomApiEndpoint& endpoint); /** * @brief Remove a custom API endpoint by id. * @param id Custom API endpoint identifier to remove. */ void remove_custom_api_endpoint(const std::string& id); /** * @brief Find a custom API endpoint by id. * @param id Custom API endpoint identifier to resolve. * @return Matching custom API endpoint, or a default-initialized value when not found. */ CustomApiEndpoint find_custom_api_endpoint(const std::string& id) const; /** * @brief Returns whether an LLM choice has been configured. * @return True when the stored LLM choice is not unset. */ bool is_llm_chosen() const; /** * @brief Returns whether subcategories are enabled. * @return True when subcategories should be used. */ bool get_use_subcategories() const; /** * @brief Enables or disables subcategories. * @param value True to enable subcategories. */ void set_use_subcategories(bool value); /** * @brief Returns whether consistency hints are enabled. * @return True when consistency hints should be used. */ bool get_use_consistency_hints() const; /** * @brief Enables or disables consistency hints. * @param value True to enable consistency hints. */ void set_use_consistency_hints(bool value); /** * @brief Returns whether files should be categorized. * @return True when file categorization is enabled. */ bool get_categorize_files() const; /** * @brief Enables or disables file categorization. * @param value True to categorize files. */ void set_categorize_files(bool value); /** * @brief Returns whether directories should be categorized. * @return True when directory categorization is enabled. */ bool get_categorize_directories() const; /** * @brief Enables or disables directory categorization. * @param value True to categorize directories. */ void set_categorize_directories(bool value); /** * @brief Returns whether subdirectories should be scanned. * @return True when subdirectory scanning is enabled. */ bool get_include_subdirectories() const; /** * @brief Enables or disables scanning of subdirectories. * @param value True to scan subdirectories. */ void set_include_subdirectories(bool value); /** * @brief Returns whether image content analysis is enabled. * @return True when image analysis is enabled. */ bool get_analyze_images_by_content() const; /** * @brief Enables or disables image content analysis. * @param value True to enable image analysis. */ void set_analyze_images_by_content(bool value); /** * @brief Returns whether image rename suggestions are enabled. * @return True when image rename suggestions are enabled. */ bool get_offer_rename_images() const; /** * @brief Enables or disables image rename suggestions. * @param value True to enable image rename suggestions. */ void set_offer_rename_images(bool value); /** * @brief Returns whether image filename suggestions should include EXIF date/place prefixes. * @return True when EXIF date/place prefixes are enabled for image rename suggestions. */ bool get_add_image_date_place_to_filename() const; /** * @brief Enables or disables adding EXIF date/place prefixes to image rename suggestions. * @param value True to enable EXIF date/place prefixes. */ void set_add_image_date_place_to_filename(bool value); /** * @brief Returns whether audio/video filename suggestions should include media metadata. * @return True when audio/video metadata-based filename suggestions are enabled. */ bool get_add_audio_video_metadata_to_filename() const; /** * @brief Enables or disables audio/video metadata-based filename suggestions. * @param value True to enable metadata-based filename suggestions for audio/video files. */ void set_add_audio_video_metadata_to_filename(bool value); /** * @brief Returns whether image creation dates should be appended to category names. * @return True when image creation dates should be appended to categories. */ bool get_add_image_date_to_category() const; /** * @brief Enables or disables appending image creation dates to category names. * @param value True to append image creation dates to categories. */ void set_add_image_date_to_category(bool value); /** * @brief Returns whether the image options group is expanded. * @return True when the image options group should be expanded. */ bool get_image_options_expanded() const; /** * @brief Sets whether the image options group is expanded. * @param value True to keep the image options group expanded. */ void set_image_options_expanded(bool value); /** * @brief Returns whether image files are treated as rename-only. * @return True when image files are in rename-only mode. */ bool get_rename_images_only() const; /** * @brief Enables or disables rename-only mode for images. * @param value True to enable rename-only mode for images. */ void set_rename_images_only(bool value); /** * @brief Returns whether only image files are processed. * @return True when only image files are processed. */ bool get_process_images_only() const; /** * @brief Enables or disables image-only processing. * @param value True to enable image-only processing. */ void set_process_images_only(bool value); /** * @brief Returns whether document content analysis is enabled. * @return True when document analysis is enabled. */ bool get_analyze_documents_by_content() const; /** * @brief Enables or disables document content analysis. * @param value True to enable document analysis. */ void set_analyze_documents_by_content(bool value); /** * @brief Returns whether document rename suggestions are enabled. * @return True when document rename suggestions are enabled. */ bool get_offer_rename_documents() const; /** * @brief Enables or disables document rename suggestions. * @param value True to enable document rename suggestions. */ void set_offer_rename_documents(bool value); /** * @brief Returns whether the document options group is expanded. * @return True when the document options group should be expanded. */ bool get_document_options_expanded() const; /** * @brief Sets whether the document options group is expanded. * @param value True to keep the document options group expanded. */ void set_document_options_expanded(bool value); /** * @brief Returns whether document files are treated as rename-only. * @return True when document files are in rename-only mode. */ bool get_rename_documents_only() const; /** * @brief Enables or disables rename-only mode for documents. * @param value True to enable rename-only mode for documents. */ void set_rename_documents_only(bool value); /** * @brief Returns whether only document files are processed. * @return True when only document files are processed. */ bool get_process_documents_only() const; /** * @brief Enables or disables document-only processing. * @param value True to enable document-only processing. */ void set_process_documents_only(bool value); /** * @brief Returns whether to append a document creation date to category names. * @return True when document creation dates should be appended to categories. */ bool get_add_document_date_to_category() const; /** * @brief Enables or disables appending document creation dates to category names. * @param value True to append document creation dates to categories. */ void set_add_document_date_to_category(bool value); /** * @brief Returns the current target sort folder path. * @return Sort folder path as UTF-8 text. */ std::string get_sort_folder() const; /** * @brief Sets the target sort folder path. * @param path Sort folder path to store. */ void set_sort_folder(const std::string &path); /** * @brief Returns whether the consistency-pass feature is enabled. * @return True when the consistency pass should be available. */ bool get_consistency_pass_enabled() const; /** * @brief Enables or disables the consistency-pass feature. * @param value True to enable the consistency pass. */ void set_consistency_pass_enabled(bool value); /** * @brief Returns whether category whitelists are enabled. * @return True when whitelist filtering is active. */ bool get_use_whitelist() const; /** * @brief Enables or disables category whitelist filtering. * @param value True to enable whitelist filtering. */ void set_use_whitelist(bool value); /** * @brief Returns the active category whitelist name. * @return Active whitelist name. */ std::string get_active_whitelist() const; /** * @brief Sets the active category whitelist name. * @param name Whitelist name to store. */ void set_active_whitelist(const std::string& name); /** * @brief Returns whether prompt logging is enabled in development mode. * @return True when prompt/response logging is enabled. */ bool get_development_prompt_logging() const; /** * @brief Enables or disables prompt logging in development mode. * @param value True to enable prompt logging. */ void set_development_prompt_logging(bool value); /** * @brief Resolves the full path to the active `config.ini` file. * @return Platform-appropriate config file path. */ std::string define_config_path(); /** * @brief Returns the directory containing the active config file. * @return Config directory path as UTF-8 text. */ std::string get_config_dir(); /** * @brief Stores the application version that should be skipped for update prompts. * @param version Version string to suppress. */ void set_skipped_version(const std::string &version); /** * @brief Returns the application version currently skipped for update prompts. * @return Skipped version string, or empty when none is set. */ std::string get_skipped_version(); /** * @brief Sets whether the file explorer panel should be shown. * @param value True to keep the file explorer visible. */ void set_show_file_explorer(bool value); /** * @brief Returns whether the file explorer panel should be shown. * @return True when the file explorer is visible by default. */ bool get_show_file_explorer() const; /** * @brief Returns whether the suitability benchmark has been completed. * @return True when the benchmark has run at least once. */ bool get_suitability_benchmark_completed() const; /** * @brief Returns whether the suitability benchmark dialog is suppressed. * @return True when the dialog should not auto-show on startup. */ bool get_suitability_benchmark_suppressed() const; /** * @brief Marks the suitability benchmark as completed. * @param value True when the benchmark has run. */ void set_suitability_benchmark_completed(bool value); /** * @brief Sets whether the suitability benchmark dialog is suppressed. * @param value True to suppress auto-showing the dialog. */ void set_suitability_benchmark_suppressed(bool value); /** * @brief Returns the most recent benchmark report text. * @return Report text (may be empty). */ std::string get_benchmark_last_report() const; /** * @brief Sets the most recent benchmark report text. * @param value Report text to store. */ void set_benchmark_last_report(const std::string& value); /** * @brief Returns the timestamp string for the last benchmark run. * @return Timestamp string (may be empty). */ std::string get_benchmark_last_run() const; /** * @brief Sets the timestamp string for the last benchmark run. * @param value Timestamp to store. */ void set_benchmark_last_run(const std::string& value); /** * @brief Returns the selected UI language. * @return Current interface language. */ Language get_language() const; /** * @brief Sets the selected UI language. * @param value Interface language to store. */ void set_language(Language value); /** * @brief Returns the cumulative number of categorized files recorded so far. * @return Total categorized file count. */ int get_total_categorized_files() const; /** * @brief Adds to the cumulative categorized-file counter. * @param count Number of files to add; non-positive values are ignored. */ void add_categorized_files(int count); /** * @brief Returns the next file-count threshold for the support prompt. * @return Next support prompt threshold. */ int get_next_support_prompt_threshold() const; /** * @brief Sets the next file-count threshold for the support prompt. * @param threshold Threshold value to store (clamped to the minimum supported value). */ void set_next_support_prompt_threshold(int threshold); /** * @brief Returns the configured allowed category whitelist. * @return Copy of the allowed category list. */ std::vector get_allowed_categories() const; /** * @brief Replaces the configured allowed category whitelist. * @param values Allowed category names to store. */ void set_allowed_categories(std::vector values); /** * @brief Returns the configured allowed subcategory whitelist. * @return Copy of the allowed subcategory list. */ std::vector get_allowed_subcategories() const; /** * @brief Replaces the configured allowed subcategory whitelist. * @param values Allowed subcategory names to store. */ void set_allowed_subcategories(std::vector values); private: LLMChoice parse_llm_choice() const; void load_basic_settings(const std::function& load_bool, const std::function& load_int); void load_whitelist_settings(const std::function& load_bool); void load_custom_llm_settings(); /** * @brief Load custom API endpoint entries from config. */ void load_custom_api_settings(); void log_loaded_settings() const; void save_core_settings(); void save_whitelist_settings(); void save_custom_llms(); /** * @brief Save custom API endpoint entries to config. */ void save_custom_api_endpoints(); std::string config_path; std::filesystem::path config_dir; IniConfig config; LLMChoice llm_choice = LLMChoice::Unset; std::string openai_api_key; std::string openai_model{ "gpt-4o-mini" }; std::string gemini_api_key; std::string gemini_model{ "gemini-2.5-flash-lite" }; bool llm_downloads_expanded{true}; bool use_subcategories; bool categorize_files; bool categorize_directories; bool include_subdirectories{false}; bool analyze_images_by_content{false}; bool offer_rename_images{false}; bool add_image_date_place_to_filename{false}; bool add_audio_video_metadata_to_filename{true}; bool add_image_date_to_category{false}; bool image_options_expanded{false}; bool rename_images_only{false}; bool process_images_only{false}; bool analyze_documents_by_content{false}; bool offer_rename_documents{false}; bool document_options_expanded{false}; bool rename_documents_only{false}; bool process_documents_only{false}; bool add_document_date_to_category{false}; bool use_consistency_hints{false}; bool use_whitelist{false}; std::string default_sort_folder; std::string sort_folder; std::string skipped_version; bool show_file_explorer{true}; bool suitability_benchmark_completed{false}; bool suitability_benchmark_suppressed{false}; std::string benchmark_last_report; std::string benchmark_last_run; Language language{Language::English}; CategoryLanguage category_language{CategoryLanguage::English}; bool consistency_pass_enabled{false}; bool development_prompt_logging{false}; int categorized_file_count{0}; int next_support_prompt_threshold{50}; std::vector allowed_categories; std::vector allowed_subcategories; std::string active_whitelist; std::vector custom_llms; std::string active_custom_llm_id; std::vector custom_api_endpoints; std::string active_custom_api_id; }; #endif ================================================ FILE: app/include/SuitabilityBenchmarkDialog.hpp ================================================ #ifndef SUITABILITY_BENCHMARK_DIALOG_HPP #define SUITABILITY_BENCHMARK_DIALOG_HPP #include #include #include #include #include #include class QLabel; class QTextEdit; class QProgressBar; class QPushButton; class QCheckBox; class Settings; class QCloseEvent; class QEvent; /** * @brief Dialog that runs a suitability benchmark for categorization and analysis features. */ class SuitabilityBenchmarkDialog : public QDialog { Q_DECLARE_TR_FUNCTIONS(SuitabilityBenchmarkDialog) public: /** * @brief Create a suitability benchmark dialog. * @param settings Settings store used for persistence. * @param parent Parent widget. */ SuitabilityBenchmarkDialog(Settings& settings, QWidget* parent = nullptr); /** * @brief Destructor that joins any running benchmark thread. */ ~SuitabilityBenchmarkDialog() override; protected: /** * @brief Handle language changes for translated UI strings. * @param event Qt event payload. */ void changeEvent(QEvent* event) override; /** * @brief Prevent closing while the benchmark is running. * @param event Qt close event. */ void closeEvent(QCloseEvent* event) override; private: /** * @brief Build and connect the dialog UI elements. */ void setup_ui(); /** * @brief Update translated strings for the dialog. */ void retranslate_ui(); /** * @brief Start the benchmark worker thread and clear prior output. */ void start_benchmark(); /** * @brief Request the benchmark to stop after the current step finishes. */ void request_stop(); /** * @brief Run benchmark steps off the UI thread. */ void run_benchmark_worker(); /** * @brief Append a line to the output view. * @param text Line to display. * @param is_html True when the text already contains HTML markup. */ void append_line(const QString& text, bool is_html); /** * @brief Toggle UI state for a running benchmark. * @param running True when the benchmark is running. */ void set_running_state(bool running); /** * @brief Finish the benchmark and persist results to settings. */ void finish_benchmark(); /** * @brief Load the most recent benchmark results from settings. */ void load_previous_results(); /** * @brief Render saved benchmark results into the output view. */ void render_previous_results(); Settings& settings_; QLabel* intro_label_{nullptr}; QTextEdit* output_view_{nullptr}; QProgressBar* progress_bar_{nullptr}; QCheckBox* suppress_checkbox_{nullptr}; QPushButton* run_button_{nullptr}; QPushButton* stop_button_{nullptr}; QPushButton* close_button_{nullptr}; std::atomic running_{false}; std::atomic stop_requested_{false}; std::thread worker_; bool recording_{false}; bool showing_previous_results_{false}; QString last_run_stamp_; QString last_report_; QStringList current_report_; }; #endif // SUITABILITY_BENCHMARK_DIALOG_HPP ================================================ FILE: app/include/SupportCodeManager.hpp ================================================ /** * @file SupportCodeManager.hpp * @brief Offline donation-code validation and prompt suppression helpers. */ #pragma once #include #include #include #include /** * @brief Handles offline donation-code validation and binary prompt suppression state. */ class SupportCodeManager { public: /** * @brief Constructs a support-code manager rooted at the app config directory. * @param config_dir Base configuration directory used for the binary suppression blob. */ explicit SupportCodeManager(std::filesystem::path config_dir); /** * @brief Returns whether a donation code passes offline validation. * @param code User-provided donation code. * @return True when the code is valid. */ static bool is_valid_code(const std::string& code); /** * @brief Validates and stores a donation code so the support prompt stays hidden. * @param code User-provided donation code. * @return True when the code is valid and the suppression blob was written. */ bool redeem_code(const std::string& code) const; /** * @brief Returns whether the binary suppression blob is present and valid. * @return True when the support prompt should remain hidden. */ bool is_prompt_permanently_disabled() const; #ifdef AI_FILE_SORTER_TEST_BUILD /** * @brief Writes a valid suppression blob without requiring a real donation code. * @return True when the test suppression blob was written successfully. */ bool force_disable_prompt_for_testing() const; #endif private: /** * @brief Verifies a donation code and returns the signed payload on success. * @param code User-provided donation code. * @return Signed payload bytes when valid, otherwise `std::nullopt`. */ static std::optional decode_payload(const std::string& code); /** * @brief Resolves the binary suppression blob path. * @return Filesystem path used for the stored suppression state. */ std::filesystem::path storage_path() const; /** * @brief Derives the current machine binding key. * @return Opaque machine-bound key material. */ std::string machine_binding_key() const; /** * @brief Writes an opaque suppression blob for the provided signed payload. * @param payload Signed payload from a valid donation code. * @return True when the blob was written successfully. */ bool write_state(const std::string& payload) const; std::filesystem::path config_dir_; }; ================================================ FILE: app/include/TestHooks.hpp ================================================ #pragma once #include #include #include #include #include #include "Utils.hpp" namespace TestHooks { struct BackendMemoryInfo { Utils::CudaMemoryInfo memory; bool is_integrated = false; std::string name; }; using BackendMemoryProbe = std::function(std::string_view backend_name)>; void set_backend_memory_probe(BackendMemoryProbe probe); void reset_backend_memory_probe(); using BackendAvailabilityProbe = std::function; void set_backend_availability_probe(BackendAvailabilityProbe probe); void reset_backend_availability_probe(); using CudaAvailabilityProbe = std::function; void set_cuda_availability_probe(CudaAvailabilityProbe probe); void reset_cuda_availability_probe(); using CudaMemoryProbe = std::function()>; void set_cuda_memory_probe(CudaMemoryProbe probe); void reset_cuda_memory_probe(); struct CategorizationMoveInfo { bool show_subcategory_folders; std::string category; std::string subcategory; std::string file_name; }; using CategorizationMoveProbe = std::function; void set_categorization_move_probe(CategorizationMoveProbe probe); void reset_categorization_move_probe(); #ifdef AI_FILE_SORTER_TEST_BUILD using LLMDownloadProbe = std::function; void set_llm_download_probe(LLMDownloadProbe probe); void reset_llm_download_probe(); #endif } // namespace TestHooks ================================================ FILE: app/include/TranslationManager.hpp ================================================ #ifndef TRANSLATIONMANAGER_HPP #define TRANSLATIONMANAGER_HPP #include "Language.hpp" #include #include #include #include class QApplication; class TranslationManager : public QObject { public: struct LanguageInfo { Language id; QString code; QString name; QString resource_path; }; static TranslationManager& instance(); void initialize(QApplication* app); void initialize_for_app(QApplication* app, Language language); void set_language(Language language); Language current_language() const; const std::vector& available_languages() const; private: TranslationManager(); bool load_translation(const LanguageInfo& info); QApplication* app_{nullptr}; std::unique_ptr translator_; Language current_language_{Language::English}; std::vector languages_; }; #endif // TRANSLATIONMANAGER_HPP ================================================ FILE: app/include/Types.hpp ================================================ #ifndef TYPES_HPP #define TYPES_HPP #include enum class LLMChoice { Unset, Remote_OpenAI, Remote_Gemini, Remote_Custom, ///< Custom OpenAI-compatible endpoint. Local_3b, Local_3b_legacy, Local_7b, Custom }; inline bool is_remote_choice(LLMChoice choice) { return choice == LLMChoice::Remote_OpenAI || choice == LLMChoice::Remote_Gemini || choice == LLMChoice::Remote_Custom; } enum class FileType {File, Directory}; struct CategorizedFile { std::string file_path; std::string file_name; FileType type; std::string category; std::string subcategory; int taxonomy_id{0}; bool from_cache{false}; bool used_consistency_hints{false}; std::string suggested_name; bool rename_only{false}; bool rename_applied{false}; std::string canonical_category; std::string canonical_subcategory; }; inline std::string to_string(FileType type) { switch (type) { case FileType::File: return "File"; case FileType::Directory: return "Directory"; default: return "Unknown"; } } struct FileEntry { std::string full_path; std::string file_name; FileType type; }; struct CustomLLM { std::string id; std::string name; std::string description; std::string path; }; inline bool is_valid_custom_llm(const CustomLLM& entry) { return !entry.id.empty() && !entry.name.empty() && !entry.path.empty(); } /** * @brief Defines a custom OpenAI-compatible API endpoint. */ struct CustomApiEndpoint { std::string id; std::string name; std::string description; std::string base_url; std::string api_key; std::string model; }; /** * @brief Returns true when the custom endpoint has the required fields. */ inline bool is_valid_custom_api_endpoint(const CustomApiEndpoint& entry) { return !entry.id.empty() && !entry.name.empty() && !entry.base_url.empty() && !entry.model.empty(); } enum class FileScanOptions { None = 0, Files = 1 << 0, // 0001 Directories = 1 << 1, // 0010 HiddenFiles = 1 << 2, // 0100 Recursive = 1 << 3 // 1000 }; inline bool has_flag(FileScanOptions value, FileScanOptions flag) { return (static_cast(value) & static_cast(flag)) != 0; } inline FileScanOptions operator|(FileScanOptions a, FileScanOptions b) { return static_cast(static_cast(a) | static_cast(b)); } inline FileScanOptions operator&(FileScanOptions a, FileScanOptions b) { return static_cast(static_cast(a) & static_cast(b)); } inline FileScanOptions operator~(FileScanOptions a) { return static_cast(~static_cast(a)); } struct cudaDeviceProp { size_t totalGlobalMem; }; #endif ================================================ FILE: app/include/UiTranslator.hpp ================================================ #ifndef UI_TRANSLATOR_HPP #define UI_TRANSLATOR_HPP #include #include #include #include #include class QAction; class QActionGroup; class QDockWidget; class QLabel; class QMainWindow; class QMenu; class QPushButton; class QComboBox; class QStandardItemModel; class QToolButton; class Settings; #include "Language.hpp" #include "CategoryLanguage.hpp" /** * @brief Applies translated text to the main window UI and related controls. */ class UiTranslator { public: /** * @brief References to the primary controls whose labels are translated together. */ struct PrimaryControls { QPointer& path_label; QPointer& browse_button; QPointer& analyze_button; QPointer& use_subcategories_checkbox; QPointer& categorization_style_heading; QPointer& categorization_style_refined_radio; QPointer& categorization_style_consistent_radio; QPointer& use_whitelist_checkbox; QPointer& whitelist_selector; QPointer& categorize_files_checkbox; QPointer& categorize_directories_checkbox; QPointer& include_subdirectories_checkbox; QPointer& analyze_images_checkbox; QPointer& process_images_only_checkbox; QPointer& add_image_date_to_category_checkbox; QPointer& add_image_date_place_to_filename_checkbox; QPointer& add_audio_video_metadata_to_filename_checkbox; QPointer& offer_rename_images_checkbox; QPointer& rename_images_only_checkbox; QPointer& image_options_toggle_button; QPointer& analyze_documents_checkbox; QPointer& process_documents_only_checkbox; QPointer& offer_rename_documents_checkbox; QPointer& rename_documents_only_checkbox; QPointer& add_document_date_to_category_checkbox; QPointer& document_options_toggle_button; }; /** * @brief References to top-level menus whose titles are translated. */ struct MenuControls { QMenu*& file_menu; QMenu*& edit_menu; QMenu*& view_menu; QMenu*& settings_menu; QMenu*& development_menu; QMenu*& development_settings_menu; QMenu*& language_menu; QMenu*& category_language_menu; QMenu*& help_menu; }; /** * @brief References to menu and command actions whose text is translated. */ struct ActionControls { QAction*& file_quit_action; QAction*& run_benchmark_action; QAction*& copy_action; QAction*& cut_action; QAction*& undo_last_run_action; QAction*& paste_action; QAction*& delete_action; QAction*& toggle_explorer_action; QAction*& toggle_llm_action; QAction*& manage_whitelists_action; QAction*& development_prompt_logging_action; QAction*& consistency_pass_action; QAction*& english_action; QAction*& dutch_action; QAction*& french_action; QAction*& german_action; QAction*& italian_action; QAction*& spanish_action; QAction*& turkish_action; QAction*& korean_action; QAction*& category_language_english; QAction*& category_language_french; QAction*& category_language_german; QAction*& category_language_italian; QAction*& category_language_dutch; QAction*& category_language_polish; QAction*& category_language_portuguese; QAction*& category_language_spanish; QAction*& category_language_turkish; QAction*& about_action; QAction*& about_qt_action; QAction*& about_agpl_action; QAction*& support_project_action; }; /** * @brief References to language-selection actions and their action group. */ struct LanguageControls { QActionGroup*& language_group; QAction*& english_action; QAction*& dutch_action; QAction*& french_action; QAction*& german_action; QAction*& italian_action; QAction*& spanish_action; QAction*& turkish_action; QAction*& korean_action; }; /** * @brief References to category-language actions and their action group. */ struct CategoryLanguageControls { QActionGroup*& category_language_group; QAction*& dutch; QAction*& english; QAction*& french; QAction*& german; QAction*& italian; QAction*& polish; QAction*& portuguese; QAction*& spanish; QAction*& turkish; }; /** * @brief Runtime state inputs used when translating status-dependent text. */ struct State { bool analysis_in_progress{false}; bool stop_analysis_requested{false}; bool status_is_ready{true}; }; /** * @brief Full dependency bundle required to translate the MainApp UI. */ struct Dependencies { QMainWindow& window; PrimaryControls primary; QPointer& tree_model; MenuControls menus; ActionControls actions; LanguageControls language; CategoryLanguageControls category_language; QPointer& file_explorer_dock; Settings& settings; std::function translator; }; /** * @brief Constructs a translator wrapper over the provided UI dependencies. * @param deps References to the UI controls and translation callback. */ explicit UiTranslator(Dependencies deps); /** * @brief Retranslates all supported UI text in one pass. * @param state Current UI state used for status-dependent labels. */ void retranslate_all(const State& state) const; /** * @brief Updates the main window title. */ void translate_window_title() const; /** * @brief Updates the labels of the primary controls on the main window. * @param analysis_in_progress True when analysis is currently active. */ void translate_primary_controls(bool analysis_in_progress) const; /** * @brief Updates translated labels inside the results tree view. */ void translate_tree_view_labels() const; /** * @brief Updates menu titles and action labels. */ void translate_menus_and_actions() const; /** * @brief Updates the status bar message for the given runtime state. * @param state Current UI state used to choose the status message. */ void translate_status_messages(const State& state) const; /** * @brief Synchronizes checkmarks for language and category-language actions. */ void update_language_checks() const; private: QString tr(const char* source) const; void update_language_group_checks(Language configured) const; void update_category_language_checks(CategoryLanguage configured) const; Dependencies deps_; }; #endif // UI_TRANSLATOR_HPP #include "Language.hpp" #include "CategoryLanguage.hpp" ================================================ FILE: app/include/UndoManager.hpp ================================================ #pragma once #include #include #include #include #include #include #include #include #include class UndoManager { public: struct Entry { std::string source; std::string destination; std::uintmax_t size_bytes{0}; std::time_t mtime{0}; }; explicit UndoManager(std::string undo_dir); bool save_plan(const std::string& run_base_dir, const std::vector& entries, const std::shared_ptr& logger) const; std::optional latest_plan_path() const; struct UndoResult { int restored{0}; int skipped{0}; QStringList details; }; UndoResult undo_plan(const QString& plan_path) const; private: std::string undo_dir_; }; ================================================ FILE: app/include/UpdateArchiveExtractor.hpp ================================================ #pragma once #include #include class UpdateArchiveExtractor { public: struct ExtractionResult { std::filesystem::path installer_path; std::string message; static ExtractionResult success(std::filesystem::path path) { return ExtractionResult{std::move(path), {}}; } static ExtractionResult failure(std::string error) { return ExtractionResult{{}, std::move(error)}; } bool ok() const { return !installer_path.empty(); } }; static bool supports_archive(const std::filesystem::path& package_path); static ExtractionResult extract_installer(const std::filesystem::path& archive_path, const std::filesystem::path& destination_root); }; ================================================ FILE: app/include/UpdateFeed.hpp ================================================ #pragma once #include #include struct UpdateInfo { std::string current_version; std::string min_version{"0.0.0"}; std::string download_url; std::string release_notes_url; std::string installer_url; std::string installer_sha256; bool has_download_target() const { return !download_url.empty() || !installer_url.empty(); } bool has_direct_installer() const { return !installer_url.empty(); } }; class UpdateFeed { public: enum class Platform { Windows, MacOS, Linux }; static Platform current_platform(); static std::optional parse_for_current_platform(const std::string& update_json); static std::optional parse_for_platform(const std::string& update_json, Platform platform); }; ================================================ FILE: app/include/UpdateInstaller.hpp ================================================ #pragma once #include "Settings.hpp" #include "UpdateFeed.hpp" #include #include #include #include #include struct UpdatePreparationResult { enum class Status { Ready, Canceled, Failed }; Status status{Status::Failed}; std::filesystem::path installer_path; std::string message; static UpdatePreparationResult ready(std::filesystem::path path) { return UpdatePreparationResult{Status::Ready, std::move(path), {}}; } static UpdatePreparationResult canceled(std::string message = {}) { return UpdatePreparationResult{Status::Canceled, {}, std::move(message)}; } static UpdatePreparationResult failed(std::string message) { return UpdatePreparationResult{Status::Failed, {}, std::move(message)}; } }; class UpdateInstaller { public: struct LaunchRequest { std::string program; std::vector arguments; }; class DownloadCanceledError : public std::runtime_error { public: DownloadCanceledError(); }; using ProgressCallback = std::function; using CancelCheck = std::function; using DownloadFunction = std::function; using LaunchFunction = std::function; explicit UpdateInstaller(Settings& settings, DownloadFunction download_fn = {}, LaunchFunction launch_fn = {}); bool supports_auto_install(const UpdateInfo& info) const; UpdatePreparationResult prepare(const UpdateInfo& info, ProgressCallback progress_cb = {}, CancelCheck cancel_check = {}) const; bool launch(const std::filesystem::path& installer_path) const; private: Settings& settings_; DownloadFunction download_fn_; LaunchFunction launch_fn_; std::filesystem::path updates_dir() const; std::filesystem::path package_path_for(const UpdateInfo& info) const; std::filesystem::path extracted_installer_root_for(const std::filesystem::path& package_path) const; std::string compute_sha256(const std::filesystem::path& path) const; bool verify_file(const std::filesystem::path& path, const std::string& expected_sha256) const; static LaunchRequest build_launch_request(const std::filesystem::path& installer_path); static void default_download(const std::string& url, const std::filesystem::path& destination_path, ProgressCallback progress_cb, CancelCheck cancel_check); static bool default_launch(const std::filesystem::path& installer_path); #ifdef AI_FILE_SORTER_TEST_BUILD friend class UpdateInstallerTestAccess; #endif }; ================================================ FILE: app/include/UpdateInstallerTestAccess.hpp ================================================ #pragma once #ifdef AI_FILE_SORTER_TEST_BUILD #include "UpdateInstaller.hpp" class UpdateInstallerTestAccess { public: static UpdateInstaller::LaunchRequest build_launch_request(const std::filesystem::path& installer_path); }; #endif // AI_FILE_SORTER_TEST_BUILD ================================================ FILE: app/include/Updater.hpp ================================================ #ifndef UPDATER_HPP #define UPDATER_HPP #include "Settings.hpp" #include "UpdateFeed.hpp" #include "UpdateInstaller.hpp" #include "Version.hpp" #include #include #include #include class QWidget; class QString; #ifdef AI_FILE_SORTER_TEST_BUILD class UpdaterTestAccess; #endif class Updater { public: explicit Updater(Settings& settings); ~Updater(); void begin(); private: Settings& settings; UpdateInstaller installer; std::optional update_spec_file_url_; std::function open_download_url_fn_; std::function quit_fn_; std::optional update_info; std::future update_future; void check_updates(); std::optional resolve_live_test_update() const; std::string fetch_update_metadata() const; Version string_to_Version(const std::string &version_str); void display_update_dialog(bool is_required=false); void show_required_update_dialog(const UpdateInfo& info, QWidget* parent); void show_optional_update_dialog(const UpdateInfo& info, QWidget* parent); bool is_update_available(); bool is_update_required(); bool is_update_skipped(); bool trigger_update_action(const UpdateInfo& info, QWidget* parent, bool quit_after_open); UpdatePreparationResult prepare_installer_update(const UpdateInfo& info, QWidget* parent); bool handle_update_error(const UpdateInfo& info, const QString& message, QWidget* parent, bool quit_after_open); #ifdef AI_FILE_SORTER_TEST_BUILD friend class UpdaterTestAccess; #endif }; #endif ================================================ FILE: app/include/UpdaterBuildConfig.hpp ================================================ #pragma once namespace UpdaterBuildConfig { enum class Mode { AutoInstall, NotifyOnly, Disabled, }; constexpr Mode current_mode() { #if defined(AI_FILE_SORTER_UPDATE_MODE_DISABLED) return Mode::Disabled; #elif defined(AI_FILE_SORTER_UPDATE_MODE_NOTIFY_ONLY) return Mode::NotifyOnly; #elif defined(AI_FILE_SORTER_UPDATE_MODE_AUTO_INSTALL) return Mode::AutoInstall; #else return Mode::AutoInstall; #endif } constexpr bool update_checks_enabled() { return current_mode() != Mode::Disabled; } constexpr bool auto_install_enabled() { return current_mode() == Mode::AutoInstall; } } // namespace UpdaterBuildConfig ================================================ FILE: app/include/UpdaterLaunchOptions.hpp ================================================ #pragma once namespace UpdaterLaunchOptions { inline constexpr const char* kLiveTestFlag = "--updater-live-test"; inline constexpr const char* kLiveTestUrlFlag = "--updater-live-test-url="; inline constexpr const char* kLiveTestSha256Flag = "--updater-live-test-sha256="; inline constexpr const char* kLiveTestVersionFlag = "--updater-live-test-version="; inline constexpr const char* kLiveTestMinVersionFlag = "--updater-live-test-min-version="; inline constexpr const char* kLiveTestModeEnv = "AI_FILE_SORTER_UPDATER_TEST_MODE"; inline constexpr const char* kLiveTestUrlEnv = "AI_FILE_SORTER_UPDATER_TEST_URL"; inline constexpr const char* kLiveTestSha256Env = "AI_FILE_SORTER_UPDATER_TEST_SHA256"; inline constexpr const char* kLiveTestVersionEnv = "AI_FILE_SORTER_UPDATER_TEST_VERSION"; inline constexpr const char* kLiveTestMinVersionEnv = "AI_FILE_SORTER_UPDATER_TEST_MIN_VERSION"; } // namespace UpdaterLaunchOptions ================================================ FILE: app/include/UpdaterLiveTestConfig.hpp ================================================ #pragma once #include #include #include struct UpdaterLiveTestConfig { bool enabled{false}; std::optional installer_url; std::optional installer_sha256; std::optional current_version; std::optional min_version; }; std::optional find_updater_live_test_ini(const std::filesystem::path& executable_path); std::optional load_missing_values_from_live_test_ini( UpdaterLiveTestConfig& config, const std::filesystem::path& executable_path); ================================================ FILE: app/include/UpdaterTestAccess.hpp ================================================ #pragma once #ifdef AI_FILE_SORTER_TEST_BUILD #include "UpdateFeed.hpp" #include #include class QWidget; class Updater; class UpdaterTestAccess { public: static bool is_update_available(Updater& updater); static std::optional current_update_info(const Updater& updater); static bool has_update_task(const Updater& updater); static void wait_for_update_task(Updater& updater); static void set_open_download_url_handler(Updater& updater, std::function handler); static void set_quit_handler(Updater& updater, std::function handler); static bool trigger_update_action(Updater& updater, const UpdateInfo& info, QWidget* parent, bool quit_after_open); static bool handle_update_error(Updater& updater, const UpdateInfo& info, const QString& message, QWidget* parent, bool quit_after_open); }; #endif // AI_FILE_SORTER_TEST_BUILD ================================================ FILE: app/include/Utils.hpp ================================================ #ifndef UTILS_HPP #define UTILS_HPP #include #include #include #include #include #include #include class Utils { public: Utils(); ~Utils(); static bool is_network_available(); static std::string get_executable_path(); static bool is_valid_directory(const char *path); static std::vector hex_to_vector(const std::string &hex); static const char* to_cstr(const std::u8string& u8str); static void ensure_directory_exists(const std::string &dir); static bool is_os_windows(); static bool is_os_macos(); static bool is_os_linux(); static std::string format_size(curl_off_t bytes); static int determine_ngl_cuda(); struct CudaMemoryInfo { size_t free_bytes{0}; size_t total_bytes{0}; size_t device_total_bytes{0}; bool valid() const { return total_bytes > 0 || free_bytes > 0; } }; static std::optional query_cuda_memory(); static int compute_ngl_from_cuda_memory(const CudaMemoryInfo& info); template void run_on_main_thread(Func &&func); static std::string get_default_llm_destination(); static std::string get_file_name_from_url(std::string url); static std::string make_default_path_to_file_from_download_url(std::string url); static bool is_cuda_available(); static int get_installed_cuda_runtime_version(); static std::string get_cudart_dll_name(); static std::string abbreviate_user_path(const std::string& path); static std::filesystem::path ensure_ca_bundle(); static std::string path_to_utf8(const std::filesystem::path& path); static std::filesystem::path utf8_to_path(const std::string& utf8_path); static std::string sanitize_path_label(const std::string& value); private: static int get_ngl(int vram_mb); }; #endif ================================================ FILE: app/include/Version.hpp ================================================ #ifndef VERSION_HPP #define VERSION_HPP #include #include #include class Version { public: explicit Version(std::initializer_list version_digits); explicit Version(const std::vector& version_digits); bool operator>=(const Version& other) const; bool operator<=(const Version& other) const; std::string to_string() const; bool operator>(const Version &other) const; private: std::vector digits; }; #endif ================================================ FILE: app/include/WhitelistManagerDialog.hpp ================================================ #ifndef WHITELIST_MANAGER_DIALOG_HPP #define WHITELIST_MANAGER_DIALOG_HPP #include #include #include #include #include #include "WhitelistStore.hpp" class QListWidget; class QTextEdit; class QLineEdit; class QPushButton; class QLabel; /** * @brief Dialog for creating, editing, and deleting whitelist entries. */ class WhitelistManagerDialog : public QDialog { Q_DECLARE_TR_FUNCTIONS(WhitelistManagerDialog) public: /** * @brief Constructs the whitelist manager dialog. * @param store Backing store for whitelist entries. * @param parent Optional parent widget. */ explicit WhitelistManagerDialog(WhitelistStore& store, QWidget* parent = nullptr); /** * @brief Registers a callback invoked when the whitelist collection changes. * @param cb Callback to invoke after changes. */ void set_on_lists_changed(std::function cb) { on_lists_changed_ = std::move(cb); } private: /** * @brief Handles the Add button action. */ void on_add_clicked(); /** * @brief Handles the Edit button action. */ void on_edit_clicked(); /** * @brief Handles the Remove button action. */ void on_remove_clicked(); /** * @brief Handles selection change events. * @param row Selected row index. */ void on_selection_changed(int row); /** * @brief Refreshes the list widget from the store. */ void refresh_list(); /** * @brief Opens the editor UI for a whitelist entry. * @param name Current whitelist name. * @param entry Entry to edit (modified on success). * @return True when the entry was saved. */ bool edit_entry(const QString& name, WhitelistEntry& entry); /** * @brief Notifies observers that the whitelist collection changed. */ void notify_changed(); /** * @brief Backing store for whitelist data. */ WhitelistStore& store_; /** * @brief List widget showing available whitelists. */ QPointer list_widget_; /** * @brief Add button pointer. */ QPointer add_button_; /** * @brief Edit button pointer. */ QPointer edit_button_; /** * @brief Remove button pointer. */ QPointer remove_button_; /** * @brief Callback invoked after list changes. */ std::function on_lists_changed_; }; #endif ================================================ FILE: app/include/WhitelistStore.hpp ================================================ #ifndef WHITELIST_STORE_HPP #define WHITELIST_STORE_HPP #include #include #include #include class Settings; struct WhitelistEntry { std::vector categories; std::vector subcategories; }; class WhitelistStore { public: explicit WhitelistStore(std::string config_dir); bool load(); bool save() const; std::vector list_names() const; std::optional get(const std::string& name) const; void set(const std::string& name, WhitelistEntry entry); void remove(const std::string& name); bool empty() const { return entries_.empty(); } // Migration helper void ensure_default_from_legacy(const std::vector& cats, const std::vector& subs); void initialize_from_settings(Settings& settings); std::string default_name() const { return default_name_; } private: std::string file_path_; std::unordered_map entries_; std::string default_name_ = "Default"; }; #endif ================================================ FILE: app/include/app_version.hpp ================================================ #pragma once #include "Version.hpp" const Version APP_VERSION = Version{1, 7, 3}; ================================================ FILE: app/include/constants.hpp ================================================ #ifndef CONSTANTS_HPP #define CONSTANTS_HPP constexpr auto APP_NAME = "AI File Sorter"; constexpr auto APP_NAME_DIR = "AIFileSorter"; #endif ================================================ FILE: app/include/external/dotenv.h ================================================ // Copyright (c) 2018 Heikki Johannes Hildén // // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following // disclaimer in the documentation and/or other materials provided // with the distribution. // // * Neither the name of copyright holder nor the names of other // contributors may be used to endorse or promote products derived // from this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /// /// \file dotenv.h /// #pragma once #include #include #include #include #include #include #include /// /// Utility class for loading environment variables from a file. /// /// ### Typical use /// /// Given a file `.env` /// /// \code /// DATABASE_HOST=localhost /// DATABASE_USERNAME=user /// DATABASE_PASSWORD="antipasto" /// \endcode /// /// and a program `example.cpp` /// /// \code /// // example.cpp /// #include /// #include /// /// int main() /// { /// dotenv::init(); /// /// std::cout << std::getenv("DATABASE_USERNAME") << std::endl; /// std::cout << std::getenv("DATABASE_PASSWORD") << std::endl; /// /// return 0; /// } /// \endcode /// /// Compile and run the program, e.g. using, /// /// \code /// c++ example.cpp -o example -I/usr/local/include/laserpants/dotenv-0.9.3 && ./example /// \endcode /// /// and the output is: /// /// \code /// user /// antipasto /// \endcode /// /// \see https://github.com/laserpants/dotenv-cpp /// class dotenv { public: dotenv() = delete; ~dotenv() = delete; static const unsigned char Preserve = 1 << 0; static const int OptionsNone = 0; static void init(const char* filename = ".env"); static void init(int flags, const char* filename = ".env"); static std::string getenv(const char* name, const std::string& def = ""); private: static void do_init(int flags, const char* filename); static std::string strip_quotes(const std::string& str); static std::pair resolve_vars(size_t iline, const std::string& str); static void ltrim(std::string& s); static void rtrim(std::string& s); static void trim(std::string& s); static std::string trim_copy(std::string s); static size_t find_var_start(const std::string& str, size_t pos, std::string& start_tag); static size_t find_var_end(const std::string& str, size_t pos, const std::string& start_tag); }; /// /// Read and initialize environment variables from the `.env` file, or a file /// specified by the \a filename argument. /// /// \param filename a file to read environment variables from /// inline void dotenv::init(const char* filename) { dotenv::do_init(OptionsNone, filename); } /// /// Read and initialize environment variables using the provided configuration /// flags. /// /// By default, if a name is already present in the environment, `dotenv::init()` /// will replace it with the new value. To preserve existing variables, you /// must pass the `Preserve` flag. /// /// \code /// dotenv::init(dotenv::Preserve); /// \endcode /// /// \param flags configuration flags /// \param filename a file to read environment variables from /// inline void dotenv::init(int flags, const char* filename) { dotenv::do_init(flags, filename); } /// /// Wrapper for std::getenv() which also takes a default value, in case the /// variable turns out to be empty. /// /// \param name the name of the variable to look up /// \param def a default value /// /// \returns the value of the environment variable \a name, or \a def if the /// variable is not set /// inline std::string dotenv::getenv(const char* name, const std::string& def) { const char* str = std::getenv(name); return str ? std::string(str) : def; } #ifdef _MSC_VER // https://stackoverflow.com/questions/17258029/c-setenv-undefined-identifier-in-visual-studio inline int setenv(const char *name, const char *value, int overwrite) { int errcode = 0; if (!overwrite) { size_t envsize = 0; errcode = getenv_s(&envsize, NULL, 0, name); if (errcode || envsize) return errcode; } return _putenv_s(name, value); } #endif // _MSC_VER /// /// Look for start of variable expression in input string /// on the form $VARIABLE or ${VARIABLE} /// /// \param str in: string to search in /// \param pos in: search from position /// \param pos out: start tag found /// /// \returns The start position of next variable expression or std::string::npos if not found /// inline size_t dotenv::find_var_start(const std::string& str, size_t pos, std::string& start_tag) { size_t p1 = str.find('$',pos); size_t p2 = str.find("${",pos); size_t pos_var = (std::min)(p1,p2); if(pos_var != std::string::npos) start_tag = (pos_var == p2)? "${":"$"; return pos_var; } /// /// Look for end of variable expression in input string /// on the form $VARIABLE or ${VARIABLE} /// /// \param str in: string to search in /// \param pos in: search from position (result from find_var_start) /// \param pos in: start tag /// /// \returns The next end position of variable expression or std::string::npos if not found /// inline size_t dotenv::find_var_end(const std::string& str, size_t pos, const std::string& start_tag) { char end_tag = (start_tag == "${")? '}':' '; size_t pos_end = str.find(end_tag,pos); // special case when $VARIABLE is at end of str with no trailing whitespace if(pos_end == std::string::npos && end_tag==' ') pos_end = str.length(); return pos_end; } // trim whitespace from left (in place) inline void dotenv::ltrim(std::string& s) { s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](int c) {return !std::isspace(c); })); } // trim whitespace from right (in place) inline void dotenv::rtrim(std::string& s) { s.erase(std::find_if(s.rbegin(), s.rend(), [](int c) {return !std::isspace(c); }).base(), s.end()); } // trim both ends (in place) inline void dotenv::trim(std::string& s) { ltrim(s); rtrim(s); } // trim from both ends (copying) inline std::string dotenv::trim_copy(std::string s) { trim(s); return s; } /// /// Resolve variables of the form $VARIABLE or ${VARIABLE} in a string /// /// \param iline line number in .env file /// \param str the string to be resolved, containing 0 or more variables /// \param ok true on return if no variables found or all variables resolved ok /// /// \returns pair with if ok, or if error /// inline std::pair dotenv::resolve_vars(size_t iline, const std::string& str) { std::string resolved; size_t pos = 0; size_t pre_pos = pos; size_t nvar = 0; bool finished=false; while(!finished) { // look for start of variable expression after pos std::string start_tag; pos = find_var_start(str,pos,start_tag); if(pos != std::string::npos) { // a variable definition detected nvar++; // keep start of variable expression size_t pos_start = pos; size_t lstart = start_tag.length(); // length of start tag size_t lend = (lstart>1)? 1 : 0; // length of end tag // add substring since last variable resolved += str.substr(pre_pos,pos-pre_pos); // look for end of variable expression pos = find_var_end(str,pos,start_tag); if(pos != std::string::npos) { // variable name with decoration std::string var = str.substr(pos_start,pos-pos_start+1); // variable name without decoration std::string env_var = var.substr(lstart,var.length()-lstart-lend); // remove possible whitespace at the end rtrim(env_var); // evaluate environment variable if(const char* env_str = std::getenv(env_var.c_str())) { resolved += env_str; nvar--; // decrement to indicate variable resolved } else { // could not resolve the variable, so don't decrement std::cout << "dotenv: Variable " << var << " is not defined on line " << iline << std::endl; } // skip end tag pre_pos = pos+lend; } } else { // no more variables finished = true; } } // add possible trailing non-whitespace after last variable if(pre_pos < str.length()) { resolved += str.substr(pre_pos); } // nvar must be 0, or else we have an error return std::make_pair(resolved,(nvar==0)); } inline void dotenv::do_init(int flags, const char* filename) { std::ifstream file; std::string line; file.open(filename); if (file) { unsigned int i = 1; while (getline(file, line)) { const auto pos = line.find("="); if (pos == std::string::npos) { std::cout << "dotenv: Ignoring ill-formed assignment on line " << i << ": '" << line << "'" << std::endl; } else { auto name = trim_copy(line.substr(0, pos)); auto line_stripped = strip_quotes(trim_copy(line.substr(pos + 1))); // resolve any contained variable expressions in 'line_stripped' auto p = resolve_vars(i,line_stripped); bool ok = p.second; if(!ok) { std::cout << "dotenv: Ignoring ill-formed assignment on line " << i << ": '" << line << "'" << std::endl; } else { // variable resolved ok, set as environment variable const auto& val = p.first; setenv(name.c_str(), val.c_str(), ~flags & dotenv::Preserve); } } ++i; } } } inline std::string dotenv::strip_quotes(const std::string& str) { const std::size_t len = str.length(); if (len < 2) return str; const char first = str[0]; const char last = str[len - 1]; if (first == last && ('"' == first || '\'' == first)) return str.substr(1, len - 2); return str; } ================================================ FILE: app/includePaths.txt ================================================ # Useful, for example, for VS Code ${workspaceFolder}/** /usr/include/qt /usr/include/qt/QtCore /usr/include/qt/QtGui /usr/include/qt/QtWidgets /usr/include/x86_64-linux-gnu/qt6 /usr/include/x86_64-linux-gnu/qt6/QtCore /usr/include/x86_64-linux-gnu/qt6/QtGui /usr/include/x86_64-linux-gnu/qt6/QtWidgets /usr/lib/x86_64-linux-gnu/qt6/mkspecs ================================================ FILE: app/lib/CategorizationDialog.cpp ================================================ #include "CategorizationDialog.hpp" #include "DatabaseManager.hpp" #include "Logger.hpp" #include "MovableCategorizedFile.hpp" #include "TestHooks.hpp" #include "Utils.hpp" #include "UndoManager.hpp" #include "DryRunPreviewDialog.hpp" #include "DocumentTextAnalyzer.hpp" #include "LlavaImageAnalyzer.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace { TestHooks::CategorizationMoveProbe& move_probe_slot() { static TestHooks::CategorizationMoveProbe probe; return probe; } struct ScopedFlag { bool& ref; explicit ScopedFlag(bool& target) : ref(target) { ref = true; } ~ScopedFlag() { ref = false; } }; void ensure_unique_image_suggested_names(std::vector& files, const std::string& base_dir, bool use_subcategory); QString edit_icon_html(int size = 16); std::string to_lower_copy_str(std::string value) { std::transform(value.begin(), value.end(), value.begin(), [](unsigned char c) { return static_cast(std::tolower(c)); }); return value; } std::string trim_copy(const std::string& value) { std::string result = value; const auto not_space = [](unsigned char ch) { return !std::isspace(ch); }; result.erase(result.begin(), std::find_if(result.begin(), result.end(), not_space)); result.erase(std::find_if(result.rbegin(), result.rend(), not_space).base(), result.end()); return result; } bool is_missing_category_label(const std::string& value) { const std::string trimmed = trim_copy(value); if (trimmed.empty()) { return true; } return to_lower_copy_str(trimmed) == "uncategorized"; } // Dialog for bulk editing category and subcategory values. class BulkEditDialog final : public QDialog { public: explicit BulkEditDialog(bool allow_subcategory, QWidget* parent = nullptr) : QDialog(parent), allow_subcategory_(allow_subcategory) { setWindowTitle(QObject::tr("Edit selected items")); auto* layout = new QVBoxLayout(this); auto* form_layout = new QFormLayout(); category_edit_ = new QLineEdit(this); category_edit_->setPlaceholderText(QObject::tr("Leave empty to keep existing")); form_layout->addRow(QObject::tr("Category"), category_edit_); if (allow_subcategory_) { subcategory_edit_ = new QLineEdit(this); subcategory_edit_->setPlaceholderText(QObject::tr("Leave empty to keep existing")); form_layout->addRow(QObject::tr("Subcategory"), subcategory_edit_); } layout->addLayout(form_layout); auto* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); ok_button_ = buttons->button(QDialogButtonBox::Ok); if (ok_button_) { ok_button_->setEnabled(false); } connect(buttons, &QDialogButtonBox::accepted, this, &QDialog::accept); connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject); connect(category_edit_, &QLineEdit::textChanged, this, &BulkEditDialog::update_ok_state); if (subcategory_edit_) { connect(subcategory_edit_, &QLineEdit::textChanged, this, &BulkEditDialog::update_ok_state); } layout->addWidget(buttons); update_ok_state(); } std::string category() const { return category_edit_ ? category_edit_->text().trimmed().toStdString() : std::string(); } std::string subcategory() const { if (!allow_subcategory_ || !subcategory_edit_) { return std::string(); } return subcategory_edit_->text().trimmed().toStdString(); } private: void update_ok_state() { const bool has_category = category_edit_ && !category_edit_->text().trimmed().isEmpty(); const bool has_subcategory = allow_subcategory_ && subcategory_edit_ && !subcategory_edit_->text().trimmed().isEmpty(); if (ok_button_) { ok_button_->setEnabled(has_category || has_subcategory); } } QLineEdit* category_edit_{nullptr}; QLineEdit* subcategory_edit_{nullptr}; QPushButton* ok_button_{nullptr}; bool allow_subcategory_{false}; }; bool contains_only_allowed_chars(const std::string& value) { for (unsigned char ch : value) { if (std::iscntrl(ch)) { return false; } static const std::string forbidden = R"(<>:"/\|?*)"; if (forbidden.find(static_cast(ch)) != std::string::npos) { return false; } // Everything else is allowed (including non-ASCII letters and punctuation). } return true; } bool has_leading_or_trailing_space_or_dot(const std::string& value) { if (value.empty()) { return false; } const unsigned char first = static_cast(value.front()); const unsigned char last = static_cast(value.back()); return std::isspace(first) || std::isspace(last) || value.front() == '.' || value.back() == '.'; } bool is_reserved_windows_name(const std::string& value) { static const std::vector reserved = { "con","prn","aux","nul", "com1","com2","com3","com4","com5","com6","com7","com8","com9", "lpt1","lpt2","lpt3","lpt4","lpt5","lpt6","lpt7","lpt8","lpt9" }; const std::string lower = to_lower_copy_str(value); return std::find(reserved.begin(), reserved.end(), lower) != reserved.end(); } bool looks_like_extension_label(const std::string& value) { const auto dot_pos = value.rfind('.'); if (dot_pos == std::string::npos || dot_pos == value.size() - 1) { return false; } const std::string ext = value.substr(dot_pos + 1); if (ext.empty() || ext.size() > 5) { return false; } return std::all_of(ext.begin(), ext.end(), [](unsigned char ch) { return std::isalpha(ch); }); } bool validate_labels(const std::string& category, const std::string& subcategory, std::string& error, bool allow_identical = false) { constexpr size_t kMaxLabelLength = 80; if (category.empty() || subcategory.empty()) { error = "Category or subcategory is empty"; return false; } if (category.size() > kMaxLabelLength || subcategory.size() > kMaxLabelLength) { error = "Category or subcategory exceeds max length"; return false; } if (!contains_only_allowed_chars(category) || !contains_only_allowed_chars(subcategory)) { error = "Category or subcategory contains disallowed characters"; return false; } if (looks_like_extension_label(category) || looks_like_extension_label(subcategory)) { error = "Category or subcategory looks like a file extension"; return false; } if (is_reserved_windows_name(category) || is_reserved_windows_name(subcategory)) { error = "Category or subcategory is a reserved name"; return false; } if (!allow_identical && to_lower_copy_str(category) == to_lower_copy_str(subcategory)) { error = "Category and subcategory are identical"; return false; } return true; } std::chrono::system_clock::time_point to_system_clock(std::filesystem::file_time_type file_time) { #if defined(__cpp_lib_chrono) && __cpp_lib_chrono >= 201907L return std::chrono::clock_cast(file_time); #else const auto now = decltype(file_time)::clock::now(); const auto delta = std::chrono::duration_cast(file_time - now); return std::chrono::system_clock::now() + delta; #endif } } // namespace namespace TestHooks { void set_categorization_move_probe(CategorizationMoveProbe probe) { move_probe_slot() = std::move(probe); } void reset_categorization_move_probe() { move_probe_slot() = CategorizationMoveProbe{}; } } // namespace TestHooks CategorizationDialog::CategorizationDialog(DatabaseManager* db_manager, bool show_subcategory_col, const std::string& undo_dir, CategoryLanguage category_language, QWidget* parent) : QDialog(parent), db_manager(db_manager), category_language_(category_language), show_subcategory_column(show_subcategory_col), core_logger(Logger::get_logger("core_logger")), db_logger(Logger::get_logger("db_logger")), ui_logger(Logger::get_logger("ui_logger")), undo_dir_(undo_dir) { resize(1100, 720); setSizeGripEnabled(true); Qt::WindowFlags flags = windowFlags(); flags &= ~Qt::WindowType_Mask; flags |= Qt::Window; flags |= Qt::WindowSystemMenuHint | Qt::WindowMinimizeButtonHint | Qt::WindowMaximizeButtonHint; flags &= ~Qt::MSWindowsFixedSizeDialogHint; setWindowFlags(flags); setMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX); setup_ui(); retranslate_ui(); } bool CategorizationDialog::is_dialog_valid() const { return model != nullptr && table_view != nullptr; } void CategorizationDialog::show_results(const std::vector& files, const std::string& base_dir_override, bool include_subdirectories, bool allow_image_renames, bool allow_document_renames) { categorized_files = files; include_subdirectories_ = include_subdirectories; allow_image_renames_ = allow_image_renames; allow_document_renames_ = allow_document_renames; base_dir_.clear(); if (!base_dir_override.empty()) { base_dir_ = base_dir_override; } else if (!categorized_files.empty()) { base_dir_ = categorized_files.front().file_path; } ensure_unique_image_suggested_names(categorized_files, base_dir_, show_subcategory_column); set_show_rename_column(std::any_of(categorized_files.begin(), categorized_files.end(), [](const CategorizedFile& file) { return !file.suggested_name.empty(); })); update_rename_only_checkbox_state(); apply_category_visibility(); apply_subcategory_visibility(); dry_run_plan_.clear(); clear_move_history(); if (undo_button) { undo_button->setEnabled(false); undo_button->setVisible(false); } { ScopedFlag guard(suppress_item_changed_); populate_model(); } on_rename_images_only_toggled(rename_images_only_checkbox && rename_images_only_checkbox->isChecked()); on_rename_documents_only_toggled(rename_documents_only_checkbox && rename_documents_only_checkbox->isChecked()); update_subcategory_checkbox_state(); exec(); } void CategorizationDialog::setup_ui() { auto* layout = new QVBoxLayout(this); auto* scroll_area = new QScrollArea(this); scroll_area->setWidgetResizable(true); scroll_area->setFrameShape(QFrame::NoFrame); auto* scroll_widget = new QWidget(scroll_area); auto* scroll_layout = new QVBoxLayout(scroll_widget); scroll_layout->setContentsMargins(0, 0, 0, 0); auto* select_layout = new QHBoxLayout(); select_layout->setContentsMargins(0, 0, 0, 0); select_all_checkbox = new QCheckBox(this); select_all_checkbox->setChecked(true); select_highlighted_button = new QPushButton(this); bulk_edit_button = new QPushButton(this); select_layout->addWidget(select_all_checkbox); select_layout->addWidget(select_highlighted_button); select_layout->addWidget(bulk_edit_button); select_layout->addStretch(1); scroll_layout->addLayout(select_layout); show_subcategories_checkbox = new QCheckBox(this); show_subcategories_checkbox->setChecked(show_subcategory_column); scroll_layout->addWidget(show_subcategories_checkbox); dry_run_checkbox = new QCheckBox(this); dry_run_checkbox->setChecked(false); scroll_layout->addWidget(dry_run_checkbox); rename_images_only_checkbox = new QCheckBox(this); rename_images_only_checkbox->setChecked(false); rename_images_only_checkbox->setEnabled(false); scroll_layout->addWidget(rename_images_only_checkbox); rename_documents_only_checkbox = new QCheckBox(this); rename_documents_only_checkbox->setChecked(false); rename_documents_only_checkbox->setEnabled(false); scroll_layout->addWidget(rename_documents_only_checkbox); model = new QStandardItemModel(this); model->setColumnCount(8); table_view = new QTableView(this); table_view->setModel(model); table_view->setSelectionBehavior(QAbstractItemView::SelectRows); table_view->setSelectionMode(QAbstractItemView::ExtendedSelection); table_view->setEditTriggers(QAbstractItemView::DoubleClicked | QAbstractItemView::SelectedClicked | QAbstractItemView::EditKeyPressed); table_view->horizontalHeader()->setStretchLastSection(true); table_view->verticalHeader()->setVisible(false); table_view->horizontalHeader()->setSectionsClickable(true); table_view->horizontalHeader()->setSortIndicatorShown(true); table_view->setSortingEnabled(true); table_view->setColumnHidden(ColumnType, false); table_view->setColumnHidden(ColumnSuggestedName, !show_rename_column); table_view->setColumnHidden(ColumnSubcategory, !show_subcategory_column); table_view->setColumnHidden(ColumnPreview, false); table_view->setColumnWidth(ColumnSelect, 70); table_view->setIconSize(QSize(16, 16)); table_view->setColumnWidth(ColumnType, table_view->iconSize().width() + 12); scroll_layout->addWidget(table_view, 1); auto* tip_label = new QLabel(this); tip_label->setWordWrap(true); QFont tip_font = tip_label->font(); tip_font.setItalic(true); tip_label->setFont(tip_font); tip_label->setTextFormat(Qt::RichText); tip_label->setText(tr("Tip: Click %1 cells to rename them.") .arg(edit_icon_html())); scroll_layout->addWidget(tip_label); confirm_button = new QPushButton(this); continue_button = new QPushButton(this); undo_button = new QPushButton(this); undo_button->setEnabled(false); undo_button->setVisible(false); close_button = new QPushButton(this); close_button->setVisible(false); scroll_area->setWidget(scroll_widget); layout->addWidget(scroll_area, 1); auto* bottom_layout = new QHBoxLayout(); bottom_layout->setContentsMargins(0, 0, 0, 0); bottom_layout->setSpacing(8); bottom_layout->addStretch(1); bottom_layout->addWidget(confirm_button); bottom_layout->addWidget(continue_button); bottom_layout->addWidget(undo_button); bottom_layout->addWidget(close_button); layout->addLayout(bottom_layout); if (auto* screen = this->screen()) { const QRect available = screen->availableGeometry(); const int max_height = static_cast(available.height() * 0.9); setMaximumHeight(max_height); } connect(confirm_button, &QPushButton::clicked, this, &CategorizationDialog::on_confirm_and_sort_button_clicked); connect(continue_button, &QPushButton::clicked, this, &CategorizationDialog::on_continue_later_button_clicked); connect(close_button, &QPushButton::clicked, this, &CategorizationDialog::accept); connect(undo_button, &QPushButton::clicked, this, &CategorizationDialog::on_undo_button_clicked); connect(select_all_checkbox, &QCheckBox::toggled, this, &CategorizationDialog::on_select_all_toggled); connect(select_highlighted_button, &QPushButton::clicked, this, &CategorizationDialog::on_select_highlighted_clicked); connect(bulk_edit_button, &QPushButton::clicked, this, &CategorizationDialog::on_bulk_edit_clicked); connect(model, &QStandardItemModel::itemChanged, this, &CategorizationDialog::on_item_changed); connect(show_subcategories_checkbox, &QCheckBox::toggled, this, &CategorizationDialog::on_show_subcategories_toggled); connect(rename_images_only_checkbox, &QCheckBox::toggled, this, &CategorizationDialog::on_rename_images_only_toggled); connect(rename_documents_only_checkbox, &QCheckBox::toggled, this, &CategorizationDialog::on_rename_documents_only_toggled); auto* select_highlighted_shortcut = new QShortcut(QKeySequence(Qt::CTRL | Qt::Key_Space), this); connect(select_highlighted_shortcut, &QShortcut::activated, this, &CategorizationDialog::on_select_highlighted_clicked); } namespace { QFileIconProvider& file_icon_provider() { static QFileIconProvider provider; return provider; } QIcon fallback_image_icon() { static QIcon icon; if (!icon.isNull()) { return icon; } auto make_pixmap = [](int size) { QPixmap pixmap(size, size); pixmap.fill(Qt::transparent); QPainter painter(&pixmap); painter.setRenderHint(QPainter::Antialiasing, true); QPen frame_pen(QColor(120, 120, 120)); frame_pen.setWidthF(1.0); painter.setPen(frame_pen); painter.setBrush(QColor(240, 240, 240)); painter.drawRoundedRect(QRectF(1, 1, size - 2, size - 2), 2, 2); QRectF image_rect(3, 4, size - 6, size - 7); painter.setPen(Qt::NoPen); painter.setBrush(QColor(140, 200, 245)); painter.drawRect(image_rect); QPolygonF mountain; mountain << QPointF(image_rect.left() + 1, image_rect.bottom() - 1) << QPointF(image_rect.center().x() - 1, image_rect.top() + 2) << QPointF(image_rect.right() - 1, image_rect.bottom() - 1); painter.setBrush(QColor(90, 170, 125)); painter.drawPolygon(mountain); painter.setBrush(QColor(255, 210, 80)); painter.drawEllipse(QPointF(image_rect.right() - 3, image_rect.top() + 3), 1.6, 1.6); return pixmap; }; icon.addPixmap(make_pixmap(16)); icon.addPixmap(make_pixmap(32)); return icon; } #if defined(Q_OS_WIN) bool icons_match(const QIcon& left, const QIcon& right, const QSize& size) { if (left.isNull() || right.isNull()) { return false; } const QPixmap left_pixmap = left.pixmap(size); const QPixmap right_pixmap = right.pixmap(size); if (left_pixmap.isNull() || right_pixmap.isNull()) { return false; } const QImage left_image = left_pixmap.toImage().convertToFormat(QImage::Format_ARGB32_Premultiplied); const QImage right_image = right_pixmap.toImage().convertToFormat(QImage::Format_ARGB32_Premultiplied); if (left_image.size() != right_image.size()) { return false; } return left_image == right_image; } #endif QIcon type_icon(const QString& code, const QString& file_path) { if (auto* style = QApplication::style()) { if (code == QStringLiteral("D")) { return style->standardIcon(QStyle::SP_DirIcon); } if (code == QStringLiteral("I")) { QIcon icon = QIcon::fromTheme(QStringLiteral("image-x-generic")); if (icon.isNull()) { icon = QIcon::fromTheme(QStringLiteral("image")); } if (icon.isNull()) { icon = QIcon::fromTheme(QStringLiteral("image-x-generic-symbolic")); } if (icon.isNull() && !file_path.isEmpty()) { icon = file_icon_provider().icon(QFileInfo(file_path)); } if (icon.isNull()) { icon = fallback_image_icon(); } #if defined(Q_OS_WIN) if (icons_match(icon, style->standardIcon(QStyle::SP_FileIcon), QSize(16, 16))) { icon = fallback_image_icon(); } #endif return icon.isNull() ? style->standardIcon(QStyle::SP_FileIcon) : icon; } return style->standardIcon(QStyle::SP_FileIcon); } return {}; } QIcon edit_icon() { QIcon icon = QIcon::fromTheme(QStringLiteral("edit-rename")); if (!icon.isNull()) { return icon; } icon = QIcon::fromTheme(QStringLiteral("document-edit")); if (!icon.isNull()) { return icon; } if (auto* style = QApplication::style()) { return style->standardIcon(QStyle::SP_FileDialogDetailedView); } return QIcon(); } QString edit_icon_html(int size) { const QIcon icon = edit_icon(); const QPixmap pixmap = icon.pixmap(size, size); if (pixmap.isNull()) { return QStringLiteral("[edit]"); } QByteArray bytes; QBuffer buffer(&bytes); buffer.open(QIODevice::WriteOnly); pixmap.save(&buffer, "PNG"); return QStringLiteral("") .arg(QString::fromLatin1(bytes.toBase64())) .arg(size); } bool is_supported_image_entry(const std::string& file_path, const std::string& file_name, FileType file_type) { if (file_type != FileType::File) { return false; } const auto full_path = Utils::utf8_to_path(file_path) / Utils::utf8_to_path(file_name); return LlavaImageAnalyzer::is_supported_image(full_path); } bool is_supported_document_entry(const std::string& file_path, const std::string& file_name, FileType file_type) { if (file_type != FileType::File) { return false; } const auto full_path = Utils::utf8_to_path(file_path) / Utils::utf8_to_path(file_name); return DocumentTextAnalyzer::is_supported_document(full_path); } std::filesystem::path build_suggested_target_dir(const CategorizedFile& file, const std::string& base_dir_override, bool use_subcategory) { const auto source_dir = Utils::utf8_to_path(file.file_path); const auto base_dir = base_dir_override.empty() ? source_dir : Utils::utf8_to_path(base_dir_override); if (file.rename_only || file.category.empty()) { return source_dir; } const auto category = Utils::utf8_to_path(file.category); if (use_subcategory && !file.subcategory.empty()) { const auto subcategory = Utils::utf8_to_path(file.subcategory); return base_dir / category / subcategory; } return base_dir / category; } struct NumericSuffix { std::string base; int value{0}; bool has_suffix{false}; }; NumericSuffix split_numeric_suffix(const std::string& stem) { NumericSuffix result{stem, 0, false}; const auto pos = stem.rfind('_'); if (pos == std::string::npos || pos + 1 >= stem.size()) { return result; } const std::string suffix = stem.substr(pos + 1); if (suffix.empty()) { return result; } for (unsigned char ch : suffix) { if (!std::isdigit(ch)) { return result; } } int value = 0; try { value = std::stoi(suffix); } catch (...) { return result; } if (value <= 0) { return result; } const std::string base = stem.substr(0, pos); if (base.empty()) { return result; } result.base = base; result.value = value; result.has_suffix = true; return result; } struct ParentheticalSuffix { std::string base; int value{0}; bool has_suffix{false}; }; ParentheticalSuffix split_parenthetical_suffix(const std::string& stem) { ParentheticalSuffix result{stem, 0, false}; if (stem.size() < 4) { return result; } if (stem.back() != ')') { return result; } const auto open_pos = stem.rfind('('); if (open_pos == std::string::npos || open_pos == 0) { return result; } if (open_pos == 0 || stem[open_pos - 1] != ' ') { return result; } const std::string number = stem.substr(open_pos + 1, stem.size() - open_pos - 2); if (number.empty()) { return result; } for (unsigned char ch : number) { if (!std::isdigit(ch)) { return result; } } int value = 0; try { value = std::stoi(number); } catch (...) { return result; } if (value <= 0) { return result; } const std::string base = stem.substr(0, open_pos - 1); if (base.empty()) { return result; } result.base = base; result.value = value; result.has_suffix = true; return result; } std::string build_unique_suggested_name(const std::string& desired_name, const std::filesystem::path& target_dir, std::unordered_set& used_names, std::unordered_map& next_index, bool force_numbering) { auto conflicts = [&](const std::string& candidate) -> bool { const std::string candidate_lower = to_lower_copy_str(candidate); if (used_names.count(candidate_lower) > 0) { return true; } if (!target_dir.empty()) { std::error_code ec; const auto candidate_path = target_dir / Utils::utf8_to_path(candidate); if (std::filesystem::exists(candidate_path, ec)) { return true; } } return false; }; const auto desired_path = Utils::utf8_to_path(desired_name); std::string stem = Utils::path_to_utf8(desired_path.stem()); std::string ext = Utils::path_to_utf8(desired_path.extension()); if (stem.empty()) { stem = desired_name; ext.clear(); } const NumericSuffix suffix = split_numeric_suffix(stem); std::string base_stem = stem; int index = 1; bool has_suffix = false; if (suffix.has_suffix) { base_stem = suffix.base; index = suffix.value; has_suffix = true; } if (!force_numbering && !conflicts(desired_name)) { return desired_name; } if (has_suffix && !conflicts(desired_name)) { return desired_name; } const std::string key = has_suffix ? to_lower_copy_str(base_stem + ext) : to_lower_copy_str(desired_name); auto it = next_index.find(key); if (it != next_index.end()) { index = it->second; } while (true) { std::string candidate = base_stem + "_" + std::to_string(index) + ext; if (!conflicts(candidate)) { next_index[key] = index + 1; return candidate; } ++index; } } std::string build_unique_move_name(const std::string& desired_name, const std::filesystem::path& target_dir, std::unordered_set& used_names, std::unordered_map& next_index) { auto conflicts = [&](const std::string& candidate) -> bool { const std::string candidate_lower = to_lower_copy_str(candidate); if (used_names.count(candidate_lower) > 0) { return true; } if (!target_dir.empty()) { std::error_code ec; const auto candidate_path = target_dir / Utils::utf8_to_path(candidate); if (std::filesystem::exists(candidate_path, ec)) { return true; } } return false; }; if (!conflicts(desired_name)) { return desired_name; } const auto desired_path = Utils::utf8_to_path(desired_name); std::string stem = Utils::path_to_utf8(desired_path.stem()); std::string ext = Utils::path_to_utf8(desired_path.extension()); if (stem.empty()) { stem = desired_name; ext.clear(); } const ParentheticalSuffix suffix = split_parenthetical_suffix(stem); std::string base_stem = suffix.has_suffix ? suffix.base : stem; int index = suffix.has_suffix ? suffix.value : 1; const std::string key = to_lower_copy_str(base_stem + ext); auto it = next_index.find(key); if (it != next_index.end()) { index = std::max(index, it->second); } while (true) { std::string candidate = base_stem + " (" + std::to_string(index) + ")" + ext; if (!conflicts(candidate)) { next_index[key] = index + 1; return candidate; } ++index; } } void ensure_unique_image_suggested_names(std::vector& files, const std::string& base_dir, bool use_subcategory) { std::unordered_map> counts; counts.reserve(files.size()); for (const auto& file : files) { if (file.suggested_name.empty()) { continue; } if (file.rename_applied) { continue; } if (to_lower_copy_str(file.suggested_name) == to_lower_copy_str(file.file_name)) { continue; } if (!is_supported_image_entry(file.file_path, file.file_name, file.type)) { continue; } const auto target_dir = build_suggested_target_dir(file, base_dir, use_subcategory); const std::string dir_key = Utils::path_to_utf8(target_dir); const std::string name_key = to_lower_copy_str(file.suggested_name); counts[dir_key][name_key] += 1; } std::unordered_map> used_names; std::unordered_map> next_index; for (auto& file : files) { if (file.suggested_name.empty()) { continue; } if (file.rename_applied) { continue; } if (to_lower_copy_str(file.suggested_name) == to_lower_copy_str(file.file_name)) { continue; } if (!is_supported_image_entry(file.file_path, file.file_name, file.type)) { continue; } const auto target_dir = build_suggested_target_dir(file, base_dir, use_subcategory); const std::string dir_key = Utils::path_to_utf8(target_dir); const std::string name_key = to_lower_copy_str(file.suggested_name); const bool force_numbering = counts[dir_key][name_key] > 1; auto& dir_used = used_names[dir_key]; auto& dir_next = next_index[dir_key]; const std::string unique_name = build_unique_suggested_name(file.suggested_name, target_dir, dir_used, dir_next, force_numbering); file.suggested_name = unique_name; dir_used.insert(to_lower_copy_str(unique_name)); } } } void CategorizationDialog::ensure_unique_suggested_names_in_model() { if (!model) { return; } struct RowEntry { int row{0}; std::string file_path; std::string file_name; FileType type{FileType::File}; std::string category; std::string subcategory; std::string suggested_name; bool rename_only{false}; bool rename_applied{false}; }; std::vector entries; entries.reserve(model->rowCount()); for (int row = 0; row < model->rowCount(); ++row) { if (!row_is_supported_image(row)) { continue; } auto* file_item = model->item(row, ColumnFile); auto* rename_item = model->item(row, ColumnSuggestedName); if (!file_item || !rename_item) { continue; } const std::string suggested = rename_item->text().toStdString(); if (suggested.empty()) { continue; } RowEntry entry; entry.row = row; entry.file_path = file_item->data(kFilePathRole).toString().toStdString(); if (entry.file_path.empty()) { entry.file_path = base_dir_; } entry.file_name = file_item->text().toStdString(); if (to_lower_copy_str(suggested) == to_lower_copy_str(entry.file_name)) { continue; } entry.type = static_cast(file_item->data(kFileTypeRole).toInt()); entry.rename_only = file_item->data(kRenameOnlyRole).toBool(); entry.rename_applied = file_item->data(kRenameAppliedRole).toBool(); if (entry.rename_applied) { continue; } if (auto* category_item = model->item(row, ColumnCategory)) { entry.category = category_item->text().toStdString(); if (is_missing_category_label(entry.category)) { entry.category.clear(); } } if (auto* subcategory_item = model->item(row, ColumnSubcategory)) { entry.subcategory = subcategory_item->text().toStdString(); if (is_missing_category_label(entry.subcategory)) { entry.subcategory.clear(); } } entry.suggested_name = suggested; entries.push_back(std::move(entry)); } std::unordered_map> counts; counts.reserve(entries.size()); for (const auto& entry : entries) { CategorizedFile file; file.file_path = entry.file_path; file.file_name = entry.file_name; file.type = entry.type; file.category = entry.category; file.subcategory = entry.subcategory; file.rename_only = entry.rename_only; file.suggested_name = entry.suggested_name; file.rename_applied = entry.rename_applied; const auto target_dir = build_suggested_target_dir(file, base_dir_, show_subcategory_column); const std::string dir_key = Utils::path_to_utf8(target_dir); const std::string name_key = to_lower_copy_str(entry.suggested_name); counts[dir_key][name_key] += 1; } std::unordered_map> used_names; std::unordered_map> next_index; for (auto& entry : entries) { CategorizedFile file; file.file_path = entry.file_path; file.file_name = entry.file_name; file.type = entry.type; file.category = entry.category; file.subcategory = entry.subcategory; file.rename_only = entry.rename_only; file.suggested_name = entry.suggested_name; file.rename_applied = entry.rename_applied; const auto target_dir = build_suggested_target_dir(file, base_dir_, show_subcategory_column); const std::string dir_key = Utils::path_to_utf8(target_dir); const std::string name_key = to_lower_copy_str(entry.suggested_name); const bool force_numbering = counts[dir_key][name_key] > 1; auto& dir_used = used_names[dir_key]; auto& dir_next = next_index[dir_key]; const std::string unique_name = build_unique_suggested_name(entry.suggested_name, target_dir, dir_used, dir_next, force_numbering); dir_used.insert(to_lower_copy_str(unique_name)); if (unique_name != entry.suggested_name) { if (auto* rename_item = model->item(entry.row, ColumnSuggestedName)) { rename_item->setText(QString::fromStdString(unique_name)); } entry.suggested_name = unique_name; } } } void CategorizationDialog::populate_model() { ScopedFlag guard(suppress_item_changed_); model->removeRows(0, model->rowCount()); const int type_col_width = table_view ? table_view->iconSize().width() + 12 : 28; if (table_view) { table_view->setColumnWidth(2, type_col_width); } updating_select_all = true; for (const auto& file : categorized_files) { QList row; auto* select_item = new QStandardItem; select_item->setCheckable(true); select_item->setCheckState(Qt::Checked); select_item->setEditable(false); select_item->setData(Qt::AlignCenter, Qt::TextAlignmentRole); auto* file_item = new QStandardItem(QString::fromStdString(file.file_name)); file_item->setEditable(false); file_item->setData(QString::fromStdString(file.file_path), kFilePathRole); file_item->setData(QString::fromStdString(file.file_name), kOriginalFileNameRole); file_item->setData(file.used_consistency_hints, kUsedConsistencyRole); file_item->setData(file.rename_only, kRenameOnlyRole); file_item->setData(static_cast(file.type), kFileTypeRole); const bool rename_locked = file.rename_applied || (!file.suggested_name.empty() && to_lower_copy_str(file.suggested_name) == to_lower_copy_str(file.file_name)); file_item->setData(file.rename_applied, kRenameAppliedRole); file_item->setData(rename_locked, kRenameLockedRole); const bool is_image_entry = is_supported_image_entry(file.file_path, file.file_name, file.type); auto* type_item = new QStandardItem; type_item->setEditable(false); if (file.type == FileType::Directory) { type_item->setData(QStringLiteral("D"), Qt::UserRole); } else if (is_image_entry) { type_item->setData(QStringLiteral("I"), Qt::UserRole); } else { type_item->setData(QStringLiteral("F"), Qt::UserRole); } type_item->setData(Qt::AlignCenter, Qt::TextAlignmentRole); update_type_icon(type_item); const std::string suggested_name = rename_locked ? std::string() : file.suggested_name; auto* suggested_item = new QStandardItem(QString::fromStdString(suggested_name)); const bool allow_rename = !suggested_name.empty(); suggested_item->setEditable(allow_rename); if (allow_rename) { suggested_item->setIcon(edit_icon()); } std::string category_text = file.category; if (is_image_entry && is_missing_category_label(category_text)) { category_text.clear(); } auto* category_item = new QStandardItem(QString::fromStdString(category_text)); category_item->setData(QString::fromStdString(category_text), kOriginalCategoryRole); category_item->setData(QString::fromStdString( file.canonical_category.empty() ? file.category : file.canonical_category), kCanonicalCategoryRole); category_item->setEditable(!file.rename_only); if (!file.rename_only) { category_item->setIcon(edit_icon()); } std::string subcategory_text = file.subcategory; if (is_image_entry && is_missing_category_label(subcategory_text)) { subcategory_text.clear(); } auto* subcategory_item = new QStandardItem(QString::fromStdString(subcategory_text)); subcategory_item->setData(QString::fromStdString(subcategory_text), kOriginalSubcategoryRole); subcategory_item->setData(QString::fromStdString( file.canonical_subcategory.empty() ? file.subcategory : file.canonical_subcategory), kCanonicalSubcategoryRole); subcategory_item->setEditable(!file.rename_only); if (!file.rename_only) { subcategory_item->setIcon(edit_icon()); } auto* status_item = new QStandardItem; status_item->setEditable(false); status_item->setData(static_cast(RowStatus::None), kStatusRole); apply_status_text(status_item); status_item->setForeground(QBrush()); auto* preview_item = new QStandardItem; preview_item->setEditable(false); row << select_item << file_item << type_item << suggested_item << category_item << subcategory_item << status_item << preview_item; model->appendRow(row); update_preview_column(model->rowCount() - 1); } updating_select_all = false; apply_subcategory_visibility(); apply_rename_visibility(); table_view->resizeColumnsToContents(); update_select_all_state(); } void CategorizationDialog::update_type_icon(QStandardItem* item) { if (!item) { return; } const QString code = item->data(Qt::UserRole).toString(); QString full_path; if (code == QStringLiteral("I") && model) { if (auto* file_item = model->item(item->row(), ColumnFile)) { const QString file_name = file_item->text(); const QString base_dir = file_item->data(kFilePathRole).toString(); if (!base_dir.isEmpty()) { full_path = QDir(base_dir).filePath(file_name); } else if (!base_dir_.empty()) { full_path = QDir(QString::fromStdString(base_dir_)).filePath(file_name); } else { full_path = file_name; } } } item->setIcon(type_icon(code, full_path)); item->setText(QString()); } void CategorizationDialog::record_categorization_to_db() { if (!db_manager) { return; } auto entry_is_unchanged = [](const CategorizedFile& cached, const DatabaseManager::ResolvedCategory& resolved, const std::string& suggested_name, bool rename_only, bool used_consistency) { if (cached.rename_only != rename_only) { return false; } if (cached.suggested_name != suggested_name) { return false; } if (cached.used_consistency_hints != used_consistency) { return false; } if (cached.category != resolved.category || cached.subcategory != resolved.subcategory) { return false; } if (!resolved.category.empty() && cached.taxonomy_id != resolved.taxonomy_id) { return false; } return true; }; auto read_role_text = [](QStandardItem* item, int role) { return item && item->data(role).isValid() ? item->data(role).toString().toStdString() : std::string(); }; auto update_category_roles = [](QStandardItem* item, const std::string& display_value, const std::string& canonical_value, int original_role, int canonical_role) { if (!item) { return; } item->setText(QString::fromStdString(display_value)); item->setData(QString::fromStdString(display_value), original_role); item->setData(QString::fromStdString(canonical_value), canonical_role); }; auto resolve_for_storage = [this, &read_role_text](QStandardItem* category_item, QStandardItem* subcategory_item, const std::string& category, const std::string& subcategory) { const std::string original_category = read_role_text(category_item, kOriginalCategoryRole); const std::string original_subcategory = read_role_text(subcategory_item, kOriginalSubcategoryRole); const std::string canonical_category = read_role_text(category_item, kCanonicalCategoryRole); const std::string canonical_subcategory = read_role_text(subcategory_item, kCanonicalSubcategoryRole); const bool unchanged_display = category == original_category && subcategory == original_subcategory && !canonical_category.empty(); if (unchanged_display) { return db_manager->resolve_category(canonical_category, canonical_subcategory); } return db_manager->resolve_category_for_language(category, subcategory, category_language_); }; for (int row = 0; row < model->rowCount(); ++row) { auto* file_item = model->item(row, ColumnFile); if (!file_item) { continue; } bool rename_only = file_item->data(kRenameOnlyRole).toBool(); auto* category_item = model->item(row, ColumnCategory); auto* subcategory_item = model->item(row, ColumnSubcategory); std::string category = category_item ? category_item->text().toStdString() : std::string(); std::string subcategory = show_subcategory_column && subcategory_item ? subcategory_item->text().toStdString() : std::string(); const bool is_image = row_is_supported_image(row); const bool is_document = row_is_supported_document(row); if (is_image || is_document) { if (is_missing_category_label(category)) { category.clear(); } if (is_missing_category_label(subcategory)) { subcategory.clear(); } } if (!rename_only && (is_image || is_document) && category.empty()) { rename_only = true; } const auto* suggested_item = model->item(row, ColumnSuggestedName); const std::string suggested_name = suggested_item ? suggested_item->text().toStdString() : std::string(); const std::string file_name = file_item->text().toStdString(); const std::string file_path = file_item->data(kFilePathRole).toString().toStdString(); const bool used_consistency = file_item->data(kUsedConsistencyRole).toBool(); const FileType file_type = static_cast(file_item->data(kFileTypeRole).toInt()); const auto cached_entry = db_manager->get_categorized_file(file_path, file_name, file_type); if (rename_only) { if (cached_entry) { const auto localized_cached = db_manager->localize_categorized_file(*cached_entry, category_language_); category = localized_cached.category; subcategory = localized_cached.subcategory; } else { category.clear(); subcategory.clear(); } if (is_missing_category_label(category)) { category.clear(); } if (is_missing_category_label(subcategory)) { subcategory.clear(); } if (category_item) { category_item->setText(QString::fromStdString(category)); } if (show_subcategory_column && subcategory_item) { subcategory_item->setText(QString::fromStdString(subcategory)); } if (cached_entry) { update_category_roles(category_item, category, cached_entry->category, kOriginalCategoryRole, kCanonicalCategoryRole); update_category_roles(subcategory_item, subcategory, cached_entry->subcategory, kOriginalSubcategoryRole, kCanonicalSubcategoryRole); } } if (rename_only) { DatabaseManager::ResolvedCategory resolved{0, "", ""}; if (cached_entry && !cached_entry->category.empty()) { resolved.taxonomy_id = cached_entry->taxonomy_id; resolved.category = cached_entry->category; resolved.subcategory = cached_entry->subcategory; } const std::string file_type_label = (file_type == FileType::Directory) ? "D" : "F"; if (cached_entry && entry_is_unchanged(*cached_entry, resolved, suggested_name, rename_only, used_consistency)) { continue; } db_manager->insert_or_update_file_with_categorization( file_name, file_type_label, file_path, resolved, used_consistency, suggested_name, true); continue; } if (!category_item) { continue; } auto resolved = resolve_for_storage(category_item, subcategory_item, category, subcategory); const std::string file_type_label = (file_type == FileType::Directory) ? "D" : "F"; if (cached_entry && entry_is_unchanged(*cached_entry, resolved, suggested_name, rename_only, used_consistency)) { continue; } db_manager->insert_or_update_file_with_categorization( file_name, file_type_label, file_path, resolved, used_consistency, suggested_name); const auto display_resolved = db_manager->localize_category(resolved, category_language_); update_category_roles(category_item, display_resolved.category, resolved.category, kOriginalCategoryRole, kCanonicalCategoryRole); if (show_subcategory_column) { update_category_roles(subcategory_item, display_resolved.subcategory, resolved.subcategory, kOriginalSubcategoryRole, kCanonicalSubcategoryRole); } } } void CategorizationDialog::on_confirm_and_sort_button_clicked() { record_categorization_to_db(); if (categorized_files.empty()) { if (ui_logger) { ui_logger->warn("No categorized files available for sorting."); } return; } const std::string base_dir = base_dir_.empty() ? categorized_files.front().file_path : base_dir_; dry_run_plan_.clear(); clear_move_history(); if (undo_button) { undo_button->setEnabled(false); undo_button->setVisible(false); } const bool dry_run = dry_run_checkbox && dry_run_checkbox->isChecked(); if (dry_run && core_logger) { core_logger->info("Dry run enabled; will not move files."); } std::vector files_not_moved; ScopedFlag guard(suppress_item_changed_); if (include_subdirectories_) { struct CollisionState { std::unordered_set used_names; std::unordered_map next_index; }; std::unordered_map collisions; collisions.reserve(static_cast(model->rowCount())); for (int row_index = 0; row_index < model->rowCount(); ++row_index) { auto* select_item = model->item(row_index, ColumnSelect); if (select_item && select_item->checkState() != Qt::Checked) { continue; } auto* file_item = model->item(row_index, ColumnFile); auto* category_item = model->item(row_index, ColumnCategory); auto* subcategory_item = model->item(row_index, ColumnSubcategory); auto* rename_item = model->item(row_index, ColumnSuggestedName); if (!file_item || !category_item) { continue; } bool rename_only = false; bool used_consistency_hints = false; FileType file_type = FileType::File; if (!resolve_row_flags(row_index, rename_only, used_consistency_hints, file_type)) { continue; } (void)used_consistency_hints; if (rename_only) { continue; } std::string category = category_item->text().toStdString(); if (is_missing_category_label(category)) { continue; } std::string subcategory = show_subcategory_column && subcategory_item ? subcategory_item->text().toStdString() : std::string(); if (is_missing_category_label(subcategory)) { subcategory.clear(); } const std::string file_name = file_item->text().toStdString(); const std::string rename_candidate = rename_item ? rename_item->text().toStdString() : std::string(); std::string source_dir = file_item->data(kFilePathRole).toString().toStdString(); if (source_dir.empty()) { source_dir = base_dir; } CategorizedFile file; file.file_path = source_dir; file.file_name = file_name; file.type = file_type; file.category = category; file.subcategory = subcategory; file.rename_only = false; const auto target_dir = build_suggested_target_dir(file, base_dir, show_subcategory_column); const std::string dir_key = Utils::path_to_utf8(target_dir); auto& state = collisions[dir_key]; const std::string desired_name = resolve_destination_name(file_name, rename_candidate); const std::string unique_name = build_unique_move_name(desired_name, target_dir, state.used_names, state.next_index); state.used_names.insert(to_lower_copy_str(unique_name)); if (unique_name != desired_name) { if (rename_item) { rename_item->setText(QString::fromStdString(unique_name)); } update_preview_column(row_index); } } } for (int row_index = 0; row_index < model->rowCount(); ++row_index) { auto* select_item = model->item(row_index, ColumnSelect); if (select_item && select_item->checkState() != Qt::Checked) { update_status_column(row_index, false, false); continue; } auto* file_item = model->item(row_index, ColumnFile); auto* category_item = model->item(row_index, ColumnCategory); auto* subcategory_item = model->item(row_index, ColumnSubcategory); auto* rename_item = model->item(row_index, ColumnSuggestedName); if (!file_item || !category_item) { update_status_column(row_index, false); continue; } bool rename_only = false; bool used_consistency_hints = false; FileType file_type = FileType::File; if (!resolve_row_flags(row_index, rename_only, used_consistency_hints, file_type)) { update_status_column(row_index, false); continue; } const std::string file_name = file_item->text().toStdString(); const std::string category = category_item->text().toStdString(); const std::string subcategory = show_subcategory_column && subcategory_item ? subcategory_item->text().toStdString() : std::string(); const std::string rename_candidate = rename_item ? rename_item->text().toStdString() : std::string(); std::string source_dir = file_item->data(kFilePathRole).toString().toStdString(); if (source_dir.empty()) { source_dir = base_dir; } handle_selected_row(row_index, file_name, rename_candidate, category, subcategory, source_dir, base_dir, files_not_moved, file_type, rename_only, used_consistency_hints, dry_run); } if (files_not_moved.empty()) { if (core_logger) { core_logger->info("All files have been sorted and moved successfully."); } } else if (ui_logger) { ui_logger->info("Categorization complete. Unmoved files: {}", files_not_moved.size()); } if (dry_run) { // Show preview dialog of planned moves. std::vector entries; entries.reserve(static_cast(model->rowCount())); for (int row = 0; row < model->rowCount(); ++row) { if (auto* select_item = model->item(row, ColumnSelect)) { if (select_item->checkState() != Qt::Checked) { continue; } } const auto* file_item = model->item(row, ColumnFile); const auto* cat_item = model->item(row, ColumnCategory); if (!file_item || !cat_item) { continue; } std::string debug_reason; auto rec = build_preview_record_for_row(row, &debug_reason); if (!rec) { if (core_logger) { core_logger->warn("Dry run preview skipped row {}: {}", row, debug_reason); } continue; } const bool rename_images_only_active = rename_images_only_checkbox && rename_images_only_checkbox->isChecked() && row_is_supported_image(row); std::string to_label; std::string destination; #ifdef _WIN32 const char sep = '\\\\'; #else const char sep = '/'; #endif if (rename_images_only_active) { to_label = rec->destination_file_name; if (!base_dir.empty()) { destination = Utils::path_to_utf8( Utils::utf8_to_path(base_dir) / Utils::utf8_to_path(rec->destination_file_name)); } else { destination = rec->destination; } } else if (rec->rename_only) { to_label = rec->destination_file_name; destination = rec->destination; } else { to_label = rec->category; if (rec->use_subcategory && !rec->subcategory.empty()) { to_label += std::string(1, sep) + rec->subcategory; } to_label += std::string(1, sep) + rec->destination_file_name; destination = rec->destination; } #ifdef _WIN32 std::replace(destination.begin(), destination.end(), '/', '\\'); #endif std::string source_tooltip = rec->source; #ifdef _WIN32 std::replace(source_tooltip.begin(), source_tooltip.end(), '/', '\\'); #endif entries.push_back(DryRunPreviewDialog::Entry{ /*from_label*/ rec->source_file_name, /*to_label*/ to_label, /*source_tooltip*/ source_tooltip, /*destination_tooltip*/ destination}); } if (core_logger) { core_logger->info("Dry run preview entries built: {}", entries.size()); } DryRunPreviewDialog preview_dialog(entries, this); preview_dialog.exec(); // In preview mode, keep the dialog actionable so the user can uncheck Dry run and re-run. if (undo_button) { undo_button->setVisible(false); undo_button->setEnabled(false); } restore_action_buttons(); return; } if (!move_history_.empty() && undo_button) { undo_button->setVisible(true); undo_button->setEnabled(true); } if (!move_history_.empty()) { persist_move_plan(); } show_close_button(); } void CategorizationDialog::handle_selected_row(int row_index, const std::string& file_name, const std::string& rename_candidate, const std::string& category, const std::string& subcategory, const std::string& source_dir, const std::string& base_dir, std::vector& files_not_moved, FileType file_type, bool rename_only, bool used_consistency_hints, bool dry_run) { const std::string destination_name = resolve_destination_name(file_name, rename_candidate); const bool rename_active = destination_name != file_name; auto* category_item_ref = model ? model->item(row_index, ColumnCategory) : nullptr; auto* subcategory_item_ref = model ? model->item(row_index, ColumnSubcategory) : nullptr; auto read_role_text = [](QStandardItem* item, int role) { return item && item->data(role).isValid() ? item->data(role).toString().toStdString() : std::string(); }; auto apply_successful_rename = [this, row_index, &destination_name]() { if (!model) { return; } if (auto* file_item = model->item(row_index, ColumnFile)) { if (!file_item->data(kOriginalFileNameRole).isValid()) { file_item->setData(file_item->text(), kOriginalFileNameRole); } file_item->setData(true, kRenameAppliedRole); file_item->setData(true, kRenameLockedRole); } if (auto* rename_item = model->item(row_index, ColumnSuggestedName)) { rename_item->setText(QString::fromStdString(destination_name)); } update_preview_column(row_index); }; if (auto& probe = move_probe_slot()) { const std::string effective_subcategory = subcategory.empty() ? category : subcategory; probe(TestHooks::CategorizationMoveInfo{ show_subcategory_column, category, effective_subcategory, file_name }); update_status_column(row_index, true, true, rename_active, !rename_only); return; } if (rename_active) { std::string rename_error; if (!validate_filename(destination_name, rename_error)) { update_status_column(row_index, false); files_not_moved.push_back(file_name); if (core_logger) { core_logger->warn("Skipping rename for '{}' due to invalid filename: {} (rename='{}')", file_name, rename_error, destination_name); } return; } } if (rename_only) { if (!rename_active) { update_status_column(row_index, true, true, false, false); return; } const auto source_path = Utils::utf8_to_path(source_dir) / Utils::utf8_to_path(file_name); const auto dest_path = Utils::utf8_to_path(source_dir) / Utils::utf8_to_path(destination_name); if (dry_run) { const std::string source_display = Utils::path_to_utf8(source_path); const std::string dest_display = Utils::path_to_utf8(dest_path); set_preview_status(row_index, dest_display); dry_run_plan_.push_back(PreviewRecord{ source_display, dest_display, file_name, destination_name, std::string(), std::string(), false, true}); if (core_logger) { core_logger->info("Dry run: would rename '{}' to '{}'", source_display, dest_display); } return; } if (!std::filesystem::exists(source_path)) { update_status_column(row_index, false); files_not_moved.push_back(file_name); if (core_logger) { core_logger->warn("Source file missing when renaming '{}'", file_name); } return; } if (std::filesystem::exists(dest_path)) { update_status_column(row_index, false); files_not_moved.push_back(file_name); if (core_logger) { core_logger->warn("Destination already exists for rename '{}'", destination_name); } return; } try { std::filesystem::rename(source_path, dest_path); update_status_column(row_index, true, true, rename_active, false); std::error_code ec; const std::uintmax_t size_bytes = std::filesystem::file_size(dest_path, ec); std::time_t mtime_value = 0; if (!ec) { const auto ftime = std::filesystem::last_write_time(dest_path, ec); if (!ec) { const auto sys = to_system_clock(ftime); mtime_value = std::chrono::system_clock::to_time_t(sys); } } record_move_for_undo(row_index, Utils::path_to_utf8(source_path), Utils::path_to_utf8(dest_path), size_bytes, mtime_value); if (db_manager) { DatabaseManager::ResolvedCategory resolved{0, "", ""}; if (auto cached = db_manager->get_categorized_file(source_dir, file_name, file_type)) { if (!is_missing_category_label(cached->category)) { resolved.category = cached->category; if (!is_missing_category_label(cached->subcategory)) { resolved.subcategory = cached->subcategory; } resolved.taxonomy_id = cached->taxonomy_id; } } const std::string file_type_label = (file_type == FileType::Directory) ? "D" : "F"; db_manager->remove_file_categorization(source_dir, file_name, file_type); db_manager->insert_or_update_file_with_categorization( destination_name, file_type_label, source_dir, resolved, used_consistency_hints, destination_name, true, true); } apply_successful_rename(); } catch (const std::exception& ex) { update_status_column(row_index, false); files_not_moved.push_back(file_name); if (core_logger) { core_logger->error("Failed to rename '{}': {}", file_name, ex.what()); } } return; } const std::string effective_subcategory = subcategory.empty() ? category : subcategory; std::string validation_error; const bool allow_identical = !show_subcategory_column; if (!validate_labels(category, effective_subcategory, validation_error, allow_identical)) { update_status_column(row_index, false); files_not_moved.push_back(file_name); if (core_logger) { core_logger->warn("Skipping move for '{}' due to invalid category/subcategory: {} (cat='{}', sub='{}')", file_name, validation_error, category, effective_subcategory); } return; } try { MovableCategorizedFile categorized_file( source_dir, base_dir, category, effective_subcategory, file_name, destination_name); const auto preview_paths = categorized_file.preview_move_paths(show_subcategory_column); if (dry_run) { set_preview_status(row_index, preview_paths.destination); dry_run_plan_.push_back(PreviewRecord{ preview_paths.source, preview_paths.destination, file_name, destination_name, category, effective_subcategory, show_subcategory_column, false}); if (core_logger) { core_logger->info("Dry run: would move '{}' to '{}'", preview_paths.source, preview_paths.destination); } return; } categorized_file.create_cat_dirs(show_subcategory_column); bool moved = categorized_file.move_file(show_subcategory_column); update_status_column(row_index, moved, true, rename_active && moved, moved); if (!moved) { files_not_moved.push_back(file_name); if (core_logger) { core_logger->warn("File {} already exists in the destination.", file_name); } } else { std::error_code ec; const std::uintmax_t size_bytes = std::filesystem::file_size(Utils::utf8_to_path(preview_paths.destination), ec); std::time_t mtime_value = 0; if (!ec) { const auto ftime = std::filesystem::last_write_time(Utils::utf8_to_path(preview_paths.destination), ec); if (!ec) { const auto sys = to_system_clock(ftime); mtime_value = std::chrono::system_clock::to_time_t(sys); } } record_move_for_undo(row_index, preview_paths.source, preview_paths.destination, size_bytes, mtime_value); if (db_manager && (rename_active || include_subdirectories_)) { const std::string original_category = read_role_text(category_item_ref, kOriginalCategoryRole); const std::string original_subcategory = read_role_text(subcategory_item_ref, kOriginalSubcategoryRole); const std::string canonical_category = read_role_text(category_item_ref, kCanonicalCategoryRole); const std::string canonical_subcategory = read_role_text(subcategory_item_ref, kCanonicalSubcategoryRole); const std::string original_effective_subcategory = original_subcategory.empty() ? original_category : original_subcategory; const bool unchanged_display = category == original_category && effective_subcategory == original_effective_subcategory && !canonical_category.empty(); auto resolved = unchanged_display ? db_manager->resolve_category(canonical_category, canonical_subcategory) : db_manager->resolve_category_for_language(category, effective_subcategory, category_language_); const std::string source_db_dir = include_subdirectories_ ? source_dir : base_dir; std::string destination_db_dir = base_dir; if (include_subdirectories_) { const auto dest_parent = Utils::utf8_to_path(preview_paths.destination).parent_path(); destination_db_dir = Utils::path_to_utf8(dest_parent); } std::string suggested_name; bool rename_applied = rename_active; if (rename_active) { suggested_name = destination_name; } else if (auto cached = db_manager->get_categorized_file(source_db_dir, file_name, file_type)) { suggested_name = cached->suggested_name; rename_applied = cached->rename_applied; } db_manager->remove_file_categorization(source_db_dir, file_name, file_type); db_manager->insert_or_update_file_with_categorization( destination_name, file_type == FileType::Directory ? "D" : "F", destination_db_dir, resolved, used_consistency_hints, suggested_name, false, rename_applied); } if (rename_active) { apply_successful_rename(); } } } catch (const std::exception& ex) { update_status_column(row_index, false); files_not_moved.push_back(file_name); if (core_logger) { core_logger->error("Failed to move '{}': {}", file_name, ex.what()); } } } void CategorizationDialog::on_continue_later_button_clicked() { record_categorization_to_db(); accept(); } void CategorizationDialog::on_undo_button_clicked() { if (!undo_move_history()) { return; } update_status_after_undo(); restore_action_buttons(); clear_move_history(); if (undo_button) { undo_button->setEnabled(false); undo_button->setVisible(false); } } void CategorizationDialog::show_close_button() { if (confirm_button) { confirm_button->setVisible(false); } if (continue_button) { continue_button->setVisible(false); } if (close_button) { close_button->setVisible(true); } } void CategorizationDialog::restore_action_buttons() { if (confirm_button) { confirm_button->setVisible(true); } if (continue_button) { continue_button->setVisible(true); } if (close_button) { close_button->setVisible(false); } } void CategorizationDialog::update_status_column(int row, bool success, bool attempted, bool renamed, bool moved) { if (auto* status_item = model->item(row, ColumnStatus)) { RowStatus status = RowStatus::None; if (!attempted) { status = RowStatus::NotSelected; status_item->setForeground(QBrush(Qt::gray)); } else if (success) { if (renamed && moved) { status = RowStatus::RenamedAndMoved; } else if (renamed) { status = RowStatus::Renamed; } else { status = RowStatus::Moved; } status_item->setForeground(QBrush(Qt::darkGreen)); } else { status = RowStatus::Skipped; status_item->setForeground(QBrush(Qt::red)); } if (status == RowStatus::None) { status_item->setForeground(QBrush()); } status_item->setData(static_cast(status), kStatusRole); apply_status_text(status_item); } } void CategorizationDialog::on_select_all_toggled(bool checked) { apply_select_all(checked); } std::vector CategorizationDialog::selected_row_indices() const { std::vector rows; if (!table_view || !table_view->selectionModel()) { return rows; } const QModelIndexList selected = table_view->selectionModel()->selectedRows(); rows.reserve(selected.size()); for (const auto& index : selected) { rows.push_back(index.row()); } std::sort(rows.begin(), rows.end()); rows.erase(std::unique(rows.begin(), rows.end()), rows.end()); return rows; } void CategorizationDialog::on_select_highlighted_clicked() { const auto rows = selected_row_indices(); if (rows.empty()) { QMessageBox::information(this, tr("No items selected"), tr("Highlight one or more rows to select them for processing.")); return; } apply_check_state_to_rows(rows, Qt::Checked); } void CategorizationDialog::record_move_for_undo(int row, const std::string& source, const std::string& destination, std::uintmax_t size_bytes, std::time_t mtime) { move_history_.push_back(MoveRecord{row, source, destination, size_bytes, mtime}); } void CategorizationDialog::remove_empty_parent_directories(const std::string& destination) { std::filesystem::path dest_path = Utils::utf8_to_path(destination); auto parent = dest_path.parent_path(); while (!parent.empty()) { std::error_code ec; if (!std::filesystem::exists(parent)) { parent = parent.parent_path(); continue; } if (std::filesystem::is_directory(parent) && std::filesystem::is_empty(parent, ec) && !ec) { std::filesystem::remove(parent, ec); parent = parent.parent_path(); } else { break; } } } bool CategorizationDialog::move_file_back(const std::string& source, const std::string& destination) { std::error_code ec; auto destination_path = Utils::utf8_to_path(destination); auto source_path = Utils::utf8_to_path(source); if (!std::filesystem::exists(destination_path)) { if (core_logger) { core_logger->warn("Undo skipped; destination '{}' missing", destination); } return false; } std::filesystem::create_directories(source_path.parent_path(), ec); try { std::filesystem::rename(destination_path, source_path); } catch (const std::filesystem::filesystem_error& ex) { if (core_logger) { core_logger->error("Undo move failed '{}' -> '{}': {}", destination, source, ex.what()); } return false; } remove_empty_parent_directories(destination); return true; } bool CategorizationDialog::undo_move_history() { if (move_history_.empty()) { return false; } bool any_success = false; for (auto it = move_history_.rbegin(); it != move_history_.rend(); ++it) { if (move_file_back(it->source_path, it->destination_path)) { any_success = true; } } if (any_success && core_logger) { core_logger->info("Undo completed for {} moved file(s)", move_history_.size()); } return any_success; } void CategorizationDialog::update_status_after_undo() { ScopedFlag guard(suppress_item_changed_); for (const auto& record : move_history_) { update_status_column(record.row_index, false, false); if (!model) { continue; } auto* file_item = model->item(record.row_index, ColumnFile); if (!file_item) { continue; } const auto source_path = Utils::utf8_to_path(record.source_path); const std::string source_name = Utils::path_to_utf8(source_path.filename()); if (!source_name.empty() && file_item->text().toStdString() != source_name) { file_item->setText(QString::fromStdString(source_name)); } update_preview_column(record.row_index); } } void CategorizationDialog::apply_select_all(bool checked) { updating_select_all = true; for (int row = 0; row < model->rowCount(); ++row) { if (auto* item = model->item(row, ColumnSelect)) { item->setCheckState(checked ? Qt::Checked : Qt::Unchecked); } update_preview_column(row); } updating_select_all = false; update_select_all_state(); } void CategorizationDialog::apply_check_state_to_rows(const std::vector& rows, Qt::CheckState state) { if (!model) { return; } updating_select_all = true; for (int row : rows) { if (row < 0 || row >= model->rowCount()) { continue; } if (auto* item = model->item(row, ColumnSelect)) { item->setCheckState(state); } update_preview_column(row); } updating_select_all = false; update_select_all_state(); } void CategorizationDialog::on_bulk_edit_clicked() { if (!model || !table_view) { return; } if (table_view->isColumnHidden(ColumnCategory)) { QMessageBox::information(this, tr("Bulk edit unavailable"), tr("Bulk editing categories is unavailable while picture rename-only mode is active.")); return; } const auto rows = selected_row_indices(); if (rows.empty()) { QMessageBox::information(this, tr("No items selected"), tr("Highlight one or more rows to edit their categories.")); return; } const bool allow_subcategory = !table_view->isColumnHidden(ColumnSubcategory); BulkEditDialog dialog(allow_subcategory, this); if (dialog.exec() != QDialog::Accepted) { return; } const std::string category = dialog.category(); const std::string subcategory = dialog.subcategory(); if (category.empty() && subcategory.empty()) { return; } for (int row : rows) { bool rename_only = false; bool used_consistency_hints = false; FileType file_type = FileType::File; if (!resolve_row_flags(row, rename_only, used_consistency_hints, file_type)) { continue; } if (rename_only) { continue; } if (!category.empty()) { if (auto* category_item = model->item(row, ColumnCategory)) { category_item->setText(QString::fromStdString(category)); } } if (allow_subcategory && !subcategory.empty()) { if (auto* subcategory_item = model->item(row, ColumnSubcategory)) { subcategory_item->setText(QString::fromStdString(subcategory)); } } } } void CategorizationDialog::on_show_subcategories_toggled(bool checked) { show_subcategory_column = checked; apply_subcategory_visibility(); apply_rename_only_row_visibility(); for (int row = 0; row < model->rowCount(); ++row) { update_preview_column(row); } } void CategorizationDialog::on_rename_images_only_toggled(bool checked) { if (!model) { return; } ScopedFlag guard(suppress_item_changed_); for (int row = 0; row < model->rowCount(); ++row) { if (!row_is_supported_image(row)) { continue; } auto* file_item = model->item(row, ColumnFile); if (!file_item) { continue; } file_item->setData(checked, kRenameOnlyRole); if (auto* category_item = model->item(row, ColumnCategory)) { category_item->setEditable(!checked); category_item->setIcon(checked ? QIcon() : edit_icon()); } if (auto* subcategory_item = model->item(row, ColumnSubcategory)) { subcategory_item->setEditable(!checked); subcategory_item->setIcon(checked ? QIcon() : edit_icon()); } } ensure_unique_suggested_names_in_model(); for (int row = 0; row < model->rowCount(); ++row) { if (!row_is_supported_image(row)) { continue; } update_preview_column(row); } dry_run_plan_.clear(); apply_category_visibility(); apply_subcategory_visibility(); apply_rename_only_row_visibility(); update_subcategory_checkbox_state(); } void CategorizationDialog::on_rename_documents_only_toggled(bool checked) { if (!model) { return; } ScopedFlag guard(suppress_item_changed_); for (int row = 0; row < model->rowCount(); ++row) { if (!row_is_supported_document(row)) { continue; } auto* file_item = model->item(row, ColumnFile); if (!file_item) { continue; } file_item->setData(checked, kRenameOnlyRole); if (auto* category_item = model->item(row, ColumnCategory)) { category_item->setEditable(!checked); category_item->setIcon(checked ? QIcon() : edit_icon()); } if (auto* subcategory_item = model->item(row, ColumnSubcategory)) { subcategory_item->setEditable(!checked); subcategory_item->setIcon(checked ? QIcon() : edit_icon()); } } ensure_unique_suggested_names_in_model(); for (int row = 0; row < model->rowCount(); ++row) { if (!row_is_supported_document(row)) { continue; } update_preview_column(row); } dry_run_plan_.clear(); apply_category_visibility(); apply_subcategory_visibility(); apply_rename_only_row_visibility(); update_subcategory_checkbox_state(); } void CategorizationDialog::apply_subcategory_visibility() { if (table_view) { const bool rename_images_active = rename_images_only_checkbox && rename_images_only_checkbox->isChecked(); const bool rename_documents_active = rename_documents_only_checkbox && rename_documents_only_checkbox->isChecked(); auto should_hide_row = [&](int row) { if (rename_images_active && row_is_supported_image(row)) { return true; } if (rename_documents_active && row_is_supported_document(row)) { return true; } return false; }; auto should_show_category_column = [&]() { if (!rename_images_active && !rename_documents_active) { return true; } if (!model) { return true; } for (int row = 0; row < model->rowCount(); ++row) { if (should_hide_row(row)) { continue; } auto* item = model->item(row, ColumnCategory); if (item && !item->text().trimmed().isEmpty()) { return true; } if (item && item->data(kHiddenCategoryRole).isValid() && !item->data(kHiddenCategoryRole).toString().trimmed().isEmpty()) { return true; } } return false; }; const bool show_category_column = should_show_category_column(); const bool hide_subcategory = !show_subcategory_column || !show_category_column; table_view->setColumnHidden(ColumnSubcategory, hide_subcategory); table_view->setColumnHidden(ColumnPreview, false); if (model) { auto update_item = [](QStandardItem* item, int role, bool hide) { if (!item) { return; } if (hide) { if (!item->data(role).isValid() && !item->text().trimmed().isEmpty()) { item->setData(item->text(), role); } item->setText(QString()); } else if (item->data(role).isValid()) { item->setText(item->data(role).toString()); item->setData(QVariant(), role); } }; for (int row = 0; row < model->rowCount(); ++row) { const bool hide_row = show_subcategory_column && show_category_column && (rename_images_active || rename_documents_active) && should_hide_row(row); update_item(model->item(row, ColumnSubcategory), kHiddenSubcategoryRole, hide_row); } } } } void CategorizationDialog::apply_category_visibility() { if (table_view) { const bool rename_images_active = rename_images_only_checkbox && rename_images_only_checkbox->isChecked(); const bool rename_documents_active = rename_documents_only_checkbox && rename_documents_only_checkbox->isChecked(); auto should_hide_row = [&](int row) { if (rename_images_active && row_is_supported_image(row)) { return true; } if (rename_documents_active && row_is_supported_document(row)) { return true; } return false; }; bool show_category_column = true; if ((rename_images_active || rename_documents_active) && model) { show_category_column = false; for (int row = 0; row < model->rowCount(); ++row) { if (should_hide_row(row)) { continue; } auto* item = model->item(row, ColumnCategory); if (item && !item->text().trimmed().isEmpty()) { show_category_column = true; break; } if (item && item->data(kHiddenCategoryRole).isValid() && !item->data(kHiddenCategoryRole).toString().trimmed().isEmpty()) { show_category_column = true; break; } } } table_view->setColumnHidden(ColumnCategory, !show_category_column); if (bulk_edit_button) { bulk_edit_button->setEnabled(show_category_column); } if (model) { auto update_item = [](QStandardItem* item, int role, bool hide) { if (!item) { return; } if (hide) { if (!item->data(role).isValid() && !item->text().trimmed().isEmpty()) { item->setData(item->text(), role); } item->setText(QString()); } else if (item->data(role).isValid()) { item->setText(item->data(role).toString()); item->setData(QVariant(), role); } }; for (int row = 0; row < model->rowCount(); ++row) { const bool hide_row = show_category_column && (rename_images_active || rename_documents_active) && should_hide_row(row); update_item(model->item(row, ColumnCategory), kHiddenCategoryRole, hide_row); } } } } void CategorizationDialog::apply_rename_only_row_visibility() { if (!table_view || !model) { return; } for (int row = 0; row < model->rowCount(); ++row) { bool hide_row = false; if (rename_images_only_checkbox && rename_images_only_checkbox->isChecked() && row_is_supported_image(row) && row_is_already_renamed_with_category(row)) { hide_row = true; } if (rename_documents_only_checkbox && rename_documents_only_checkbox->isChecked() && row_is_supported_document(row) && row_is_already_renamed_with_category(row)) { hide_row = true; } table_view->setRowHidden(row, hide_row); } } void CategorizationDialog::apply_rename_visibility() { if (table_view) { table_view->setColumnHidden(ColumnSuggestedName, !show_rename_column); } } void CategorizationDialog::update_rename_only_checkbox_state() { if (!rename_images_only_checkbox) { return; } bool has_images = false; bool all_rename_only = true; for (const auto& file : categorized_files) { if (!is_supported_image_entry(file.file_path, file.file_name, file.type)) { continue; } has_images = true; if (!file.rename_only) { all_rename_only = false; } } QSignalBlocker blocker(rename_images_only_checkbox); const bool enable_images_checkbox = has_images && allow_image_renames_; rename_images_only_checkbox->setEnabled(enable_images_checkbox); rename_images_only_checkbox->setChecked(enable_images_checkbox && all_rename_only); if (rename_documents_only_checkbox) { bool has_documents = false; bool all_doc_rename_only = true; for (const auto& file : categorized_files) { if (!is_supported_document_entry(file.file_path, file.file_name, file.type)) { continue; } has_documents = true; if (!file.rename_only) { all_doc_rename_only = false; } } QSignalBlocker doc_blocker(rename_documents_only_checkbox); const bool enable_documents_checkbox = has_documents && allow_document_renames_; rename_documents_only_checkbox->setEnabled(enable_documents_checkbox); rename_documents_only_checkbox->setChecked(enable_documents_checkbox && all_doc_rename_only); } update_subcategory_checkbox_state(); } void CategorizationDialog::update_subcategory_checkbox_state() { if (!show_subcategories_checkbox || !model) { return; } const bool rename_only_active = (rename_images_only_checkbox && rename_images_only_checkbox->isChecked()) || (rename_documents_only_checkbox && rename_documents_only_checkbox->isChecked()); const bool enable_checkbox = !rename_only_active; QSignalBlocker blocker(show_subcategories_checkbox); show_subcategories_checkbox->setEnabled(enable_checkbox); if (!enable_checkbox) { show_subcategory_column = false; show_subcategories_checkbox->setChecked(false); apply_subcategory_visibility(); } } bool CategorizationDialog::row_is_supported_image(int row) const { if (!model || row < 0 || row >= model->rowCount()) { return false; } auto* file_item = model->item(row, ColumnFile); if (!file_item) { return false; } const std::string file_name = file_item->text().toStdString(); const std::string file_path = file_item->data(kFilePathRole).toString().toStdString(); const FileType file_type = static_cast(file_item->data(kFileTypeRole).toInt()); return is_supported_image_entry(file_path, file_name, file_type); } bool CategorizationDialog::row_is_supported_document(int row) const { if (!model || row < 0 || row >= model->rowCount()) { return false; } auto* file_item = model->item(row, ColumnFile); if (!file_item) { return false; } const std::string file_name = file_item->text().toStdString(); const std::string file_path = file_item->data(kFilePathRole).toString().toStdString(); const FileType file_type = static_cast(file_item->data(kFileTypeRole).toInt()); return is_supported_document_entry(file_path, file_name, file_type); } bool CategorizationDialog::row_is_already_renamed_with_category(int row) const { if (!model || row < 0 || row >= model->rowCount()) { return false; } auto* file_item = model->item(row, ColumnFile); if (!file_item) { return false; } if (!file_item->data(kRenameLockedRole).toBool()) { return false; } auto* category_item = model->item(row, ColumnCategory); std::string category = category_item ? category_item->text().toStdString() : std::string(); if (is_missing_category_label(category)) { category.clear(); } if (category.empty()) { return false; } if (!show_subcategory_column) { return true; } auto* subcategory_item = model->item(row, ColumnSubcategory); std::string subcategory = subcategory_item ? subcategory_item->text().toStdString() : std::string(); if (is_missing_category_label(subcategory)) { subcategory.clear(); } return !subcategory.empty(); } std::optional CategorizationDialog::compute_preview_path(int row) const { auto rec = build_preview_record_for_row(row); if (rec) { return rec->destination; } return std::nullopt; } std::optional CategorizationDialog::build_preview_record_for_row(int row, std::string* debug_reason) const { auto fail = [&](std::string reason) -> std::optional { if (debug_reason) { *debug_reason = std::move(reason); } return std::nullopt; }; if (!model || row < 0 || row >= model->rowCount()) { return fail("Invalid model or row"); } if (base_dir_.empty()) { return fail("Base dir empty"); } const auto* file_item = model->item(row, ColumnFile); const auto* category_item = model->item(row, ColumnCategory); const auto* subcategory_item = model->item(row, ColumnSubcategory); const auto* rename_item = model->item(row, ColumnSuggestedName); if (!file_item || !category_item) { return fail("Missing file/category item"); } const std::string file_name = file_item->text().toStdString(); std::string source_dir = file_item->data(kFilePathRole).toString().toStdString(); if (source_dir.empty()) { source_dir = base_dir_; } const std::string rename_candidate = rename_item ? rename_item->text().toStdString() : std::string(); const std::string destination_name = resolve_destination_name(file_name, rename_candidate); const bool rename_active = destination_name != file_name; bool rename_only = false; bool used_consistency_hints = false; FileType file_type = FileType::File; if (!resolve_row_flags(row, rename_only, used_consistency_hints, file_type)) { return fail("Missing row metadata"); } (void)used_consistency_hints; (void)file_type; if (rename_active) { std::string rename_error; if (!validate_filename(destination_name, rename_error)) { return fail("Invalid rename: " + rename_error); } } if (rename_only) { const auto source_path = Utils::utf8_to_path(source_dir) / Utils::utf8_to_path(file_name); const auto destination_path = Utils::utf8_to_path(source_dir) / Utils::utf8_to_path(destination_name); return PreviewRecord{ Utils::path_to_utf8(source_path), Utils::path_to_utf8(destination_path), file_name, destination_name, std::string(), std::string(), false, true}; } const std::string category = category_item->text().toStdString(); const std::string subcategory = show_subcategory_column && subcategory_item ? subcategory_item->text().toStdString() : std::string(); const std::string effective_subcategory = subcategory.empty() ? category : subcategory; std::string validation_error; const bool allow_identical = !show_subcategory_column; if (!validate_labels(category, effective_subcategory, validation_error, allow_identical)) { return fail("Validation failed: " + validation_error); } try { MovableCategorizedFile categorized_file(source_dir, base_dir_, category, effective_subcategory, file_name, destination_name); const auto preview_paths = categorized_file.preview_move_paths(show_subcategory_column); return PreviewRecord{ preview_paths.source, preview_paths.destination, file_name, destination_name, category, effective_subcategory, show_subcategory_column, false}; } catch (...) { return fail("Exception building preview record"); } } std::string CategorizationDialog::resolve_destination_name(const std::string& original_name, const std::string& rename_candidate) const { std::string trimmed = trim_copy(rename_candidate); if (trimmed.empty()) { return original_name; } if (trimmed == original_name) { return original_name; } const std::filesystem::path original_path = Utils::utf8_to_path(original_name); const std::filesystem::path candidate_path = Utils::utf8_to_path(trimmed); if (!candidate_path.has_extension() && original_path.has_extension()) { return Utils::path_to_utf8(candidate_path) + original_path.extension().string(); } return trimmed; } bool CategorizationDialog::validate_filename(const std::string& name, std::string& error) const { if (name.empty()) { error = "Filename is empty"; return false; } if (name == "." || name == "..") { error = "Filename is invalid"; return false; } if (!contains_only_allowed_chars(name)) { error = "Filename contains disallowed characters"; return false; } if (has_leading_or_trailing_space_or_dot(name)) { error = "Filename has leading/trailing space or dot"; return false; } const auto path = Utils::utf8_to_path(name); const std::string stem = Utils::path_to_utf8(path.stem()); if (stem.empty()) { error = "Filename is missing a base name"; return false; } if (is_reserved_windows_name(stem)) { error = "Filename is a reserved name"; return false; } return true; } bool CategorizationDialog::resolve_row_flags(int row, bool& rename_only, bool& used_consistency_hints, FileType& file_type) const { if (!model || row < 0 || row >= model->rowCount()) { return false; } auto* file_item = model->item(row, ColumnFile); if (!file_item) { return false; } rename_only = file_item->data(kRenameOnlyRole).toBool(); used_consistency_hints = file_item->data(kUsedConsistencyRole).toBool(); file_type = static_cast(file_item->data(kFileTypeRole).toInt()); if (!rename_only && (row_is_supported_image(row) || row_is_supported_document(row))) { auto* category_item = model->item(row, ColumnCategory); if (category_item) { const std::string category_text = category_item->text().toStdString(); if (is_missing_category_label(category_text)) { rename_only = true; } } } return true; } void CategorizationDialog::update_preview_column(int row) { if (!model || row < 0 || row >= model->rowCount()) { return; } auto* preview_item = model->item(row, ColumnPreview); if (!preview_item) { return; } if (rename_images_only_checkbox && rename_images_only_checkbox->isChecked() && row_is_supported_image(row)) { preview_item->setText(QStringLiteral("-")); preview_item->setToolTip(QString()); return; } if (rename_documents_only_checkbox && rename_documents_only_checkbox->isChecked() && row_is_supported_document(row)) { preview_item->setText(QStringLiteral("-")); preview_item->setToolTip(QString()); return; } const auto preview = compute_preview_path(row); if (preview) { std::string display = *preview; #ifdef _WIN32 std::replace(display.begin(), display.end(), '/', '\\'); #endif preview_item->setText(QString::fromStdString(display)); preview_item->setToolTip(QString::fromStdString(display)); } else { preview_item->setText(QStringLiteral("-")); preview_item->setToolTip(QString()); } } void CategorizationDialog::set_preview_status(int row, const std::string& destination) { if (!model || row < 0 || row >= model->rowCount()) { return; } if (auto* status_item = model->item(row, ColumnStatus)) { status_item->setData(static_cast(RowStatus::Preview), kStatusRole); status_item->setText(tr("Preview")); status_item->setForeground(QBrush(Qt::blue)); std::string display = destination; #ifdef _WIN32 std::replace(display.begin(), display.end(), '/', '\\'); #endif status_item->setToolTip(QString::fromStdString(display)); } } void CategorizationDialog::persist_move_plan() { if (undo_dir_.empty() || base_dir_.empty() || move_history_.empty()) { return; } std::vector entries; entries.reserve(move_history_.size()); for (const auto& rec : move_history_) { entries.push_back(UndoManager::Entry{ rec.source_path, rec.destination_path, rec.size_bytes, rec.mtime}); } UndoManager manager(undo_dir_); manager.save_plan(base_dir_, entries, core_logger); } void CategorizationDialog::clear_move_history() { move_history_.clear(); } void CategorizationDialog::retranslate_ui() { setWindowTitle(tr("Review and Confirm")); const auto set_text_if = [](auto* widget, const QString& text) { if (widget) { widget->setText(text); } }; set_text_if(select_all_checkbox, tr("Select all")); set_text_if(select_highlighted_button, tr("Select highlighted")); set_text_if(bulk_edit_button, tr("Edit selected...")); set_text_if(show_subcategories_checkbox, tr("Create subcategory folders")); set_text_if(dry_run_checkbox, tr("Dry run (preview only, do not move files)")); set_text_if(rename_images_only_checkbox, tr("Do not categorize picture files (only rename)")); set_text_if(rename_documents_only_checkbox, tr("Do not categorize document files (only rename)")); set_text_if(confirm_button, tr("Confirm and Process")); set_text_if(continue_button, tr("Continue Later")); set_text_if(undo_button, tr("Undo this change")); set_text_if(close_button, tr("Close")); if (select_highlighted_button) { select_highlighted_button->setToolTip(tr("Mark highlighted rows for processing (Ctrl+Space).")); } if (bulk_edit_button) { bulk_edit_button->setToolTip(tr("Apply category/subcategory values to highlighted rows.")); } if (model) { model->setHorizontalHeaderLabels(QStringList{ tr("Process"), tr("File"), tr("Type"), tr("Suggested filename"), tr("Category"), tr("Subcategory"), tr("Status"), tr("Planned destination") }); for (int row = 0; row < model->rowCount(); ++row) { if (auto* type_item = model->item(row, ColumnType)) { update_type_icon(type_item); type_item->setTextAlignment(Qt::AlignCenter); } if (auto* status_item = model->item(row, ColumnStatus)) { apply_status_text(status_item); } } } } void CategorizationDialog::apply_status_text(QStandardItem* item) const { if (!item) { return; } switch (status_from_item(item)) { case RowStatus::Moved: item->setText(tr("Moved")); break; case RowStatus::Renamed: item->setText(tr("Renamed")); break; case RowStatus::RenamedAndMoved: item->setText(tr("Renamed & Moved")); break; case RowStatus::Skipped: item->setText(tr("Skipped")); break; case RowStatus::Preview: item->setText(tr("Preview")); break; case RowStatus::NotSelected: item->setText(tr("Not selected")); break; case RowStatus::None: default: item->setText(QString()); break; } } CategorizationDialog::RowStatus CategorizationDialog::status_from_item(const QStandardItem* item) const { if (!item) { return RowStatus::None; } bool ok = false; const int value = item->data(kStatusRole).toInt(&ok); if (!ok) { return RowStatus::None; } const RowStatus status = static_cast(value); switch (status) { case RowStatus::None: case RowStatus::Moved: case RowStatus::Renamed: case RowStatus::RenamedAndMoved: case RowStatus::Skipped: case RowStatus::NotSelected: case RowStatus::Preview: return status; } return RowStatus::None; } void CategorizationDialog::on_item_changed(QStandardItem* item) { if (!item || updating_select_all || suppress_item_changed_) { return; } if (item->column() == ColumnSelect) { update_select_all_state(); } else if (item->column() == ColumnCategory || item->column() == ColumnSubcategory || item->column() == ColumnSuggestedName) { if ((item->column() == ColumnCategory || item->column() == ColumnSubcategory) && (row_is_supported_image(item->row()) || row_is_supported_document(item->row()))) { const std::string text = item->text().toStdString(); if (is_missing_category_label(text)) { ScopedFlag guard(suppress_item_changed_); item->setText(QString()); } } update_preview_column(item->row()); if (item->column() == ColumnCategory || item->column() == ColumnSubcategory) { update_subcategory_checkbox_state(); } } // invalidate preview plan only on user-facing edits (selection/category fields) if (item->column() == ColumnSelect || item->column() == ColumnCategory || item->column() == ColumnSubcategory || item->column() == ColumnSuggestedName) { dry_run_plan_.clear(); } } void CategorizationDialog::update_select_all_state() { if (!select_all_checkbox) { return; } bool all_checked = true; for (int row = 0; row < model->rowCount(); ++row) { if (auto* item = model->item(row, ColumnSelect)) { if (item->checkState() != Qt::Checked) { all_checked = false; break; } } } QSignalBlocker blocker(select_all_checkbox); select_all_checkbox->setChecked(all_checked); } void CategorizationDialog::changeEvent(QEvent* event) { QDialog::changeEvent(event); if (event && event->type() == QEvent::LanguageChange) { retranslate_ui(); for (int row = 0; row < model->rowCount(); ++row) { update_preview_column(row); } } } void CategorizationDialog::closeEvent(QCloseEvent* event) { record_categorization_to_db(); QDialog::closeEvent(event); } void CategorizationDialog::set_show_subcategory_column(bool enabled) { if (show_subcategory_column == enabled) { return; } show_subcategory_column = enabled; if (show_subcategories_checkbox) { QSignalBlocker blocker(show_subcategories_checkbox); show_subcategories_checkbox->setChecked(enabled); } apply_subcategory_visibility(); update_subcategory_checkbox_state(); } void CategorizationDialog::set_show_rename_column(bool enabled) { if (show_rename_column == enabled) { return; } show_rename_column = enabled; apply_rename_visibility(); } #ifdef AI_FILE_SORTER_TEST_BUILD void CategorizationDialog::test_set_entries(const std::vector& files) { categorized_files = files; include_subdirectories_ = false; base_dir_.clear(); if (!categorized_files.empty()) { base_dir_ = categorized_files.front().file_path; } ensure_unique_image_suggested_names(categorized_files, base_dir_, show_subcategory_column); set_show_rename_column(std::any_of(categorized_files.begin(), categorized_files.end(), [](const CategorizedFile& file) { return !file.suggested_name.empty(); })); update_rename_only_checkbox_state(); apply_category_visibility(); apply_subcategory_visibility(); populate_model(); on_rename_images_only_toggled(rename_images_only_checkbox && rename_images_only_checkbox->isChecked()); on_rename_documents_only_toggled(rename_documents_only_checkbox && rename_documents_only_checkbox->isChecked()); update_subcategory_checkbox_state(); } void CategorizationDialog::test_trigger_confirm() { on_confirm_and_sort_button_clicked(); } void CategorizationDialog::test_trigger_undo() { on_undo_button_clicked(); } bool CategorizationDialog::test_undo_enabled() const { return undo_button && undo_button->isEnabled(); } #endif ================================================ FILE: app/lib/CategorizationProgressDialog.cpp ================================================ #include "CategorizationProgressDialog.hpp" #include "DocumentTextAnalyzer.hpp" #include "LlavaImageAnalyzer.hpp" #include "Logger.hpp" #include "MainApp.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include CategorizationProgressDialog::CategorizationProgressDialog(QWidget* parent, MainApp* main_app, bool show_subcategory_col) : QDialog(parent), main_app(main_app) { resize(900, 650); setup_ui(show_subcategory_col); retranslate_ui(); } void CategorizationProgressDialog::setup_ui(bool /*show_subcategory_col*/) { auto* layout = new QVBoxLayout(this); layout->setSpacing(10); stage_list_label = new QLabel(this); stage_list_label->setTextFormat(Qt::RichText); layout->addWidget(stage_list_label); summary_label = new QLabel(this); layout->addWidget(summary_label); status_table = new QTableWidget(this); status_table->setColumnCount(2); status_table->setSelectionMode(QAbstractItemView::NoSelection); status_table->setSelectionBehavior(QAbstractItemView::SelectRows); status_table->setEditTriggers(QAbstractItemView::NoEditTriggers); status_table->setAlternatingRowColors(true); status_table->setShowGrid(false); status_table->verticalHeader()->setVisible(false); layout->addWidget(status_table, 2); log_label = new QLabel(this); layout->addWidget(log_label); text_view = new QPlainTextEdit(this); text_view->setReadOnly(true); text_view->setLineWrapMode(QPlainTextEdit::WidgetWidth); layout->addWidget(text_view, 1); auto* button_layout = new QHBoxLayout(); button_layout->addStretch(1); stop_button = new QPushButton(this); QIcon stop_icon = QIcon::fromTheme(QStringLiteral("process-stop")); if (stop_icon.isNull()) { stop_icon = QIcon(style()->standardIcon(QStyle::SP_BrowserStop)); } stop_button->setIcon(stop_icon); stop_button->setIconSize(QSize(18, 18)); button_layout->addWidget(stop_button); layout->addLayout(button_layout); connect(stop_button, &QPushButton::clicked, this, &CategorizationProgressDialog::request_stop); spinner_timer = new QTimer(this); spinner_timer->setInterval(140); connect(spinner_timer, &QTimer::timeout, this, &CategorizationProgressDialog::refresh_spinner); } void CategorizationProgressDialog::show() { QDialog::show(); if (text_view) { text_view->moveCursor(QTextCursor::End); } } void CategorizationProgressDialog::hide() { if (spinner_timer) { spinner_timer->stop(); } QDialog::hide(); } void CategorizationProgressDialog::append_text(const std::string& text) { if (!text_view) { if (auto logger = Logger::get_logger("core_logger")) { logger->error("Progress dialog text view is null"); } return; } QString qt_text = QString::fromStdString(text); if (!qt_text.endsWith('\n')) { qt_text.append('\n'); } text_view->appendPlainText(qt_text); QScrollBar* scroll = text_view->verticalScrollBar(); if (scroll) { scroll->setValue(scroll->maximum()); } } void CategorizationProgressDialog::configure_stages(const std::vector& stages) { spinner_frame_index_ = 0; active_stage_order_.clear(); active_stage_.reset(); item_states_.clear(); for (auto& stage_state : stage_states_) { stage_state.enabled = false; stage_state.item_keys.clear(); } if (status_table) { status_table->setRowCount(0); } std::unordered_set seen_stages; std::unordered_set seen_items; std::vector all_items; for (const auto& stage : stages) { if (!seen_stages.contains(stage.id)) { seen_stages.insert(stage.id); active_stage_order_.push_back(stage.id); stage_states_[stage_index(stage.id)].enabled = true; } auto& stage_state = stage_states_[stage_index(stage.id)]; for (const auto& entry : stage.items) { const std::string key = make_item_key(entry.full_path, entry.type); stage_state.item_keys.insert(key); if (!seen_items.contains(key)) { seen_items.insert(key); all_items.push_back(entry); } } } if (!active_stage_order_.empty()) { active_stage_ = active_stage_order_.front(); } rebuild_headers(); for (const auto& entry : all_items) { upsert_item(entry); } refresh_stage_overview(); refresh_summary(); if (!has_in_progress_item() && spinner_timer) { spinner_timer->stop(); } } void CategorizationProgressDialog::set_stage_items(StageId stage_id, const std::vector& items) { ensure_stage_enabled(stage_id); auto& stage_state = stage_states_[stage_index(stage_id)]; stage_state.item_keys.clear(); for (const auto& entry : items) { const std::string key = make_item_key(entry.full_path, entry.type); stage_state.item_keys.insert(key); upsert_item(entry); } const std::size_t idx = stage_index(stage_id); for (auto& [key, state] : item_states_) { if (stage_state.item_keys.contains(key)) { if (state.stage_statuses[idx] == ItemStatus::NotApplicable) { state.stage_statuses[idx] = ItemStatus::Pending; } } else { state.stage_statuses[idx] = ItemStatus::NotApplicable; } } for (const auto& [key, state] : item_states_) { (void)key; refresh_row(state.row); } refresh_stage_overview(); refresh_summary(); } void CategorizationProgressDialog::set_active_stage(StageId stage_id) { const auto& stage_state = stage_states_[stage_index(stage_id)]; if (!stage_state.enabled) { return; } active_stage_ = stage_id; refresh_stage_overview(); refresh_summary(); if (const auto in_progress_row = find_stage_row(stage_id, ItemStatus::InProgress)) { ensure_row_visible(*in_progress_row); return; } if (const auto pending_row = find_stage_row(stage_id, ItemStatus::Pending)) { ensure_row_visible(*pending_row); } } void CategorizationProgressDialog::mark_stage_item_pending(StageId stage_id, const FileEntry& entry) { set_stage_item_status(stage_id, entry, ItemStatus::Pending); } void CategorizationProgressDialog::mark_stage_item_in_progress(StageId stage_id, const FileEntry& entry) { set_stage_item_status(stage_id, entry, ItemStatus::InProgress); } void CategorizationProgressDialog::mark_stage_item_completed(StageId stage_id, const FileEntry& entry) { set_stage_item_status(stage_id, entry, ItemStatus::Completed); } void CategorizationProgressDialog::request_stop() { if (!main_app) { return; } main_app->report_progress( tr("[STOP] Analysis will stop after the current item is processed.") .toUtf8() .toStdString()); main_app->request_stop_analysis(); } std::string CategorizationProgressDialog::make_item_key(const std::string& full_path, FileType type) { return full_path + "|" + std::to_string(static_cast(type)); } std::size_t CategorizationProgressDialog::stage_index(StageId stage_id) { switch (stage_id) { case StageId::ImageAnalysis: return 0; case StageId::DocumentAnalysis: return 1; case StageId::Categorization: default: return 2; } } QString CategorizationProgressDialog::stage_label(StageId stage_id) const { switch (stage_id) { case StageId::ImageAnalysis: return tr("Image analysis"); case StageId::DocumentAnalysis: return tr("Document analysis"); case StageId::Categorization: default: return tr("Categorization"); } } CategorizationProgressDialog::DisplayType CategorizationProgressDialog::classify_display_type(const FileEntry& entry) { if (entry.type == FileType::Directory) { return DisplayType::Directory; } if (LlavaImageAnalyzer::is_supported_image(entry.full_path)) { return DisplayType::Image; } if (DocumentTextAnalyzer::is_supported_document(entry.full_path)) { return DisplayType::Document; } return DisplayType::File; } QString CategorizationProgressDialog::display_type_label(DisplayType display_type) const { switch (display_type) { case DisplayType::Directory: return tr("Directory"); case DisplayType::Image: return tr("Image"); case DisplayType::Document: return tr("Document"); case DisplayType::File: default: return tr("File"); } } int CategorizationProgressDialog::column_for_stage(StageId stage_id) const { for (std::size_t i = 0; i < active_stage_order_.size(); ++i) { if (active_stage_order_[i] == stage_id) { return static_cast(2 + i); } } return -1; } void CategorizationProgressDialog::ensure_stage_enabled(StageId stage_id) { auto& stage_state = stage_states_[stage_index(stage_id)]; if (!stage_state.enabled) { stage_state.enabled = true; if (std::find(active_stage_order_.begin(), active_stage_order_.end(), stage_id) == active_stage_order_.end()) { active_stage_order_.push_back(stage_id); } } if (!active_stage_.has_value()) { active_stage_ = stage_id; } rebuild_headers(); } void CategorizationProgressDialog::upsert_stage_item(StageId stage_id, const FileEntry& entry) { ensure_stage_enabled(stage_id); const std::string key = make_item_key(entry.full_path, entry.type); auto& stage_state = stage_states_[stage_index(stage_id)]; stage_state.item_keys.insert(key); upsert_item(entry); auto it = item_states_.find(key); if (it == item_states_.end()) { return; } const std::size_t idx = stage_index(stage_id); if (it->second.stage_statuses[idx] == ItemStatus::NotApplicable) { it->second.stage_statuses[idx] = ItemStatus::Pending; } } void CategorizationProgressDialog::upsert_item(const FileEntry& entry) { if (!status_table) { return; } const std::string key = make_item_key(entry.full_path, entry.type); if (item_states_.contains(key)) { return; } const int row = status_table->rowCount(); status_table->insertRow(row); auto* file_item = new QTableWidgetItem(QString::fromStdString(entry.file_name)); file_item->setToolTip(QString::fromStdString(entry.full_path)); status_table->setItem(row, 0, file_item); auto* type_item = new QTableWidgetItem(display_type_label(classify_display_type(entry))); type_item->setTextAlignment(Qt::AlignCenter); status_table->setItem(row, 1, type_item); ItemState state; state.row = row; state.display_type = classify_display_type(entry); for (std::size_t i = 0; i < kStageCount; ++i) { const auto& stage_state = stage_states_[i]; if (stage_state.enabled && stage_state.item_keys.contains(key)) { state.stage_statuses[i] = ItemStatus::Pending; } else { state.stage_statuses[i] = ItemStatus::NotApplicable; } } item_states_.emplace(key, state); refresh_row(row); } void CategorizationProgressDialog::set_stage_item_status(StageId stage_id, const FileEntry& entry, ItemStatus status) { upsert_stage_item(stage_id, entry); const std::string key = make_item_key(entry.full_path, entry.type); auto it = item_states_.find(key); if (it == item_states_.end()) { return; } ItemState& state = it->second; const std::size_t idx = stage_index(stage_id); if (state.stage_statuses[idx] == status) { if (status == ItemStatus::InProgress) { refresh_row(state.row); ensure_row_visible(state.row); } return; } state.stage_statuses[idx] = status; refresh_row(state.row); refresh_summary(); if (!spinner_timer) { if (status == ItemStatus::InProgress) { ensure_row_visible(state.row); } return; } if (has_in_progress_item()) { if (!spinner_timer->isActive()) { spinner_timer->start(); } } else { spinner_timer->stop(); } if (status == ItemStatus::InProgress) { ensure_row_visible(state.row); } } void CategorizationProgressDialog::rebuild_headers() { if (!status_table) { return; } const int stage_col_count = static_cast(active_stage_order_.size()); status_table->setColumnCount(2 + stage_col_count); QStringList headers; headers << tr("File") << tr("Type"); for (StageId stage_id : active_stage_order_) { headers << stage_label(stage_id); } status_table->setHorizontalHeaderLabels(headers); auto* header = status_table->horizontalHeader(); if (!header) { return; } header->setStretchLastSection(false); header->setSectionResizeMode(0, QHeaderView::Stretch); header->setSectionResizeMode(1, QHeaderView::ResizeToContents); for (int col = 2; col < status_table->columnCount(); ++col) { header->setSectionResizeMode(col, QHeaderView::ResizeToContents); } } void CategorizationProgressDialog::refresh_stage_overview() { if (!stage_list_label) { return; } if (active_stage_order_.empty()) { stage_list_label->setText(QString()); return; } QStringList lines; for (std::size_t i = 0; i < active_stage_order_.size(); ++i) { const StageId stage_id = active_stage_order_[i]; QString line = tr("Stage %1: %2") .arg(static_cast(i + 1)) .arg(stage_label(stage_id)); if (active_stage_.has_value() && active_stage_.value() == stage_id) { line = QStringLiteral("%1").arg(line); } lines << line; } stage_list_label->setText(lines.join(QStringLiteral("
"))); } CategorizationProgressDialog::ItemStatus CategorizationProgressDialog::stage_status_for_row( const ItemState& state, StageId stage_id) const { return state.stage_statuses[stage_index(stage_id)]; } std::optional CategorizationProgressDialog::find_stage_row(StageId stage_id, ItemStatus status) const { std::optional best_row; const std::size_t idx = stage_index(stage_id); for (const auto& [key, item] : item_states_) { (void)key; if (item.stage_statuses[idx] != status) { continue; } if (!best_row.has_value() || item.row < *best_row) { best_row = item.row; } } return best_row; } void CategorizationProgressDialog::ensure_row_visible(int row) { if (!status_table || row < 0 || row >= status_table->rowCount()) { return; } auto* anchor_item = status_table->item(row, 0); if (!anchor_item) { return; } status_table->scrollToItem(anchor_item, QAbstractItemView::EnsureVisible); } void CategorizationProgressDialog::refresh_row(int row) { if (!status_table || row < 0 || row >= status_table->rowCount()) { return; } const ItemState* state = nullptr; for (const auto& [key, item] : item_states_) { (void)key; if (item.row == row) { state = &item; break; } } if (!state) { return; } auto* type_item = status_table->item(row, 1); if (!type_item) { type_item = new QTableWidgetItem(); status_table->setItem(row, 1, type_item); } type_item->setText(display_type_label(state->display_type)); type_item->setTextAlignment(Qt::AlignCenter); static const QString kSpinnerFrames[] = { QStringLiteral("◐"), QStringLiteral("◓"), QStringLiteral("◑"), QStringLiteral("◒") }; for (StageId stage_id : active_stage_order_) { const int col = column_for_stage(stage_id); if (col < 0) { continue; } auto* stage_item = status_table->item(row, col); if (!stage_item) { stage_item = new QTableWidgetItem(); status_table->setItem(row, col, stage_item); } const ItemStatus status = stage_status_for_row(*state, stage_id); switch (status) { case ItemStatus::NotApplicable: stage_item->setText(QStringLiteral("—")); stage_item->setForeground(QColor(150, 150, 150)); break; case ItemStatus::Pending: stage_item->setText(QStringLiteral("○ %1").arg(tr("Pending"))); stage_item->setForeground(QColor(120, 120, 120)); break; case ItemStatus::InProgress: stage_item->setText(QStringLiteral("%1 %2") .arg(kSpinnerFrames[spinner_frame_index_ % 4], tr("In progress"))); stage_item->setForeground(QColor(33, 150, 243)); break; case ItemStatus::Completed: stage_item->setText(QStringLiteral("✓ %1").arg(tr("Complete"))); stage_item->setForeground(QColor(46, 125, 50)); break; } stage_item->setTextAlignment(Qt::AlignCenter); } } void CategorizationProgressDialog::refresh_summary() { if (!summary_label) { return; } if (!active_stage_.has_value()) { summary_label->setText(tr("Processed 0/0 | In progress: 0 | Pending: 0")); return; } const StageId current_stage = active_stage_.value(); const auto& stage_state = stage_states_[stage_index(current_stage)]; int processed = 0; int in_progress = 0; int pending = 0; for (const auto& key : stage_state.item_keys) { auto it = item_states_.find(key); if (it == item_states_.end()) { continue; } const ItemStatus status = it->second.stage_statuses[stage_index(current_stage)]; switch (status) { case ItemStatus::Completed: ++processed; break; case ItemStatus::InProgress: ++in_progress; break; case ItemStatus::Pending: ++pending; break; case ItemStatus::NotApplicable: default: break; } } const int total = static_cast(stage_state.item_keys.size()); summary_label->setText(tr("Processed %1/%2 | In progress: %3 | Pending: %4") .arg(processed) .arg(total) .arg(in_progress) .arg(pending)); } void CategorizationProgressDialog::refresh_spinner() { if (!has_in_progress_item()) { if (spinner_timer) { spinner_timer->stop(); } return; } spinner_frame_index_ = (spinner_frame_index_ + 1) % 4; for (const auto& [key, item] : item_states_) { (void)key; for (StageId stage_id : active_stage_order_) { if (item.stage_statuses[stage_index(stage_id)] == ItemStatus::InProgress) { refresh_row(item.row); break; } } } } bool CategorizationProgressDialog::has_in_progress_item() const { for (const auto& [key, item] : item_states_) { (void)key; for (StageId stage_id : active_stage_order_) { if (item.stage_statuses[stage_index(stage_id)] == ItemStatus::InProgress) { return true; } } } return false; } void CategorizationProgressDialog::changeEvent(QEvent* event) { QDialog::changeEvent(event); if (event && event->type() == QEvent::LanguageChange) { retranslate_ui(); } } void CategorizationProgressDialog::retranslate_ui() { setWindowTitle(tr("Analyzing Files")); if (stop_button) { stop_button->setText(tr("Stop Analysis")); } if (log_label) { log_label->setText(tr("Activity log")); } rebuild_headers(); refresh_stage_overview(); for (const auto& [key, item] : item_states_) { (void)key; refresh_row(item.row); } refresh_summary(); } ================================================ FILE: app/lib/CategorizationService.cpp ================================================ #include "CategorizationService.hpp" #include "Settings.hpp" #include "CategoryLanguage.hpp" #include "DatabaseManager.hpp" #include "ILLMClient.hpp" #include "LLMErrors.hpp" #include "Utils.hpp" #if __has_include() #include #elif __has_include() #include #else #error "jsoncpp headers not found. Install jsoncpp development files." #endif #include #include #include #include #include #include #include #include #include #include #include namespace { constexpr const char* kLocalTimeoutEnv = "AI_FILE_SORTER_LOCAL_LLM_TIMEOUT"; constexpr const char* kRemoteTimeoutEnv = "AI_FILE_SORTER_REMOTE_LLM_TIMEOUT"; constexpr const char* kCustomTimeoutEnv = "AI_FILE_SORTER_CUSTOM_LLM_TIMEOUT"; constexpr size_t kMaxConsistencyHints = 5; constexpr size_t kMaxLabelLength = 80; std::string to_lower_copy_str(std::string value); std::string trim_copy(std::string value) { auto not_space = [](unsigned char ch) { return !std::isspace(ch); }; value.erase(value.begin(), std::find_if(value.begin(), value.end(), not_space)); value.erase(std::find_if(value.rbegin(), value.rend(), not_space).base(), value.end()); return value; } std::string collapse_spaces_copy(std::string value) { std::string collapsed; collapsed.reserve(value.size()); bool previous_space = false; for (unsigned char ch : value) { if (std::isspace(ch)) { if (!previous_space) { collapsed.push_back(' '); } previous_space = true; continue; } collapsed.push_back(static_cast(ch)); previous_space = false; } return trim_copy(std::move(collapsed)); } std::string strip_wrapping_punctuation(std::string value) { auto is_wrapping = [](unsigned char ch) { switch (ch) { case '"': case '\'': case '`': case '(': case ')': case '[': case ']': case '{': case '}': case '<': case '>': return true; default: return false; } }; while (!value.empty() && (std::isspace(static_cast(value.front())) || is_wrapping(static_cast(value.front())))) { value.erase(value.begin()); } while (!value.empty() && (std::isspace(static_cast(value.back())) || is_wrapping(static_cast(value.back())) || value.back() == '.' || value.back() == ',' || value.back() == ':' || value.back() == ';')) { value.pop_back(); } return value; } std::string strip_trailing_parenthetical_gloss(std::string value) { value = trim_copy(std::move(value)); while (true) { const auto open = value.rfind(" ("); if (open == std::string::npos) { break; } std::string gloss = trim_copy(value.substr(open + 2)); if (!gloss.empty() && gloss.back() == ')') { gloss.pop_back(); gloss = trim_copy(std::move(gloss)); } const bool has_alpha_chars = std::any_of(gloss.begin(), gloss.end(), [](unsigned char ch) { return std::isalpha(ch); }); if (!has_alpha_chars) { break; } value = trim_copy(value.substr(0, open)); } return value; } std::size_t find_case_insensitive(const std::string& value, std::string_view needle) { const std::string lower_value = to_lower_copy_str(value); std::string lower_needle(needle); std::transform(lower_needle.begin(), lower_needle.end(), lower_needle.begin(), [](unsigned char ch) { return static_cast(std::tolower(ch)); }); return lower_value.find(lower_needle); } std::string strip_explanatory_suffix(std::string value) { static const std::vector markers = { " (based on", " (note", " (since", " - this ", " - based on", " because ", " based on ", " which ", " since ", " however ", " specifically ", " indicating ", " indicates ", " commonly ", " related to " }; std::size_t cut = std::string::npos; for (const std::string_view marker : markers) { const auto pos = find_case_insensitive(value, marker); if (pos != std::string::npos && (cut == std::string::npos || pos < cut)) { cut = pos; } } if (cut != std::string::npos) { value.resize(cut); } return strip_wrapping_punctuation(collapse_spaces_copy(std::move(value))); } std::string extract_category_phrase(std::string value) { struct PhrasePattern { std::string_view prefix; std::string_view suffix; }; static const std::vector patterns = { {"falls under the ", " category"}, {"falls under ", " category"}, {"belongs to the ", " category"}, {"belongs to ", " category"}, {"categorized as ", ""}, {"classified as ", ""}, {"category is ", ""}, {"category would be ", ""} }; const std::string lower = to_lower_copy_str(value); for (const auto& pattern : patterns) { const auto start = lower.find(pattern.prefix); if (start == std::string::npos) { continue; } const std::size_t content_start = start + pattern.prefix.size(); std::size_t content_end = value.size(); if (!pattern.suffix.empty()) { content_end = lower.find(pattern.suffix, content_start); if (content_end == std::string::npos || content_end <= content_start) { continue; } } return value.substr(content_start, content_end - content_start); } return value; } std::string strip_inline_label_artifacts(std::string value, bool category_label) { const std::vector markers = category_label ? std::vector{ ", subcategory", ", sub category", " - subcategory", " - sub category", "; subcategory", "; sub category", " subcategory:", " sub category:" } : std::vector{ ", category", ", main category", " - category", " - main category", "; category", "; main category", " category:", " main category:" }; std::size_t cut = std::string::npos; for (const std::string_view marker : markers) { const auto pos = find_case_insensitive(value, marker); if (pos != std::string::npos && (cut == std::string::npos || pos < cut)) { cut = pos; } } if (cut != std::string::npos) { value.resize(cut); } return trim_copy(std::move(value)); } std::string normalize_candidate_label(std::string value, bool category_label) { value = strip_wrapping_punctuation(collapse_spaces_copy(trim_copy(std::move(value)))); if (value.empty()) { return value; } if (category_label) { value = extract_category_phrase(std::move(value)); } value = strip_explanatory_suffix(std::move(value)); value = strip_trailing_parenthetical_gloss(std::move(value)); value = strip_inline_label_artifacts(std::move(value), category_label); return strip_wrapping_punctuation(collapse_spaces_copy(std::move(value))); } std::string strip_list_prefix(std::string line) { line = trim_copy(std::move(line)); if (line.empty()) { return line; } if ((line.front() == '-' || line.front() == '*') && line.size() > 1 && std::isspace(static_cast(line[1]))) { return trim_copy(line.substr(1)); } size_t idx = 0; while (idx < line.size() && std::isdigit(static_cast(line[idx]))) { ++idx; } if (idx > 0 && idx + 1 < line.size() && (line[idx] == '.' || line[idx] == ')') && std::isspace(static_cast(line[idx + 1]))) { return trim_copy(line.substr(idx + 1)); } return line; } bool has_alpha(const std::string& value) { return std::any_of(value.begin(), value.end(), [](unsigned char ch) { return std::isalpha(ch); }); } bool is_heading_like_label(const std::string& value) { const std::string lower = to_lower_copy_str(strip_wrapping_punctuation(collapse_spaces_copy(trim_copy(value)))); static const std::vector exact_matches = { "category", "main category", "subcategory", "sub category", "categorization", "classification", "result", "answer", "note", "warning", "disclaimer", "reason", "explanation", "full path", "file name", "directory name" }; if (std::find(exact_matches.begin(), exact_matches.end(), lower) != exact_matches.end()) { return true; } return lower.find("categorization") != std::string::npos || lower.find("classification") != std::string::npos; } std::vector split_segments(const std::string& line, std::string_view delimiter) { std::vector segments; std::size_t start = 0; while (start <= line.size()) { const auto pos = line.find(delimiter, start); const std::string segment = trim_copy(line.substr(start, pos == std::string::npos ? pos : pos - start)); if (!segment.empty()) { segments.push_back(segment); } if (pos == std::string::npos) { break; } start = pos + delimiter.size(); } return segments; } std::optional extract_labeled_value(const std::string& line, std::initializer_list labels, bool category_label) { const auto colon = line.find(':'); if (colon == std::string::npos) { return std::nullopt; } const std::string key = to_lower_copy_str(trim_copy(line.substr(0, colon))); for (const std::string_view label : labels) { if (key == label) { const std::string value = normalize_candidate_label(line.substr(colon + 1), category_label); if (!value.empty()) { return value; } break; } } return std::nullopt; } bool split_inline_pair(const std::string& line, std::string& category, std::string& subcategory) { for (std::string_view delimiter : {std::string_view(" : "), std::string_view(":")}) { const auto segments = split_segments(line, delimiter); if (segments.size() < 2) { continue; } for (std::size_t idx = segments.size() - 1; idx > 0; --idx) { const std::string left = normalize_candidate_label(segments[idx - 1], true); const std::string right = normalize_candidate_label(segments[idx], false); if (left.size() < 2 || right.empty()) { continue; } if (!has_alpha(left) || !has_alpha(right)) { continue; } if (is_heading_like_label(left)) { continue; } category = left; subcategory = right; return true; } } return false; } // Splits common category/subcategory response variants and sanitizes the labels. std::pair split_category_subcategory(const std::string& input) { std::vector lines; lines.reserve(4); std::istringstream iss(input); std::string line; while (std::getline(iss, line)) { std::string cleaned = strip_list_prefix(std::move(line)); if (!cleaned.empty()) { lines.push_back(std::move(cleaned)); } } if (lines.empty()) { std::string fallback = Utils::sanitize_path_label(trim_copy(input)); return {fallback, ""}; } std::string category; std::string subcategory; for (const auto& entry : lines) { if (category.empty()) { if (auto value = extract_labeled_value(entry, {"category", "main category"}, true)) { category = std::move(*value); } } if (subcategory.empty()) { if (auto value = extract_labeled_value(entry, {"subcategory", "sub category"}, false)) { subcategory = std::move(*value); } } } if (category.empty() || subcategory.empty()) { for (auto it = lines.rbegin(); it != lines.rend(); ++it) { std::string parsed_category; std::string parsed_subcategory; if (!split_inline_pair(*it, parsed_category, parsed_subcategory)) { continue; } if (category.empty()) { category = std::move(parsed_category); } if (subcategory.empty()) { subcategory = std::move(parsed_subcategory); } if (!category.empty() && !subcategory.empty()) { break; } } } if (category.empty()) { category = lines.front(); } return {Utils::sanitize_path_label(category), Utils::sanitize_path_label(subcategory)}; } std::optional> parse_translated_category_response(const std::string& response) { Json::Value root; Json::CharReaderBuilder reader; std::string errors; std::istringstream stream(response); if (Json::parseFromStream(reader, stream, &root, &errors) && root.isObject()) { const std::string category = normalize_candidate_label(root.get("category", "").asString(), true); const std::string subcategory = normalize_candidate_label(root.get("subcategory", "").asString(), false); if (!category.empty()) { return std::make_pair(Utils::sanitize_path_label(category), Utils::sanitize_path_label(subcategory.empty() ? category : subcategory)); } } auto [category, subcategory] = split_category_subcategory(response); if (category.empty()) { return std::nullopt; } if (subcategory.empty()) { subcategory = category; } return std::make_pair(category, subcategory); } // Returns a lowercase copy of the input string. std::string to_lower_copy_str(std::string value) { std::transform(value.begin(), value.end(), value.begin(), [](unsigned char c) { return static_cast(std::tolower(c)); }); return value; } // Returns true when the label contains only allowed characters. bool contains_only_allowed_chars(const std::string& value) { for (unsigned char ch : value) { if (std::iscntrl(ch)) { return false; } static const std::string forbidden = R"(<>:"/\|?*)"; if (forbidden.find(static_cast(ch)) != std::string::npos) { return false; } // Everything else is allowed (including non-ASCII letters and punctuation). } return true; } // Returns true when the label has leading/trailing whitespace. bool has_leading_or_trailing_space_or_dot(const std::string& value) { if (value.empty()) { return false; } const unsigned char first = static_cast(value.front()); const unsigned char last = static_cast(value.back()); // Only guard leading/trailing whitespace; dots are allowed. return std::isspace(first) || std::isspace(last); } // Returns true when the label matches a reserved Windows device name. bool is_reserved_windows_name(const std::string& value) { static const std::vector reserved = { "con","prn","aux","nul", "com1","com2","com3","com4","com5","com6","com7","com8","com9", "lpt1","lpt2","lpt3","lpt4","lpt5","lpt6","lpt7","lpt8","lpt9" }; const std::string lower = to_lower_copy_str(value); return std::find(reserved.begin(), reserved.end(), lower) != reserved.end(); } // Returns true when the label looks like a file extension. bool looks_like_extension_label(const std::string& value) { const auto dot_pos = value.rfind('.'); if (dot_pos == std::string::npos || dot_pos == value.size() - 1) { return false; } const std::string ext = value.substr(dot_pos + 1); if (ext.empty() || ext.size() > 5) { return false; } return std::all_of(ext.begin(), ext.end(), [](unsigned char ch) { return std::isalpha(ch); }); } // Result for category/subcategory validation. struct LabelValidationResult { bool valid{false}; std::string error; }; // Validates category/subcategory labels for length and invalid content. LabelValidationResult validate_labels(const std::string& category, const std::string& subcategory) { if (category.empty() || subcategory.empty()) { return {false, "Category or subcategory is empty"}; } if (category.size() > kMaxLabelLength || subcategory.size() > kMaxLabelLength) { return {false, "Category or subcategory exceeds max length"}; } if (!contains_only_allowed_chars(category) || !contains_only_allowed_chars(subcategory)) { return {false, "Category or subcategory contains disallowed characters"}; } if (looks_like_extension_label(category) || looks_like_extension_label(subcategory)) { return {false, "Category or subcategory looks like a file extension"}; } if (is_reserved_windows_name(category) || is_reserved_windows_name(subcategory)) { return {false, "Category or subcategory is a reserved name"}; } if (has_leading_or_trailing_space_or_dot(category) || has_leading_or_trailing_space_or_dot(subcategory)) { return {false, "Category or subcategory has leading/trailing space or dot"}; } if (to_lower_copy_str(category) == to_lower_copy_str(subcategory)) { return {false, "Category and subcategory are identical"}; } return {true, {}}; } } CategorizationService::CategorizationService(Settings& settings, DatabaseManager& db_manager, std::shared_ptr core_logger) : settings(settings), db_manager(db_manager), core_logger(std::move(core_logger)) {} bool CategorizationService::ensure_remote_credentials(std::string* error_message) const { const LLMChoice choice = settings.get_llm_choice(); if (!is_remote_choice(choice)) { return true; } if (choice == LLMChoice::Remote_Custom) { const auto id = settings.get_active_custom_api_id(); const CustomApiEndpoint endpoint = settings.find_custom_api_endpoint(id); if (is_valid_custom_api_endpoint(endpoint)) { return true; } if (core_logger) { core_logger->error("Custom API endpoint selected but is missing required settings."); } if (error_message) { *error_message = "Custom API endpoint is missing required settings. Please edit it in the Select LLM dialog."; } return false; } const bool has_key = (choice == LLMChoice::Remote_OpenAI) ? !settings.get_openai_api_key().empty() : !settings.get_gemini_api_key().empty(); if (has_key) { return true; } const char* provider = choice == LLMChoice::Remote_OpenAI ? "OpenAI" : "Gemini"; if (core_logger) { core_logger->error("Remote LLM selected but {} API key is not configured.", provider); } if (error_message) { *error_message = fmt::format("Remote model credentials are missing. Enter your {} API key in the Select LLM dialog.", provider); } return false; } std::vector CategorizationService::prune_empty_cached_entries(const std::string& directory_path) { return db_manager.remove_empty_categorizations(directory_path); } std::vector CategorizationService::load_cached_entries(const std::string& directory_path) const { auto cached = settings.get_include_subdirectories() ? db_manager.get_categorized_files_recursive(directory_path) : db_manager.get_categorized_files(directory_path); const CategoryLanguage language = settings.get_category_language(); for (auto& entry : cached) { entry = db_manager.localize_categorized_file(entry, language); } return cached; } std::vector CategorizationService::categorize_entries( const std::vector& files, bool is_local_llm, std::atomic& stop_flag, const ProgressCallback& progress_callback, const QueueCallback& queue_callback, const CompletionCallback& completion_callback, const RecategorizationCallback& recategorization_callback, std::function()> llm_factory, const PromptOverrideProvider& prompt_override, const SuggestedNameProvider& suggested_name_provider) const { std::vector categorized; if (files.empty()) { return categorized; } if (stop_flag.load()) { return categorized; } auto llm = llm_factory ? llm_factory() : nullptr; if (!llm) { throw std::runtime_error("Failed to create LLM client."); } categorized.reserve(files.size()); SessionHistoryMap session_history; for (const auto& entry : files) { if (stop_flag.load()) { break; } if (queue_callback) { queue_callback(entry); } const std::string suggested_name = suggested_name_provider ? suggested_name_provider(entry) : std::string(); const auto override_value = prompt_override ? prompt_override(entry) : std::nullopt; if (auto categorized_entry = categorize_single_entry(*llm, is_local_llm, entry, override_value, suggested_name, stop_flag, progress_callback, recategorization_callback, session_history)) { categorized.push_back(*categorized_entry); } if (completion_callback) { completion_callback(entry); } } return categorized; } std::string CategorizationService::build_whitelist_context() const { std::ostringstream oss; const auto cats = settings.get_allowed_categories(); const auto subs = settings.get_allowed_subcategories(); if (!cats.empty()) { oss << "Allowed main categories (pick exactly one label from the numbered list):\n"; for (size_t i = 0; i < cats.size(); ++i) { oss << (i + 1) << ") " << cats[i] << "\n"; } } if (!subs.empty()) { oss << "Allowed subcategories (pick exactly one label from the numbered list):\n"; for (size_t i = 0; i < subs.size(); ++i) { oss << (i + 1) << ") " << subs[i] << "\n"; } } else { oss << "Allowed subcategories: any (pick a specific, relevant subcategory; do not repeat the main category)."; } return oss.str(); } std::string CategorizationService::build_category_language_context() const { const CategoryLanguage lang = settings.get_category_language(); if (lang == CategoryLanguage::English) { return std::string(); } const std::string name = categoryLanguageDisplay(lang); return fmt::format( "Determine the canonical main category and subcategory in English only. " "Do not translate, do not add bilingual text, do not use parentheses, and do not explain. " "The final labels will be translated to {} later.", name); } namespace { // Returns true when the value appears in the allowed list (case-insensitive). bool is_allowed(const std::string& value, const std::vector& allowed) { if (allowed.empty()) { return true; } const std::string norm = to_lower_copy_str(value); for (const auto& item : allowed) { if (to_lower_copy_str(item) == norm) { return true; } } return false; } // Returns the first allowed entry or an empty string when the list is empty. std::string first_allowed_or_blank(const std::vector& allowed) { return allowed.empty() ? std::string() : allowed.front(); } } // namespace std::optional CategorizationService::try_cached_categorization( const std::string& item_name, const std::string& current_path, const std::string& categorization_path, const std::string& dir_path, FileType file_type, const ProgressCallback& progress_callback) const { const auto cached = db_manager.get_categorization_from_db(dir_path, item_name, file_type); if (cached.size() < 2) { return std::nullopt; } const std::string sanitized_category = Utils::sanitize_path_label(cached[0]); const std::string sanitized_subcategory = Utils::sanitize_path_label(cached[1]); if (sanitized_category.empty() || sanitized_subcategory.empty()) { if (core_logger) { core_logger->warn("Ignoring cached categorization with empty values for '{}'", item_name); } return std::nullopt; } const auto validation = validate_labels(sanitized_category, sanitized_subcategory); if (!validation.valid) { if (core_logger) { core_logger->warn("Ignoring cached categorization for '{}' due to validation error: {} (cat='{}', sub='{}')", item_name, validation.error, sanitized_category, sanitized_subcategory); } return std::nullopt; } (void)item_name; (void)current_path; (void)categorization_path; (void)progress_callback; return db_manager.resolve_category(sanitized_category, sanitized_subcategory); } bool CategorizationService::ensure_remote_credentials_for_request( const std::string& item_name, const ProgressCallback& progress_callback) const { if (!is_remote_choice(settings.get_llm_choice())) { return true; } const LLMChoice choice = settings.get_llm_choice(); if (choice == LLMChoice::Remote_Custom) { const auto id = settings.get_active_custom_api_id(); const CustomApiEndpoint endpoint = settings.find_custom_api_endpoint(id); if (is_valid_custom_api_endpoint(endpoint)) { return true; } const std::string err_msg = fmt::format("[REMOTE] {} (missing custom API settings)", item_name); if (progress_callback) { progress_callback(err_msg); } if (core_logger) { core_logger->error("{}", err_msg); } return false; } const bool has_key = (choice == LLMChoice::Remote_OpenAI) ? !settings.get_openai_api_key().empty() : !settings.get_gemini_api_key().empty(); if (has_key) { return true; } const std::string provider = choice == LLMChoice::Remote_OpenAI ? "OpenAI" : "Gemini"; const std::string err_msg = fmt::format("[REMOTE] {} (missing {} API key)", item_name, provider); if (progress_callback) { progress_callback(err_msg); } if (core_logger) { core_logger->error("{}", err_msg); } return false; } DatabaseManager::ResolvedCategory CategorizationService::categorize_via_llm( ILLMClient& llm, bool is_local_llm, const std::string& display_name, const std::string& display_path, const std::string& prompt_name, const std::string& prompt_path, FileType file_type, const ProgressCallback& progress_callback, const std::string& consistency_context) const { try { const std::string category_subcategory = run_llm_with_timeout(llm, prompt_name, prompt_path, file_type, is_local_llm, consistency_context); auto [category, subcategory] = split_category_subcategory(category_subcategory); auto resolved = db_manager.resolve_category(category, subcategory); if (settings.get_use_whitelist()) { const auto allowed_categories = settings.get_allowed_categories(); const auto allowed_subcategories = settings.get_allowed_subcategories(); if (!is_allowed(resolved.category, allowed_categories)) { resolved.category = first_allowed_or_blank(allowed_categories); } if (!is_allowed(resolved.subcategory, allowed_subcategories)) { resolved.subcategory = first_allowed_or_blank(allowed_subcategories); } } const auto validation = validate_labels(resolved.category, resolved.subcategory); if (!validation.valid) { if (progress_callback) { progress_callback(fmt::format("[LLM-ERROR] {} (invalid category/subcategory: {})", display_name, validation.error)); } if (core_logger) { core_logger->warn("Invalid LLM output for '{}': {} (cat='{}', sub='{}')", display_name, validation.error, resolved.category, resolved.subcategory); } return DatabaseManager::ResolvedCategory{-1, "", ""}; } if (resolved.category.empty()) { resolved.category = "Uncategorized"; } const auto display_resolved = localize_resolved_category(llm, resolved); emit_progress_message(progress_callback, "AI", display_name, display_resolved, display_path, prompt_path); return resolved; } catch (const std::exception& ex) { const std::string err_msg = fmt::format("[LLM-ERROR] {} ({})", display_name, ex.what()); if (progress_callback) { progress_callback(err_msg); } if (core_logger) { core_logger->error("LLM error while categorizing '{}': {}", display_name, ex.what()); } throw; } } void CategorizationService::emit_progress_message(const ProgressCallback& progress_callback, std::string_view source, const std::string& item_name, const DatabaseManager::ResolvedCategory& resolved, const std::string& current_path, const std::string& categorization_path) const { if (!progress_callback) { return; } const std::string sub = resolved.subcategory.empty() ? "-" : resolved.subcategory; const std::string current_path_display = current_path.empty() ? "-" : current_path; const std::string categorization_path_display = categorization_path.empty() ? current_path_display : categorization_path; progress_callback(fmt::format( "[{}] {}\n" " Category : {}\n" " Subcat : {}\n" " Current Path : {}\n" " Categorization Path : {}", source, item_name, resolved.category, sub, current_path_display, categorization_path_display)); } DatabaseManager::ResolvedCategory CategorizationService::categorize_with_cache( ILLMClient& llm, bool is_local_llm, const std::string& display_name, const std::string& display_path, const std::string& dir_path, const std::string& prompt_name, const std::string& prompt_path, FileType file_type, const ProgressCallback& progress_callback, const std::string& consistency_context) const { if (auto cached = try_cached_categorization(display_name, display_path, prompt_path, dir_path, file_type, progress_callback)) { const auto display_resolved = localize_resolved_category(llm, *cached); emit_progress_message(progress_callback, "CACHE", display_name, display_resolved, display_path, prompt_path); return *cached; } if (!is_local_llm && !ensure_remote_credentials_for_request(display_name, progress_callback)) { return DatabaseManager::ResolvedCategory{-1, "", ""}; } return categorize_via_llm(llm, is_local_llm, display_name, display_path, prompt_name, prompt_path, file_type, progress_callback, consistency_context); } std::optional CategorizationService::categorize_single_entry( ILLMClient& llm, bool is_local_llm, const FileEntry& entry, const std::optional& prompt_override, const std::string& suggested_name, std::atomic& stop_flag, const ProgressCallback& progress_callback, const RecategorizationCallback& recategorization_callback, SessionHistoryMap& session_history) const { (void)stop_flag; const std::filesystem::path entry_path = Utils::utf8_to_path(entry.full_path); const std::string dir_path = Utils::path_to_utf8(entry_path.parent_path()); const std::string display_path = Utils::abbreviate_user_path(entry.full_path); const std::string prompt_name = prompt_override ? prompt_override->name : entry.file_name; const std::string prompt_path = prompt_override ? prompt_override->path : entry.full_path; const std::string prompt_path_display = Utils::abbreviate_user_path(prompt_path); const bool use_consistency_hints = settings.get_use_consistency_hints(); const std::string extension = extract_extension(entry.file_name); const std::string signature = make_file_signature(entry.type, extension); std::string hint_block; if (use_consistency_hints) { const auto hints = collect_consistency_hints(signature, session_history, extension, entry.type); hint_block = format_hint_block(hints); } const std::string combined_context = build_combined_context(hint_block); DatabaseManager::ResolvedCategory resolved; bool retried_after_backoff = false; while (true) { try { resolved = run_categorization_with_cache(llm, is_local_llm, entry, display_path, dir_path, prompt_name, prompt_path_display, progress_callback, combined_context); break; } catch (const BackoffError& backoff) { const int wait_seconds = backoff.retry_after_seconds() > 0 ? backoff.retry_after_seconds() : 60; if (progress_callback) { progress_callback(fmt::format( "[REMOTE] Rate limit hit. Waiting {}s before retrying {}...", wait_seconds, entry.file_name)); } if (core_logger) { core_logger->warn("Rate limit hit for '{}'; retrying in {}s", entry.file_name, wait_seconds); } for (int remaining = wait_seconds; remaining > 0; --remaining) { if (stop_flag.load()) { return std::nullopt; } if (progress_callback && (remaining % 10 == 0 || remaining <= 3)) { progress_callback(fmt::format("[REMOTE] Retrying {} in {}s...", entry.file_name, remaining)); } std::this_thread::sleep_for(std::chrono::seconds(1)); } if (retried_after_backoff) { throw; } retried_after_backoff = true; } } if (auto retry = handle_empty_result(entry, dir_path, resolved, use_consistency_hints, is_local_llm, recategorization_callback)) { return retry; } update_storage_with_result(entry, dir_path, resolved, use_consistency_hints, suggested_name, session_history); const auto display_resolved = db_manager.localize_category(resolved, settings.get_category_language()); CategorizedFile result{dir_path, entry.file_name, entry.type, display_resolved.category, display_resolved.subcategory, resolved.taxonomy_id}; result.used_consistency_hints = use_consistency_hints; result.suggested_name = suggested_name; result.canonical_category = resolved.category; result.canonical_subcategory = resolved.subcategory; return result; } std::string CategorizationService::build_combined_context(const std::string& hint_block) const { std::string combined_context; const std::string whitelist_block = build_whitelist_context(); const std::string language_block = build_category_language_context(); if (!language_block.empty()) { combined_context += language_block; } if (settings.get_use_whitelist() && !whitelist_block.empty()) { if (core_logger) { core_logger->debug("Applying category whitelist ({} cats, {} subs)", settings.get_allowed_categories().size(), settings.get_allowed_subcategories().size()); } if (!combined_context.empty()) { combined_context += "\n\n"; } combined_context += whitelist_block; } if (!hint_block.empty()) { if (!combined_context.empty()) { combined_context += "\n\n"; } combined_context += hint_block; } return combined_context; } DatabaseManager::ResolvedCategory CategorizationService::localize_resolved_category( ILLMClient& llm, const DatabaseManager::ResolvedCategory& resolved) const { const CategoryLanguage language = settings.get_category_language(); if (language == CategoryLanguage::English || resolved.taxonomy_id <= 0) { return resolved; } if (!db_manager.get_category_translation(resolved.taxonomy_id, language)) { if (const auto translated = translate_resolved_category(llm, resolved)) { db_manager.upsert_category_translation(resolved.taxonomy_id, language, translated->category, translated->subcategory); } } return db_manager.localize_category(resolved, language); } std::optional CategorizationService::translate_resolved_category( ILLMClient& llm, const DatabaseManager::ResolvedCategory& resolved) const { const CategoryLanguage language = settings.get_category_language(); if (language == CategoryLanguage::English || resolved.taxonomy_id <= 0 || resolved.category.empty() || resolved.subcategory.empty()) { return std::nullopt; } const std::string language_name = categoryLanguageDisplay(language); const std::string prompt = fmt::format( "Translate the following taxonomy labels into {}.\n" "Return only JSON in this exact shape: {{\"category\":\"...\",\"subcategory\":\"...\"}}\n" "Rules:\n" "- Keep the meaning precise.\n" "- No English.\n" "- No parentheses.\n" "- No explanations.\n" "- No trailing periods.\n" "- Keep the main category broad and concise.\n" "- Keep the subcategory specific and concise.\n\n" "category: {}\n" "subcategory: {}", language_name, resolved.category, resolved.subcategory); try { const std::string response = llm.complete_prompt(prompt, 128); const auto translated = parse_translated_category_response(response); if (!translated) { return std::nullopt; } DatabaseManager::ResolvedCategory translated_resolved{ resolved.taxonomy_id, translated->first, translated->second }; const auto validation = validate_labels(translated_resolved.category, translated_resolved.subcategory); if (!validation.valid) { if (core_logger) { core_logger->warn("Ignoring invalid translated category pair for taxonomy {}: {} (cat='{}', sub='{}')", resolved.taxonomy_id, validation.error, translated_resolved.category, translated_resolved.subcategory); } return std::nullopt; } return translated_resolved; } catch (const std::exception& ex) { if (core_logger) { core_logger->warn("Category translation failed for taxonomy {} to {}: {}", resolved.taxonomy_id, language_name, ex.what()); } return std::nullopt; } } DatabaseManager::ResolvedCategory CategorizationService::run_categorization_with_cache( ILLMClient& llm, bool is_local_llm, const FileEntry& entry, const std::string& display_path, const std::string& dir_path, const std::string& prompt_name, const std::string& prompt_path, const ProgressCallback& progress_callback, const std::string& combined_context) const { return categorize_with_cache(llm, is_local_llm, entry.file_name, display_path, dir_path, prompt_name, prompt_path, entry.type, progress_callback, combined_context); } std::optional CategorizationService::handle_empty_result( const FileEntry& entry, const std::string& dir_path, const DatabaseManager::ResolvedCategory& resolved, bool used_consistency_hints, bool is_local_llm, const RecategorizationCallback& recategorization_callback) const { const bool invalid = resolved.taxonomy_id == -1; if (!resolved.category.empty() && !resolved.subcategory.empty() && !invalid) { return std::nullopt; } const std::string reason = invalid ? "Categorization returned invalid category/subcategory and was skipped." : "Categorization returned no result."; if (core_logger) { core_logger->warn("{} for '{}'.", reason, entry.file_name); } db_manager.remove_file_categorization(dir_path, entry.file_name, entry.type); if (recategorization_callback) { CategorizedFile retry_entry{dir_path, entry.file_name, entry.type, resolved.category, resolved.subcategory, resolved.taxonomy_id}; retry_entry.used_consistency_hints = used_consistency_hints; recategorization_callback(retry_entry, reason); } return std::nullopt; } void CategorizationService::update_storage_with_result(const FileEntry& entry, const std::string& dir_path, const DatabaseManager::ResolvedCategory& resolved, bool used_consistency_hints, const std::string& suggested_name, SessionHistoryMap& session_history) const { if (core_logger) { core_logger->info("Categorized '{}' as '{} / {}'.", entry.file_name, resolved.category, resolved.subcategory.empty() ? "" : resolved.subcategory); } db_manager.insert_or_update_file_with_categorization( entry.file_name, entry.type == FileType::File ? "F" : "D", dir_path, resolved, used_consistency_hints, suggested_name); const std::string signature = make_file_signature(entry.type, extract_extension(entry.file_name)); if (!signature.empty()) { record_session_assignment(session_history[signature], {resolved.category, resolved.subcategory}); } } std::string CategorizationService::run_llm_with_timeout( ILLMClient& llm, const std::string& item_name, const std::string& item_path, FileType file_type, bool is_local_llm, const std::string& consistency_context) const { const int timeout_seconds = resolve_llm_timeout(is_local_llm); auto future = start_llm_future(llm, item_name, item_path, file_type, consistency_context); if (future.wait_for(std::chrono::seconds(timeout_seconds)) == std::future_status::timeout) { throw std::runtime_error("Timed out waiting for LLM response"); } return future.get(); } int CategorizationService::resolve_llm_timeout(bool is_local_llm) const { int timeout_seconds = is_local_llm ? 60 : 10; const char* timeout_env = std::getenv(is_local_llm ? kLocalTimeoutEnv : kRemoteTimeoutEnv); if (!is_local_llm && settings.get_llm_choice() == LLMChoice::Remote_Custom) { timeout_seconds = 60; timeout_env = std::getenv(kCustomTimeoutEnv); } if (!timeout_env || *timeout_env == '\0') { return timeout_seconds; } try { const int parsed = std::stoi(timeout_env); if (parsed > 0) { timeout_seconds = parsed; } else if (core_logger) { core_logger->warn("Ignoring non-positive LLM timeout '{}'", timeout_env); } } catch (const std::exception& ex) { if (core_logger) { core_logger->warn("Failed to parse LLM timeout '{}': {}", timeout_env, ex.what()); } } if (core_logger) { core_logger->debug("Using {} LLM timeout of {} second(s)", is_local_llm ? "local" : "remote", timeout_seconds); } return timeout_seconds; } std::future CategorizationService::start_llm_future( ILLMClient& llm, const std::string& item_name, const std::string& item_path, FileType file_type, const std::string& consistency_context) const { auto promise = std::make_shared>(); std::future future = promise->get_future(); std::thread([&llm, promise, item_name, item_path, file_type, consistency_context]() mutable { try { promise->set_value(llm.categorize_file(item_name, item_path, file_type, consistency_context)); } catch (...) { try { promise->set_exception(std::current_exception()); } catch (...) { // no-op } } }).detach(); return future; } std::vector CategorizationService::collect_consistency_hints( const std::string& signature, const SessionHistoryMap& session_history, const std::string& extension, FileType file_type) const { std::vector hints; if (signature.empty()) { return hints; } if (auto it = session_history.find(signature); it != session_history.end()) { for (const auto& entry : it->second) { if (append_unique_hint(hints, entry) && hints.size() == kMaxConsistencyHints) { return hints; } } } if (hints.size() < kMaxConsistencyHints) { const size_t remaining = kMaxConsistencyHints - hints.size(); const auto db_hints = db_manager.get_recent_categories_for_extension(extension, file_type, remaining); for (const auto& entry : db_hints) { if (append_unique_hint(hints, entry) && hints.size() == kMaxConsistencyHints) { break; } } } return hints; } std::string CategorizationService::make_file_signature(FileType file_type, const std::string& extension) { const std::string type_tag = (file_type == FileType::Directory) ? "DIR" : "FILE"; const std::string normalized_extension = extension.empty() ? std::string("") : extension; return type_tag + ":" + normalized_extension; } std::string CategorizationService::extract_extension(const std::string& file_name) { const auto pos = file_name.find_last_of('.'); if (pos == std::string::npos || pos + 1 >= file_name.size()) { return std::string(); } std::string ext = file_name.substr(pos); std::transform(ext.begin(), ext.end(), ext.begin(), [](unsigned char ch) { return static_cast(std::tolower(ch)); }); return ext; } bool CategorizationService::append_unique_hint(std::vector& target, const CategoryPair& candidate) { CategoryPair normalized{Utils::sanitize_path_label(candidate.first), Utils::sanitize_path_label(candidate.second)}; if (normalized.first.empty()) { return false; } if (normalized.second.empty()) { normalized.second = normalized.first; } for (const auto& existing : target) { if (existing.first == normalized.first && existing.second == normalized.second) { return false; } } target.push_back(std::move(normalized)); return true; } void CategorizationService::record_session_assignment(HintHistory& history, const CategoryPair& assignment) { CategoryPair normalized{Utils::sanitize_path_label(assignment.first), Utils::sanitize_path_label(assignment.second)}; if (normalized.first.empty()) { return; } if (normalized.second.empty()) { normalized.second = normalized.first; } history.erase(std::remove(history.begin(), history.end(), normalized), history.end()); history.push_front(normalized); if (history.size() > kMaxConsistencyHints) { history.pop_back(); } } std::string CategorizationService::format_hint_block(const std::vector& hints) const { if (hints.empty()) { return std::string(); } std::ostringstream oss; oss << "Recent assignments for similar items:\n"; for (const auto& hint : hints) { const std::string sub = hint.second.empty() ? hint.first : hint.second; oss << "- " << hint.first << " : " << sub << "\n"; } oss << "Prefer one of the above when it fits; otherwise, choose the closest consistent alternative."; return oss.str(); } ================================================ FILE: app/lib/CategorizationSession.cpp ================================================ #include "CategorizationSession.hpp" #include #include CategorizationSession::CategorizationSession(std::string api_key, std::string model, std::string base_url) : key(std::move(api_key)), model(std::move(model)), base_url(std::move(base_url)) { } CategorizationSession::~CategorizationSession() { // Securely clear key memory std::fill(key.begin(), key.end(), '\0'); } LLMClient CategorizationSession::create_llm_client() const { return LLMClient(key, model, base_url); } ================================================ FILE: app/lib/ConsistencyPassService.cpp ================================================ #include "ConsistencyPassService.hpp" #include "ILLMClient.hpp" #include #include #if __has_include() #include #elif __has_include() #include #else #error "jsoncpp headers not found. Install jsoncpp development files." #endif #include #include #include #include #include #include #include namespace { std::string trim_whitespace(const std::string& value) { const char* whitespace = " \t\n\r\f\v"; const auto start = value.find_first_not_of(whitespace); const auto end = value.find_last_not_of(whitespace); if (start == std::string::npos || end == std::string::npos) { return std::string(); } return value.substr(start, end - start + 1); } bool try_parse_harmonized_entry(const std::string& line, size_t line_number, const std::string& raw_line, Json::Value& entry, const std::shared_ptr& logger) { const auto arrow_pos = line.find("=>"); if (arrow_pos == std::string::npos) { return false; } std::string id = trim_whitespace(line.substr(0, arrow_pos)); std::string remainder = trim_whitespace(line.substr(arrow_pos + 2)); const auto colon_pos = remainder.find(':'); if (colon_pos == std::string::npos) { return false; } std::string category = trim_whitespace(remainder.substr(0, colon_pos)); std::string subcategory = trim_whitespace(remainder.substr(colon_pos + 1)); if (subcategory.empty()) { subcategory = category; } if (id.empty() || category.empty()) { if (logger) { logger->warn("Consistency pass skipped malformed line {}: '{}'", line_number, raw_line); } return false; } entry = Json::Value(Json::objectValue); entry["id"] = id; entry["category"] = category; entry["subcategory"] = subcategory; return true; } std::string make_item_key(const CategorizedFile& item) { std::filesystem::path path(item.file_path); path /= item.file_name; return path.generic_string(); } std::string canonical_category_text(const CategorizedFile& item) { return item.canonical_category.empty() ? item.category : item.canonical_category; } std::string canonical_subcategory_text(const CategorizedFile& item) { return item.canonical_subcategory.empty() ? item.subcategory : item.canonical_subcategory; } std::unordered_map build_items_by_key(std::vector& items) { std::unordered_map map; map.reserve(items.size()); for (auto& item : items) { map[make_item_key(item)] = &item; } return map; } std::string build_consistency_prompt( const std::vector& chunk, const std::vector>& taxonomy) { Json::Value taxonomy_json(Json::arrayValue); for (const auto& entry : taxonomy) { Json::Value obj; obj["category"] = entry.first; obj["subcategory"] = entry.second; taxonomy_json.append(obj); } std::ostringstream prompt; prompt << "You are a taxonomy normalization assistant.\n"; prompt << "Your task is to review existing (category, subcategory) assignments for files and make them consistent.\n"; prompt << "Guidelines:\n"; prompt << "1. Prefer using the known taxonomy entries when they closely match.\n"; prompt << "2. Merge near-duplicate labels (e.g. 'Docs' vs 'Documents'), but do not collapse distinct concepts.\n"; prompt << "3. Preserve the intent of each file. If a category/subcategory already looks appropriate, keep it.\n"; prompt << "4. Always provide both category and subcategory strings.\n"; prompt << "5. Respond with one line per item using the exact format: => : .\n"; prompt << "6. The must be copied verbatim from the list below (full path). No other text may appear before it.\n"; prompt << "7. Keep the output order identical to the input and finish by writing END on its own line. No other prose.\n\n"; Json::StreamWriterBuilder builder; builder["indentation"] = ""; const std::string taxonomy_str = Json::writeString(builder, taxonomy_json); prompt << "Known taxonomy entries (JSON array): " << taxonomy_str << "\n\n"; prompt << "Items to harmonize (follow the input order in your response):\n"; for (const auto* item : chunk) { if (!item) { continue; } prompt << "- id: " << make_item_key(*item) << ", file: " << item->file_name << ", current: " << canonical_category_text(*item) << " / " << canonical_subcategory_text(*item) << "\n"; } prompt << "Example response lines:\n"; prompt << "/home/user/Downloads/setup.exe => Applications : Installers\n"; prompt << "/home/user/Documents/taxes.pdf => Documents : Tax forms\n"; prompt << "END"; return prompt.str(); } bool parse_structured_lines( const std::string& response, Json::Value& root, const std::shared_ptr& logger) { Json::Value harmonized(Json::arrayValue); std::istringstream stream(response); std::string raw_line; size_t line_number = 0; while (std::getline(stream, raw_line)) { ++line_number; std::string line = trim_whitespace(raw_line); if (line.empty()) { continue; } if (line == "END") { break; } Json::Value entry(Json::objectValue); if (try_parse_harmonized_entry(line, line_number, raw_line, entry, logger)) { harmonized.append(entry); } } if (harmonized.empty()) { if (logger) { logger->warn("Consistency pass parsed zero harmonized entries from line-based response"); } return false; } root = harmonized; return true; } const Json::Value* parse_structured_fallback( const std::string& response, Json::Value& root, const std::shared_ptr& logger) { return parse_structured_lines(response, root, logger) ? &root : nullptr; } const Json::Value* extract_harmonized_array(Json::Value& root) { if (root.isObject() && root.isMember("harmonized")) { const Json::Value& harmonized = root["harmonized"]; if (harmonized.isArray()) { return &harmonized; } return nullptr; } if (root.isArray()) { return &root; } return nullptr; } struct HarmonizedUpdate { std::string id; CategorizedFile* target{nullptr}; std::string category; std::string subcategory; }; std::optional extract_harmonized_update( const Json::Value& entry, std::unordered_map& items_by_key, const std::shared_ptr& logger) { if (!entry.isObject()) { return std::nullopt; } const std::string id = entry.get("id", "").asString(); if (id.empty()) { return std::nullopt; } auto it = items_by_key.find(id); if (it == items_by_key.end() || !it->second) { if (logger) { logger->warn("Consistency pass referenced unknown item id '{}'", id); } return std::nullopt; } CategorizedFile* target = it->second; const auto trim_or_fallback = [](const Json::Value& parent, const char* key, const std::string& fallback) { if (!parent.isMember(key)) { return fallback; } std::string candidate = parent[key].asString(); if (candidate.empty()) { return fallback; } candidate = trim_whitespace(std::move(candidate)); return candidate.empty() ? fallback : candidate; }; std::string category = trim_or_fallback(entry, "category", canonical_category_text(*target)); if (category.empty()) { category = canonical_category_text(*target); } std::string subcategory = trim_or_fallback(entry, "subcategory", canonical_subcategory_text(*target)); if (!entry.isMember("subcategory") || subcategory.empty()) { subcategory = category; } return HarmonizedUpdate{id, target, std::move(category), std::move(subcategory)}; } void apply_harmonized_update( const HarmonizedUpdate& update, DatabaseManager& db_manager, CategoryLanguage category_language, std::unordered_map& new_items_by_key, const ConsistencyPassService::ProgressCallback& progress_callback, const std::shared_ptr& logger) { DatabaseManager::ResolvedCategory resolved = db_manager.resolve_category(update.category, update.subcategory); const DatabaseManager::ResolvedCategory display_resolved = db_manager.localize_category(resolved, category_language); bool changed = (display_resolved.category != update.target->category) || (display_resolved.subcategory != update.target->subcategory); update.target->category = display_resolved.category; update.target->subcategory = display_resolved.subcategory; update.target->taxonomy_id = resolved.taxonomy_id; update.target->canonical_category = resolved.category; update.target->canonical_subcategory = resolved.subcategory; db_manager.insert_or_update_file_with_categorization( update.target->file_name, update.target->type == FileType::File ? "F" : "D", update.target->file_path, resolved, update.target->used_consistency_hints, update.target->suggested_name, update.target->rename_only); if (auto new_it = new_items_by_key.find(update.id); new_it != new_items_by_key.end() && new_it->second) { new_it->second->category = display_resolved.category; new_it->second->subcategory = display_resolved.subcategory; new_it->second->taxonomy_id = resolved.taxonomy_id; new_it->second->canonical_category = resolved.category; new_it->second->canonical_subcategory = resolved.subcategory; } if (changed) { const std::string message = fmt::format("[CONSISTENCY] {} -> {} / {}", update.target->file_name, display_resolved.category, display_resolved.subcategory); if (progress_callback) { progress_callback(message); } if (logger) { logger->info(message); } } } const Json::Value* parse_consistency_response( const std::string& response, Json::Value& root, const std::shared_ptr& logger) { Json::CharReaderBuilder reader; std::string errors; std::istringstream stream(response); if (!Json::parseFromStream(reader, stream, &root, &errors)) { if (logger) { logger->warn("Consistency pass JSON parse failed: {}", errors); logger->warn("Consistency pass raw response ({} chars):\n{}", response.size(), response); } return parse_structured_fallback(response, root, logger); } if (const Json::Value* direct = extract_harmonized_array(root)) { return direct; } if (logger) { logger->warn("Consistency pass response missing 'harmonized' array"); } return parse_structured_fallback(response, root, logger); } std::string strip_list_prefix(std::string line) { line = trim_whitespace(line); while (!line.empty() && (line.front() == '-' || line.front() == '*')) { line.erase(line.begin()); line = trim_whitespace(line); } return line; } std::optional> split_key_value(const std::string& line) { const auto colon_pos = line.find(':'); if (colon_pos == std::string::npos) { return std::nullopt; } std::string lhs = trim_whitespace(line.substr(0, colon_pos)); std::string rhs = trim_whitespace(line.substr(colon_pos + 1)); const auto arrow_pos = rhs.find("=>"); if (arrow_pos != std::string::npos) { rhs = trim_whitespace(rhs.substr(0, arrow_pos)); } return std::make_pair(std::move(lhs), std::move(rhs)); } std::pair split_category_subcategory(const std::string& lhs) { const auto slash_pos = lhs.find('/'); if (slash_pos != std::string::npos) { return {trim_whitespace(lhs.substr(0, slash_pos)), trim_whitespace(lhs.substr(slash_pos + 1))}; } return {lhs, std::string()}; } std::optional> parse_ordered_line( std::string line, const std::string& raw_line, size_t line_number, const std::shared_ptr& logger) { line = strip_list_prefix(std::move(line)); const auto key_value = split_key_value(line); if (!key_value.has_value()) { return std::nullopt; } const auto& [lhs, rhs_raw] = *key_value; auto [category, subcategory] = split_category_subcategory(lhs); std::string rhs = rhs_raw; if (subcategory.empty()) { subcategory = rhs; } if (subcategory.empty()) { subcategory = category; } if (category.empty()) { if (logger) { logger->warn("Consistency pass fallback skipped malformed line {}: '{}'", line_number, raw_line); } return std::nullopt; } return std::make_pair(std::move(category), std::move(subcategory)); } std::vector> parse_ordered_category_lines( const std::string& response, const std::shared_ptr& logger) { std::vector> ordered; std::istringstream stream(response); std::string raw_line; size_t line_number = 0; while (std::getline(stream, raw_line)) { ++line_number; std::string line = trim_whitespace(raw_line); if (line.empty()) { continue; } if (line == "END") { break; } if (auto parsed = parse_ordered_line(line, raw_line, line_number, logger)) { ordered.push_back(std::move(*parsed)); } } if (ordered.empty() && logger) { logger->warn("Consistency pass fallback parsing produced no entries"); } return ordered; } bool apply_ordered_fallback( const std::string& response, const std::vector& chunk, std::unordered_map& items_by_key, DatabaseManager& db_manager, CategoryLanguage category_language, std::unordered_map& new_items_by_key, const ConsistencyPassService::ProgressCallback& progress_callback, const std::shared_ptr& logger) { const auto ordered = parse_ordered_category_lines(response, logger); if (ordered.empty()) { return false; } const size_t limit = std::min(chunk.size(), ordered.size()); bool applied = false; for (size_t index = 0; index < limit; ++index) { if (!chunk[index]) { continue; } Json::Value entry(Json::objectValue); entry["id"] = make_item_key(*chunk[index]); entry["category"] = ordered[index].first; entry["subcategory"] = ordered[index].second; if (auto update = extract_harmonized_update(entry, items_by_key, logger)) { apply_harmonized_update(*update, db_manager, category_language, new_items_by_key, progress_callback, logger); applied = true; } } return applied; } } // namespace ConsistencyPassService::ConsistencyPassService(DatabaseManager& db_manager, std::shared_ptr logger) : db_manager(db_manager), logger(std::move(logger)) { } void ConsistencyPassService::set_prompt_logging_enabled(bool enabled) { prompt_logging_enabled = enabled; } std::unique_ptr ConsistencyPassService::create_llm( std::function()> llm_factory) const { if (!llm_factory) { return nullptr; } try { return llm_factory(); } catch (const std::exception& ex) { if (logger) { logger->warn("Failed to create LLM client for consistency pass: {}", ex.what()); } return nullptr; } } void ConsistencyPassService::log_chunk_items(const std::vector& chunk, const char* stage) const { if (!logger) { return; } for (const auto* item : chunk) { if (!item) { continue; } logger->info(" [{}] {} -> {} / {}", stage, item->file_name, canonical_category_text(*item), canonical_subcategory_text(*item)); } } bool ConsistencyPassService::apply_harmonized_response( const std::string& response, const std::vector& chunk, std::unordered_map& items_by_key, std::unordered_map& new_items_by_key, const ProgressCallback& progress_callback, DatabaseManager& db_manager, CategoryLanguage category_language) const { Json::Value root; if (const Json::Value* harmonized = parse_consistency_response(response, root, logger)) { for (const auto& entry : *harmonized) { if (auto update = extract_harmonized_update(entry, items_by_key, logger)) { apply_harmonized_update(*update, db_manager, category_language, new_items_by_key, progress_callback, logger); } } return true; } if (apply_ordered_fallback(response, chunk, items_by_key, db_manager, category_language, new_items_by_key, progress_callback, logger)) { return true; } if (logger) { logger->warn("Consistency pass could not interpret response; skipping chunk"); } return false; } void ConsistencyPassService::process_chunk( const std::vector& chunk, size_t start_index, size_t end_index, size_t total_items, ILLMClient& llm, const std::vector>& taxonomy, std::unordered_map& items_by_key, std::unordered_map& new_items_by_key, CategoryLanguage category_language, const ProgressCallback& progress_callback) const { if (logger) { logger->info("[CONSISTENCY] Processing chunk {}-{} of {}", start_index + 1, end_index, total_items); log_chunk_items(chunk, "BEFORE"); } const std::string prompt = build_consistency_prompt(chunk, taxonomy); if (prompt_logging_enabled) { std::cout << "\n[CONSISTENCY PROMPT]\n" << prompt << "\n"; } try { const std::string response = llm.complete_prompt(prompt, 512); if (prompt_logging_enabled) { std::cout << "[CONSISTENCY RESPONSE]\n" << response << "\n"; } apply_harmonized_response(response, chunk, items_by_key, new_items_by_key, progress_callback, db_manager, category_language); } catch (const std::exception& ex) { if (logger) { logger->warn("Consistency pass chunk failed: {}", ex.what()); } } log_chunk_items(chunk, "AFTER"); } void ConsistencyPassService::process_chunks( ILLMClient& llm, const std::vector>& taxonomy, std::vector& categorized_files, std::unordered_map& items_by_key, std::unordered_map& new_items_by_key, std::atomic& stop_flag, CategoryLanguage category_language, const ProgressCallback& progress_callback) const { std::vector chunk; chunk.reserve(10); for (size_t index = 0; index < categorized_files.size(); ++index) { if (stop_flag.load()) { break; } chunk.push_back(&categorized_files[index]); const bool should_flush = chunk.size() == 10 || index + 1 == categorized_files.size(); if (!should_flush) { continue; } const size_t start_index = index + 1 - chunk.size(); const size_t end_index = index + 1; process_chunk(chunk, start_index, end_index, categorized_files.size(), llm, taxonomy, items_by_key, new_items_by_key, category_language, progress_callback); chunk.clear(); } } void ConsistencyPassService::run(std::vector& categorized_files, std::vector& newly_categorized_files, std::function()> llm_factory, std::atomic& stop_flag, CategoryLanguage category_language, const ProgressCallback& progress_callback) const { if (stop_flag.load() || categorized_files.empty()) { return; } auto llm = create_llm(std::move(llm_factory)); if (!llm) { return; } const auto taxonomy = db_manager.get_taxonomy_snapshot(150); auto items_by_key = build_items_by_key(categorized_files); auto new_items_by_key = build_items_by_key(newly_categorized_files); process_chunks(*llm, taxonomy, categorized_files, items_by_key, new_items_by_key, stop_flag, category_language, progress_callback); } ================================================ FILE: app/lib/CustomApiDialog.cpp ================================================ #include "CustomApiDialog.hpp" #include #include #include #include #include #include #include #include #include CustomApiDialog::CustomApiDialog(QWidget* parent) : QDialog(parent) { setup_ui(); wire_signals(); } CustomApiDialog::CustomApiDialog(QWidget* parent, const CustomApiEndpoint& existing) : QDialog(parent) { setup_ui(); wire_signals(); apply_existing(existing); } void CustomApiDialog::setup_ui() { setWindowTitle(tr("Custom OpenAI-compatible API")); auto* layout = new QVBoxLayout(this); auto* form = new QFormLayout(); name_edit = new QLineEdit(this); description_edit = new QTextEdit(this); description_edit->setFixedHeight(70); base_url_edit = new QLineEdit(this); base_url_edit->setPlaceholderText(tr("e.g. http://localhost:1234/v1")); model_edit = new QLineEdit(this); model_edit->setPlaceholderText(tr("e.g. llama-3.1, gpt-4o-mini")); api_key_edit = new QLineEdit(this); api_key_edit->setEchoMode(QLineEdit::Password); api_key_edit->setClearButtonEnabled(true); show_api_key_checkbox = new QCheckBox(tr("Show"), this); auto* api_key_row = new QWidget(this); auto* api_key_layout = new QHBoxLayout(api_key_row); api_key_layout->setContentsMargins(0, 0, 0, 0); api_key_layout->addWidget(api_key_edit, 1); api_key_layout->addWidget(show_api_key_checkbox); form->addRow(tr("Display name"), name_edit); form->addRow(tr("Description"), description_edit); form->addRow(tr("Base URL or endpoint"), base_url_edit); form->addRow(tr("Model"), model_edit); form->addRow(tr("API key (optional)"), api_key_row); layout->addLayout(form); auto* hint = new QLabel(tr("Enter a base URL (e.g. http://localhost:1234/v1) or a full /chat/completions endpoint."), this); hint->setWordWrap(true); layout->addWidget(hint); auto* button_box = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); ok_button = button_box->button(QDialogButtonBox::Ok); ok_button->setEnabled(false); layout->addWidget(button_box); connect(button_box, &QDialogButtonBox::accepted, this, &QDialog::accept); connect(button_box, &QDialogButtonBox::rejected, this, &QDialog::reject); } void CustomApiDialog::wire_signals() { connect(name_edit, &QLineEdit::textChanged, this, &CustomApiDialog::validate_inputs); connect(base_url_edit, &QLineEdit::textChanged, this, &CustomApiDialog::validate_inputs); connect(model_edit, &QLineEdit::textChanged, this, &CustomApiDialog::validate_inputs); if (show_api_key_checkbox) { connect(show_api_key_checkbox, &QCheckBox::toggled, this, [this](bool checked) { if (api_key_edit) { api_key_edit->setEchoMode(checked ? QLineEdit::Normal : QLineEdit::Password); } }); } } void CustomApiDialog::apply_existing(const CustomApiEndpoint& existing) { name_edit->setText(QString::fromStdString(existing.name)); description_edit->setPlainText(QString::fromStdString(existing.description)); base_url_edit->setText(QString::fromStdString(existing.base_url)); model_edit->setText(QString::fromStdString(existing.model)); api_key_edit->setText(QString::fromStdString(existing.api_key)); validate_inputs(); } void CustomApiDialog::validate_inputs() { const bool valid = !name_edit->text().trimmed().isEmpty() && !base_url_edit->text().trimmed().isEmpty() && !model_edit->text().trimmed().isEmpty(); if (ok_button) { ok_button->setEnabled(valid); } } CustomApiEndpoint CustomApiDialog::result() const { CustomApiEndpoint endpoint; endpoint.name = name_edit->text().trimmed().toStdString(); endpoint.description = description_edit->toPlainText().trimmed().toStdString(); endpoint.base_url = base_url_edit->text().trimmed().toStdString(); endpoint.model = model_edit->text().trimmed().toStdString(); endpoint.api_key = api_key_edit->text().trimmed().toStdString(); return endpoint; } ================================================ FILE: app/lib/CustomLLMDialog.cpp ================================================ #include "CustomLLMDialog.hpp" #include #include #include #include #include #include #include #include #include CustomLLMDialog::CustomLLMDialog(QWidget* parent) : QDialog(parent) { setup_ui(); wire_signals(); } CustomLLMDialog::CustomLLMDialog(QWidget* parent, const CustomLLM& existing) : QDialog(parent) { setup_ui(); wire_signals(); apply_existing(existing); } void CustomLLMDialog::setup_ui() { setWindowTitle(tr("Custom local LLM")); auto* layout = new QVBoxLayout(this); auto* form = new QFormLayout(); name_edit = new QLineEdit(this); description_edit = new QTextEdit(this); description_edit->setFixedHeight(70); path_edit = new QLineEdit(this); browse_button = new QPushButton(tr("Browse…"), this); auto* path_row = new QHBoxLayout(); path_row->addWidget(path_edit, 1); path_row->addWidget(browse_button); form->addRow(tr("Display name"), name_edit); form->addRow(tr("Description"), description_edit); form->addRow(tr("Model file (.gguf)"), path_row); layout->addLayout(form); auto* button_box = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); ok_button = button_box->button(QDialogButtonBox::Ok); ok_button->setEnabled(false); layout->addWidget(button_box); connect(button_box, &QDialogButtonBox::accepted, this, &QDialog::accept); connect(button_box, &QDialogButtonBox::rejected, this, &QDialog::reject); } void CustomLLMDialog::wire_signals() { connect(name_edit, &QLineEdit::textChanged, this, &CustomLLMDialog::validate_inputs); connect(path_edit, &QLineEdit::textChanged, this, &CustomLLMDialog::validate_inputs); connect(browse_button, &QPushButton::clicked, this, &CustomLLMDialog::browse_for_file); } void CustomLLMDialog::apply_existing(const CustomLLM& existing) { name_edit->setText(QString::fromStdString(existing.name)); description_edit->setPlainText(QString::fromStdString(existing.description)); path_edit->setText(QString::fromStdString(existing.path)); validate_inputs(); } void CustomLLMDialog::validate_inputs() { const bool valid = !name_edit->text().trimmed().isEmpty() && !path_edit->text().trimmed().isEmpty(); if (ok_button) { ok_button->setEnabled(valid); } } void CustomLLMDialog::browse_for_file() { const QString path = QFileDialog::getOpenFileName(this, tr("Select .gguf model"), QString(), tr("GGUF models (*.gguf);;All files (*.*)")); if (!path.isEmpty()) { path_edit->setText(path); } } CustomLLM CustomLLMDialog::result() const { CustomLLM llm; llm.name = name_edit->text().trimmed().toStdString(); llm.description = description_edit->toPlainText().trimmed().toStdString(); llm.path = path_edit->text().trimmed().toStdString(); return llm; } ================================================ FILE: app/lib/DatabaseManager.cpp ================================================ #include "DatabaseManager.hpp" #include "Types.hpp" #include "Logger.hpp" #include "Utils.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace { constexpr double kSimilarityThreshold = 0.85; template void db_log(spdlog::level::level_enum level, const char* fmt, Args&&... args) { auto message = fmt::format(fmt::runtime(fmt), std::forward(args)...); if (auto logger = Logger::get_logger("core_logger")) { logger->log(level, "{}", message); } else { std::fprintf(stderr, "%s\n", message.c_str()); } } bool is_duplicate_column_error(const char *error_msg) { if (!error_msg) { return false; } std::string message(error_msg); std::transform(message.begin(), message.end(), message.begin(), [](unsigned char c) { return static_cast(std::tolower(c)); }); return message.find("duplicate column name") != std::string::npos; } std::string to_lower_copy(std::string value) { std::transform(value.begin(), value.end(), value.begin(), [](unsigned char c) { return static_cast(std::tolower(c)); }); return value; } std::string language_storage_key(CategoryLanguage language) { return to_lower_copy(categoryLanguageDisplay(language)); } std::string extract_extension_lower(const std::string& file_name) { const auto pos = file_name.find_last_of('.'); if (pos == std::string::npos || pos + 1 >= file_name.size()) { return std::string(); } std::string ext = file_name.substr(pos); return to_lower_copy(ext); } struct StatementDeleter { void operator()(sqlite3_stmt* stmt) const { if (stmt) { sqlite3_finalize(stmt); } } }; using StatementPtr = std::unique_ptr; StatementPtr prepare_statement(sqlite3* db, const char* sql) { sqlite3_stmt* raw = nullptr; if (sqlite3_prepare_v2(db, sql, -1, &raw, nullptr) != SQLITE_OK) { return StatementPtr{}; } return StatementPtr(raw); } std::string trim_copy(std::string value) { auto not_space = [](unsigned char ch) { return !std::isspace(ch); }; value.erase(value.begin(), std::find_if(value.begin(), value.end(), not_space)); value.erase(std::find_if(value.rbegin(), value.rend(), not_space).base(), value.end()); return value; } bool has_label_content(const std::string& value) { return !trim_copy(value).empty(); } std::string escape_like_pattern(const std::string& value) { std::string escaped; escaped.reserve(value.size() * 2); for (char ch : value) { if (ch == '\\' || ch == '%' || ch == '_') { escaped.push_back('\\'); } escaped.push_back(ch); } return escaped; } std::string build_recursive_dir_pattern(const std::string& directory_path) { std::string escaped = escape_like_pattern(directory_path); if (directory_path.empty()) { return escaped + "%"; } const char sep = directory_path.find('\\') != std::string::npos ? '\\' : '/'; if (directory_path.back() == sep) { escaped.push_back('%'); return escaped; } if (sep == '\\' || sep == '%' || sep == '_') { escaped.push_back('\\'); } escaped.push_back(sep); escaped.push_back('%'); return escaped; } std::optional build_categorized_entry(sqlite3_stmt* stmt) { const char *file_dir_path = reinterpret_cast(sqlite3_column_text(stmt, 0)); const char *file_name = reinterpret_cast(sqlite3_column_text(stmt, 1)); const char *file_type = reinterpret_cast(sqlite3_column_text(stmt, 2)); const char *category = reinterpret_cast(sqlite3_column_text(stmt, 3)); const char *subcategory = reinterpret_cast(sqlite3_column_text(stmt, 4)); const char *suggested_name = nullptr; if (sqlite3_column_count(stmt) > 5) { suggested_name = reinterpret_cast(sqlite3_column_text(stmt, 5)); } std::string dir_path = file_dir_path ? file_dir_path : ""; std::string name = file_name ? file_name : ""; std::string type_str = file_type ? file_type : ""; std::string cat = Utils::sanitize_path_label(category ? category : ""); std::string subcat = Utils::sanitize_path_label(subcategory ? subcategory : ""); std::string suggested = Utils::sanitize_path_label(suggested_name ? suggested_name : ""); int taxonomy_id = 0; if (sqlite3_column_count(stmt) > 6 && sqlite3_column_type(stmt, 6) != SQLITE_NULL) { taxonomy_id = sqlite3_column_int(stmt, 6); } bool used_consistency = false; if (sqlite3_column_count(stmt) > 7 && sqlite3_column_type(stmt, 7) != SQLITE_NULL) { used_consistency = sqlite3_column_int(stmt, 7) != 0; } bool rename_only = false; if (sqlite3_column_count(stmt) > 8 && sqlite3_column_type(stmt, 8) != SQLITE_NULL) { rename_only = sqlite3_column_int(stmt, 8) != 0; } bool rename_applied = false; if (sqlite3_column_count(stmt) > 9 && sqlite3_column_type(stmt, 9) != SQLITE_NULL) { rename_applied = sqlite3_column_int(stmt, 9) != 0; } const bool has_labels = has_label_content(cat) && has_label_content(subcat); const bool has_suggestion = has_label_content(suggested); if (!rename_only && !has_labels && !has_suggestion) { return std::nullopt; } FileType file_type_enum = (type_str == "F") ? FileType::File : FileType::Directory; CategorizedFile entry{dir_path, name, file_type_enum, cat, subcat, taxonomy_id}; entry.from_cache = true; entry.used_consistency_hints = used_consistency; entry.suggested_name = suggested; entry.rename_only = rename_only; entry.rename_applied = rename_applied; entry.canonical_category = cat; entry.canonical_subcategory = subcat; return entry; } } // namespace DatabaseManager::DatabaseManager(std::string config_dir) : db(nullptr), config_dir(std::move(config_dir)), db_file(this->config_dir + "/" + (std::getenv("CATEGORIZATION_CACHE_FILE") ? std::getenv("CATEGORIZATION_CACHE_FILE") : "categorization_results.db")) { if (db_file.empty()) { db_log(spdlog::level::err, "Error: Database path is empty"); return; } if (sqlite3_open(db_file.c_str(), &db) != SQLITE_OK) { db_log(spdlog::level::err, "Can't open database: {}", sqlite3_errmsg(db)); db = nullptr; return; } sqlite3_extended_result_codes(db, 1); initialize_schema(); initialize_taxonomy_schema(); load_taxonomy_cache(); load_translation_cache(); } DatabaseManager::~DatabaseManager() { if (db) { sqlite3_close(db); db = nullptr; } } void DatabaseManager::initialize_schema() { if (!db) return; const char *create_table_sql = R"( CREATE TABLE IF NOT EXISTS file_categorization ( id INTEGER PRIMARY KEY AUTOINCREMENT, file_name TEXT NOT NULL, file_type TEXT NOT NULL, dir_path TEXT NOT NULL, category TEXT NOT NULL, subcategory TEXT, suggested_name TEXT, taxonomy_id INTEGER, categorization_style INTEGER DEFAULT 0, rename_only INTEGER DEFAULT 0, rename_applied INTEGER DEFAULT 0, timestamp DATETIME DEFAULT CURRENT_TIMESTAMP, UNIQUE(file_name, file_type, dir_path) ); )"; char *error_msg = nullptr; if (sqlite3_exec(db, create_table_sql, nullptr, nullptr, &error_msg) != SQLITE_OK) { db_log(spdlog::level::err, "Failed to create file_categorization table: {}", error_msg); sqlite3_free(error_msg); } const char *add_column_sql = "ALTER TABLE file_categorization ADD COLUMN taxonomy_id INTEGER;"; if (sqlite3_exec(db, add_column_sql, nullptr, nullptr, &error_msg) != SQLITE_OK) { if (!is_duplicate_column_error(error_msg)) { db_log(spdlog::level::warn, "Failed to add taxonomy_id column: {}", error_msg ? error_msg : ""); } if (error_msg) { sqlite3_free(error_msg); } } const char *add_style_column_sql = "ALTER TABLE file_categorization ADD COLUMN categorization_style INTEGER DEFAULT 0;"; if (sqlite3_exec(db, add_style_column_sql, nullptr, nullptr, &error_msg) != SQLITE_OK) { if (!is_duplicate_column_error(error_msg)) { db_log(spdlog::level::warn, "Failed to add categorization_style column: {}", error_msg ? error_msg : ""); } if (error_msg) { sqlite3_free(error_msg); } } const char *add_suggested_name_column_sql = "ALTER TABLE file_categorization ADD COLUMN suggested_name TEXT;"; if (sqlite3_exec(db, add_suggested_name_column_sql, nullptr, nullptr, &error_msg) != SQLITE_OK) { if (!is_duplicate_column_error(error_msg)) { db_log(spdlog::level::warn, "Failed to add suggested_name column: {}", error_msg ? error_msg : ""); } if (error_msg) { sqlite3_free(error_msg); } } const char *add_rename_only_column_sql = "ALTER TABLE file_categorization ADD COLUMN rename_only INTEGER DEFAULT 0;"; if (sqlite3_exec(db, add_rename_only_column_sql, nullptr, nullptr, &error_msg) != SQLITE_OK) { if (!is_duplicate_column_error(error_msg)) { db_log(spdlog::level::warn, "Failed to add rename_only column: {}", error_msg ? error_msg : ""); } if (error_msg) { sqlite3_free(error_msg); } } const char *add_rename_applied_column_sql = "ALTER TABLE file_categorization ADD COLUMN rename_applied INTEGER DEFAULT 0;"; if (sqlite3_exec(db, add_rename_applied_column_sql, nullptr, nullptr, &error_msg) != SQLITE_OK) { if (!is_duplicate_column_error(error_msg)) { db_log(spdlog::level::warn, "Failed to add rename_applied column: {}", error_msg ? error_msg : ""); } if (error_msg) { sqlite3_free(error_msg); } } const char *create_index_sql = "CREATE INDEX IF NOT EXISTS idx_file_categorization_taxonomy ON file_categorization(taxonomy_id);"; if (sqlite3_exec(db, create_index_sql, nullptr, nullptr, &error_msg) != SQLITE_OK) { db_log(spdlog::level::err, "Failed to create taxonomy index: {}", error_msg); sqlite3_free(error_msg); } } void DatabaseManager::initialize_taxonomy_schema() { if (!db) return; const char *taxonomy_sql = R"( CREATE TABLE IF NOT EXISTS category_taxonomy ( id INTEGER PRIMARY KEY AUTOINCREMENT, canonical_category TEXT NOT NULL, canonical_subcategory TEXT NOT NULL, normalized_category TEXT NOT NULL, normalized_subcategory TEXT NOT NULL, frequency INTEGER DEFAULT 0, UNIQUE(normalized_category, normalized_subcategory) ); )"; char *error_msg = nullptr; if (sqlite3_exec(db, taxonomy_sql, nullptr, nullptr, &error_msg) != SQLITE_OK) { db_log(spdlog::level::err, "Failed to create category_taxonomy table: {}", error_msg); sqlite3_free(error_msg); } const char *alias_sql = R"( CREATE TABLE IF NOT EXISTS category_alias ( alias_category_norm TEXT NOT NULL, alias_subcategory_norm TEXT NOT NULL, taxonomy_id INTEGER NOT NULL, PRIMARY KEY(alias_category_norm, alias_subcategory_norm), FOREIGN KEY(taxonomy_id) REFERENCES category_taxonomy(id) ); )"; if (sqlite3_exec(db, alias_sql, nullptr, nullptr, &error_msg) != SQLITE_OK) { db_log(spdlog::level::err, "Failed to create category_alias table: {}", error_msg); sqlite3_free(error_msg); } const char *alias_index_sql = "CREATE INDEX IF NOT EXISTS idx_category_alias_taxonomy ON category_alias(taxonomy_id);"; if (sqlite3_exec(db, alias_index_sql, nullptr, nullptr, &error_msg) != SQLITE_OK) { db_log(spdlog::level::err, "Failed to create alias index: {}", error_msg); sqlite3_free(error_msg); } const char* translation_sql = R"( CREATE TABLE IF NOT EXISTS category_translation ( taxonomy_id INTEGER NOT NULL, language TEXT NOT NULL, category TEXT NOT NULL, subcategory TEXT NOT NULL, normalized_category TEXT NOT NULL, normalized_subcategory TEXT NOT NULL, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY(taxonomy_id, language), FOREIGN KEY(taxonomy_id) REFERENCES category_taxonomy(id) ); )"; if (sqlite3_exec(db, translation_sql, nullptr, nullptr, &error_msg) != SQLITE_OK) { db_log(spdlog::level::err, "Failed to create category_translation table: {}", error_msg); sqlite3_free(error_msg); } const char* translation_lookup_index_sql = "CREATE INDEX IF NOT EXISTS idx_category_translation_lookup " "ON category_translation(language, normalized_category, normalized_subcategory);"; if (sqlite3_exec(db, translation_lookup_index_sql, nullptr, nullptr, &error_msg) != SQLITE_OK) { db_log(spdlog::level::err, "Failed to create translation lookup index: {}", error_msg); sqlite3_free(error_msg); } } void DatabaseManager::load_taxonomy_cache() { taxonomy_entries.clear(); canonical_lookup.clear(); alias_lookup.clear(); taxonomy_index.clear(); if (!db) return; sqlite3_stmt *stmt = nullptr; const char *select_taxonomy = "SELECT id, canonical_category, canonical_subcategory, " "normalized_category, normalized_subcategory, frequency FROM category_taxonomy;"; if (sqlite3_prepare_v2(db, select_taxonomy, -1, &stmt, nullptr) == SQLITE_OK) { while (sqlite3_step(stmt) == SQLITE_ROW) { TaxonomyEntry entry; entry.id = sqlite3_column_int(stmt, 0); entry.category = reinterpret_cast(sqlite3_column_text(stmt, 1)); entry.subcategory = reinterpret_cast(sqlite3_column_text(stmt, 2)); entry.normalized_category = reinterpret_cast(sqlite3_column_text(stmt, 3)); entry.normalized_subcategory = reinterpret_cast(sqlite3_column_text(stmt, 4)); taxonomy_index[entry.id] = taxonomy_entries.size(); taxonomy_entries.push_back(entry); canonical_lookup[make_key(entry.normalized_category, entry.normalized_subcategory)] = entry.id; } } else { db_log(spdlog::level::err, "Failed to load taxonomy cache: {}", sqlite3_errmsg(db)); } if (stmt) sqlite3_finalize(stmt); const char *select_alias = "SELECT alias_category_norm, alias_subcategory_norm, taxonomy_id FROM category_alias;"; if (sqlite3_prepare_v2(db, select_alias, -1, &stmt, nullptr) == SQLITE_OK) { while (sqlite3_step(stmt) == SQLITE_ROW) { std::string alias_cat = reinterpret_cast(sqlite3_column_text(stmt, 0)); std::string alias_subcat = reinterpret_cast(sqlite3_column_text(stmt, 1)); int taxonomy_id = sqlite3_column_int(stmt, 2); alias_lookup[make_key(alias_cat, alias_subcat)] = taxonomy_id; } } else { db_log(spdlog::level::err, "Failed to load category aliases: {}", sqlite3_errmsg(db)); } if (stmt) sqlite3_finalize(stmt); } void DatabaseManager::load_translation_cache() { translation_entries.clear(); translation_lookup.clear(); if (!db) { return; } sqlite3_stmt* stmt = nullptr; const char* select_translation = "SELECT taxonomy_id, language, category, subcategory, normalized_category, normalized_subcategory " "FROM category_translation;"; if (sqlite3_prepare_v2(db, select_translation, -1, &stmt, nullptr) == SQLITE_OK) { while (sqlite3_step(stmt) == SQLITE_ROW) { const int taxonomy_id = sqlite3_column_int(stmt, 0); const char* language_text = reinterpret_cast(sqlite3_column_text(stmt, 1)); const char* category_text = reinterpret_cast(sqlite3_column_text(stmt, 2)); const char* subcategory_text = reinterpret_cast(sqlite3_column_text(stmt, 3)); const char* normalized_category = reinterpret_cast(sqlite3_column_text(stmt, 4)); const char* normalized_subcategory = reinterpret_cast(sqlite3_column_text(stmt, 5)); CategoryLanguage language = categoryLanguageFromString(QString::fromStdString(language_text ? language_text : "")); ResolvedCategory translated{ taxonomy_id, category_text ? category_text : "", subcategory_text ? subcategory_text : "" }; translation_entries[make_translation_entry_key(taxonomy_id, language)] = translated; translation_lookup[make_translation_lookup_key(language, normalized_category ? normalized_category : "", normalized_subcategory ? normalized_subcategory : "")] = taxonomy_id; } } else { db_log(spdlog::level::err, "Failed to load category translations: {}", sqlite3_errmsg(db)); } if (stmt) { sqlite3_finalize(stmt); } } std::string DatabaseManager::normalize_label(const std::string &input) const { std::string result; result.reserve(input.size()); bool last_was_space = true; for (unsigned char ch : input) { if (std::isalnum(ch)) { result.push_back(static_cast(std::tolower(ch))); last_was_space = false; } else if (std::isspace(ch)) { if (!last_was_space) { result.push_back(' '); last_was_space = true; } } } // Trim leading/trailing space if any while (!result.empty() && result.front() == ' ') { result.erase(result.begin()); } while (!result.empty() && result.back() == ' ') { result.pop_back(); } return result; } std::string DatabaseManager::make_translation_entry_key(int taxonomy_id, CategoryLanguage language) { return fmt::format("{}|{}", taxonomy_id, language_storage_key(language)); } std::string DatabaseManager::make_translation_lookup_key(CategoryLanguage language, const std::string& norm_category, const std::string& norm_subcategory) { return fmt::format("{}|{}|{}", language_storage_key(language), norm_category, norm_subcategory); } static std::string strip_trailing_stopwords(const std::string& normalized) { if (normalized.empty()) { return normalized; } static const std::unordered_set kStopwords = { "file", "files", "doc", "docs", "document", "documents", "image", "images", "photo", "photos", "pic", "pics" }; std::istringstream iss(normalized); std::vector tokens; std::string token; while (iss >> token) { tokens.push_back(token); } if (tokens.size() <= 1) { return normalized; } while (tokens.size() > 1 && kStopwords.contains(tokens.back())) { tokens.pop_back(); } if (tokens.empty()) { return normalized; } std::string joined; for (size_t index = 0; index < tokens.size(); ++index) { if (index > 0) { joined.push_back(' '); } joined += tokens[index]; } return joined; } struct CanonicalCategoryLabel { std::string normalized; std::string display; }; bool is_image_like_label(const std::string& normalized) { if (normalized.empty()) { return false; } static const std::unordered_set kImageLike = { "image", "images", "image file", "image files", "photo", "photos", "graphic", "graphics", "picture", "pictures", "pic", "pics", "screenshot", "screenshots", "wallpaper", "wallpapers" }; if (kImageLike.contains(normalized)) { return true; } return kImageLike.contains(strip_trailing_stopwords(normalized)); } CanonicalCategoryLabel canonicalize_category_label(const std::string& normalized_category, const std::string& normalized_subcategory) { static const std::unordered_map kCategorySynonyms = { {"archive", {"archives", "Archives"}}, {"archives", {"archives", "Archives"}}, {"backup", {"archives", "Archives"}}, {"backups", {"archives", "Archives"}}, {"backup file", {"archives", "Archives"}}, {"backup files", {"archives", "Archives"}}, {"document", {"documents", "Documents"}}, {"documents", {"documents", "Documents"}}, {"doc", {"documents", "Documents"}}, {"docs", {"documents", "Documents"}}, {"text", {"documents", "Documents"}}, {"texts", {"documents", "Documents"}}, {"paper", {"documents", "Documents"}}, {"papers", {"documents", "Documents"}}, {"report", {"documents", "Documents"}}, {"reports", {"documents", "Documents"}}, {"spreadsheet", {"documents", "Documents"}}, {"spreadsheets", {"documents", "Documents"}}, {"table", {"documents", "Documents"}}, {"tables", {"documents", "Documents"}}, {"office file", {"documents", "Documents"}}, {"office files", {"documents", "Documents"}}, {"software", {"software", "Software"}}, {"application", {"software", "Software"}}, {"applications", {"software", "Software"}}, {"app", {"software", "Software"}}, {"apps", {"software", "Software"}}, {"program", {"software", "Software"}}, {"programs", {"software", "Software"}}, {"installer", {"software", "Software"}}, {"installers", {"software", "Software"}}, {"installation", {"software", "Software"}}, {"installations", {"software", "Software"}}, {"installation file", {"software", "Software"}}, {"installation files", {"software", "Software"}}, {"software installation", {"software", "Software"}}, {"software installations", {"software", "Software"}}, {"software installation file", {"software", "Software"}}, {"software installation files", {"software", "Software"}}, {"setup", {"software", "Software"}}, {"setups", {"software", "Software"}}, {"setup file", {"software", "Software"}}, {"setup files", {"software", "Software"}}, {"update", {"software", "Software"}}, {"updates", {"software", "Software"}}, {"software update", {"software", "Software"}}, {"software updates", {"software", "Software"}}, {"patch", {"software", "Software"}}, {"patches", {"software", "Software"}}, {"upgrade", {"software", "Software"}}, {"upgrades", {"software", "Software"}}, {"updater", {"software", "Software"}}, {"updaters", {"software", "Software"}}, {"image", {"images", "Images"}}, {"images", {"images", "Images"}}, {"image file", {"images", "Images"}}, {"image files", {"images", "Images"}}, {"photo", {"images", "Images"}}, {"photos", {"images", "Images"}}, {"graphic", {"images", "Images"}}, {"graphics", {"images", "Images"}}, {"picture", {"images", "Images"}}, {"pictures", {"images", "Images"}}, {"pic", {"images", "Images"}}, {"pics", {"images", "Images"}}, {"screenshot", {"images", "Images"}}, {"screenshots", {"images", "Images"}}, {"wallpaper", {"images", "Images"}}, {"wallpapers", {"images", "Images"}} }; if (auto it = kCategorySynonyms.find(normalized_category); it != kCategorySynonyms.end()) { return it->second; } const std::string stripped_category = strip_trailing_stopwords(normalized_category); if (auto it = kCategorySynonyms.find(stripped_category); it != kCategorySynonyms.end()) { return it->second; } // "Media" can be broader than images, so only collapse when the paired subcategory is image-like. if ((normalized_category == "media" || stripped_category == "media") && is_image_like_label(normalized_subcategory)) { return {"images", "Images"}; } return {normalized_category, ""}; } double DatabaseManager::string_similarity(const std::string &a, const std::string &b) { if (a == b) { return 1.0; } if (a.empty() || b.empty()) { return 0.0; } const size_t m = a.size(); const size_t n = b.size(); std::vector prev(n + 1), curr(n + 1); for (size_t j = 0; j <= n; ++j) { prev[j] = j; } for (size_t i = 1; i <= m; ++i) { curr[0] = i; for (size_t j = 1; j <= n; ++j) { size_t cost = (a[i - 1] == b[j - 1]) ? 0 : 1; curr[j] = std::min({prev[j] + 1, curr[j - 1] + 1, prev[j - 1] + cost}); } std::swap(prev, curr); } const double dist = static_cast(prev[n]); const double max_len = static_cast(std::max(m, n)); return 1.0 - (dist / max_len); } std::string DatabaseManager::make_key(const std::string &norm_category, const std::string &norm_subcategory) { return norm_category + "::" + norm_subcategory; } int DatabaseManager::create_taxonomy_entry(const std::string &category, const std::string &subcategory, const std::string &norm_category, const std::string &norm_subcategory) { if (!db) return -1; const char *sql = R"( INSERT INTO category_taxonomy (canonical_category, canonical_subcategory, normalized_category, normalized_subcategory, frequency) VALUES (?, ?, ?, ?, 0); )"; sqlite3_stmt *stmt = nullptr; if (sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr) != SQLITE_OK) { db_log(spdlog::level::err, "Failed to prepare taxonomy insert: {}", sqlite3_errmsg(db)); return -1; } sqlite3_bind_text(stmt, 1, category.c_str(), -1, SQLITE_TRANSIENT); sqlite3_bind_text(stmt, 2, subcategory.c_str(), -1, SQLITE_TRANSIENT); sqlite3_bind_text(stmt, 3, norm_category.c_str(), -1, SQLITE_TRANSIENT); sqlite3_bind_text(stmt, 4, norm_subcategory.c_str(), -1, SQLITE_TRANSIENT); int step_rc = sqlite3_step(stmt); int extended_rc = sqlite3_extended_errcode(db); sqlite3_finalize(stmt); if (step_rc != SQLITE_DONE) { if (extended_rc == SQLITE_CONSTRAINT_UNIQUE || extended_rc == SQLITE_CONSTRAINT_PRIMARYKEY || extended_rc == SQLITE_CONSTRAINT) { return find_existing_taxonomy_id(norm_category, norm_subcategory); } db_log(spdlog::level::err, "Failed to insert taxonomy entry: {}", sqlite3_errmsg(db)); return -1; } int new_id = static_cast(sqlite3_last_insert_rowid(db)); TaxonomyEntry entry{new_id, category, subcategory, norm_category, norm_subcategory}; taxonomy_index[new_id] = taxonomy_entries.size(); taxonomy_entries.push_back(entry); canonical_lookup[make_key(norm_category, norm_subcategory)] = new_id; return new_id; } int DatabaseManager::find_existing_taxonomy_id(const std::string &norm_category, const std::string &norm_subcategory) const { if (!db) return -1; const char *select_sql = "SELECT id FROM category_taxonomy WHERE normalized_category = ? AND normalized_subcategory = ? LIMIT 1;"; sqlite3_stmt *stmt = nullptr; int existing_id = -1; if (sqlite3_prepare_v2(db, select_sql, -1, &stmt, nullptr) == SQLITE_OK) { sqlite3_bind_text(stmt, 1, norm_category.c_str(), -1, SQLITE_TRANSIENT); sqlite3_bind_text(stmt, 2, norm_subcategory.c_str(), -1, SQLITE_TRANSIENT); if (sqlite3_step(stmt) == SQLITE_ROW) { existing_id = sqlite3_column_int(stmt, 0); } } if (stmt) { sqlite3_finalize(stmt); } return existing_id; } void DatabaseManager::ensure_alias_mapping(int taxonomy_id, const std::string &norm_category, const std::string &norm_subcategory) { if (!db) return; std::string key = make_key(norm_category, norm_subcategory); auto canonical_it = canonical_lookup.find(key); if (canonical_it != canonical_lookup.end() && canonical_it->second == taxonomy_id) { return; // Already canonical form } if (alias_lookup.find(key) != alias_lookup.end()) { return; } const char *sql = R"( INSERT OR IGNORE INTO category_alias (alias_category_norm, alias_subcategory_norm, taxonomy_id) VALUES (?, ?, ?); )"; sqlite3_stmt *stmt = nullptr; if (sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr) != SQLITE_OK) { db_log(spdlog::level::err, "Failed to prepare alias insert: {}", sqlite3_errmsg(db)); return; } sqlite3_bind_text(stmt, 1, norm_category.c_str(), -1, SQLITE_TRANSIENT); sqlite3_bind_text(stmt, 2, norm_subcategory.c_str(), -1, SQLITE_TRANSIENT); sqlite3_bind_int(stmt, 3, taxonomy_id); if (sqlite3_step(stmt) != SQLITE_DONE) { db_log(spdlog::level::err, "Failed to insert alias: {}", sqlite3_errmsg(db)); sqlite3_finalize(stmt); return; } sqlite3_finalize(stmt); alias_lookup[key] = taxonomy_id; } const DatabaseManager::TaxonomyEntry *DatabaseManager::find_taxonomy_entry(int taxonomy_id) const { auto it = taxonomy_index.find(taxonomy_id); if (it == taxonomy_index.end()) { return nullptr; } size_t idx = it->second; if (idx >= taxonomy_entries.size()) { return nullptr; } return &taxonomy_entries[idx]; } std::pair DatabaseManager::find_fuzzy_match( const std::string& norm_category, const std::string& norm_subcategory) const { if (taxonomy_entries.empty()) { return {-1, 0.0}; } double best_score = 0.0; int best_id = -1; for (const auto &entry : taxonomy_entries) { double category_score = string_similarity(norm_category, entry.normalized_category); double subcategory_score = string_similarity(norm_subcategory, entry.normalized_subcategory); double combined = (category_score + subcategory_score) / 2.0; if (combined > best_score) { best_score = combined; best_id = entry.id; } } if (best_id != -1 && best_score >= kSimilarityThreshold) { return {best_id, best_score}; } return {-1, best_score}; } int DatabaseManager::resolve_existing_taxonomy(const std::string& key, const std::string& norm_category, const std::string& norm_subcategory) const { auto alias_it = alias_lookup.find(key); if (alias_it != alias_lookup.end()) { return alias_it->second; } auto canonical_it = canonical_lookup.find(key); if (canonical_it != canonical_lookup.end()) { return canonical_it->second; } auto [best_id, score] = find_fuzzy_match(norm_category, norm_subcategory); return best_id; } DatabaseManager::ResolvedCategory DatabaseManager::build_resolved_category( int taxonomy_id, const std::string& fallback_category, const std::string& fallback_subcategory, const std::string& norm_category, const std::string& norm_subcategory) { ResolvedCategory result{-1, fallback_category, fallback_subcategory}; if (taxonomy_id == -1) { taxonomy_id = create_taxonomy_entry(fallback_category, fallback_subcategory, norm_category, norm_subcategory); } if (taxonomy_id != -1) { ensure_alias_mapping(taxonomy_id, norm_category, norm_subcategory); if (const auto *entry = find_taxonomy_entry(taxonomy_id)) { result.taxonomy_id = entry->id; result.category = entry->category; result.subcategory = entry->subcategory; } else { result.taxonomy_id = taxonomy_id; } } else { result.category = fallback_category; result.subcategory = fallback_subcategory; } return result; } DatabaseManager::ResolvedCategory DatabaseManager::resolve_category(const std::string &category, const std::string &subcategory) { ResolvedCategory result{-1, category, subcategory}; if (!db) { return result; } auto trim_copy = [](std::string value) { auto is_space = [](unsigned char ch) { return std::isspace(ch); }; value.erase(value.begin(), std::find_if(value.begin(), value.end(), [&](unsigned char ch) { return !is_space(ch); })); value.erase(std::find_if(value.rbegin(), value.rend(), [&](unsigned char ch) { return !is_space(ch); }).base(), value.end()); return value; }; std::string trimmed_category = trim_copy(category); std::string trimmed_subcategory = trim_copy(subcategory); if (trimmed_category.empty()) { trimmed_category = "Uncategorized"; } if (trimmed_subcategory.empty()) { trimmed_subcategory = "General"; } std::string norm_category = normalize_label(trimmed_category); std::string norm_subcategory = normalize_label(trimmed_subcategory); const CanonicalCategoryLabel canonical_category = canonicalize_category_label(norm_category, norm_subcategory); norm_category = canonical_category.normalized; if (!canonical_category.display.empty()) { trimmed_category = canonical_category.display; } const std::string match_subcategory = strip_trailing_stopwords(norm_subcategory); std::string key = make_key(norm_category, match_subcategory); int taxonomy_id = resolve_existing_taxonomy(key, norm_category, match_subcategory); if (taxonomy_id == -1 && match_subcategory != norm_subcategory) { const std::string raw_key = make_key(norm_category, norm_subcategory); taxonomy_id = resolve_existing_taxonomy(raw_key, norm_category, norm_subcategory); } return build_resolved_category(taxonomy_id, trimmed_category, trimmed_subcategory, norm_category, match_subcategory); } DatabaseManager::ResolvedCategory DatabaseManager::resolve_category_for_language(const std::string& category, const std::string& subcategory, CategoryLanguage language) { if (language == CategoryLanguage::English || !db) { return resolve_category(category, subcategory); } auto trim_copy = [](std::string value) { auto is_space = [](unsigned char ch) { return std::isspace(ch); }; value.erase(value.begin(), std::find_if(value.begin(), value.end(), [&](unsigned char ch) { return !is_space(ch); })); value.erase(std::find_if(value.rbegin(), value.rend(), [&](unsigned char ch) { return !is_space(ch); }).base(), value.end()); return value; }; std::string trimmed_category = trim_copy(category); std::string trimmed_subcategory = trim_copy(subcategory); if (trimmed_category.empty()) { return resolve_category(category, subcategory); } if (trimmed_subcategory.empty()) { trimmed_subcategory = "General"; } const std::string normalized_category = normalize_label(trimmed_category); const std::string normalized_subcategory = normalize_label(trimmed_subcategory); const std::string stripped_subcategory = strip_trailing_stopwords(normalized_subcategory); const auto lookup_translation = [&](const std::string& norm_subcategory) -> int { const auto it = translation_lookup.find(make_translation_lookup_key(language, normalized_category, norm_subcategory)); return it != translation_lookup.end() ? it->second : -1; }; int taxonomy_id = lookup_translation(stripped_subcategory); if (taxonomy_id == -1 && stripped_subcategory != normalized_subcategory) { taxonomy_id = lookup_translation(normalized_subcategory); } if (taxonomy_id != -1) { if (const auto* entry = find_taxonomy_entry(taxonomy_id)) { return ResolvedCategory{entry->id, entry->category, entry->subcategory}; } return ResolvedCategory{taxonomy_id, trimmed_category, trimmed_subcategory}; } return resolve_category(category, subcategory); } std::optional DatabaseManager::get_category_translation(int taxonomy_id, CategoryLanguage language) const { if (language == CategoryLanguage::English || taxonomy_id <= 0) { return std::nullopt; } const auto it = translation_entries.find(make_translation_entry_key(taxonomy_id, language)); if (it == translation_entries.end()) { return std::nullopt; } return it->second; } DatabaseManager::ResolvedCategory DatabaseManager::localize_category(const ResolvedCategory& resolved, CategoryLanguage language) const { if (language == CategoryLanguage::English || resolved.taxonomy_id <= 0) { return resolved; } if (const auto translated = get_category_translation(resolved.taxonomy_id, language)) { return *translated; } if (const auto* entry = find_taxonomy_entry(resolved.taxonomy_id)) { return ResolvedCategory{entry->id, entry->category, entry->subcategory}; } return resolved; } CategorizedFile DatabaseManager::localize_categorized_file(const CategorizedFile& entry, CategoryLanguage language) const { CategorizedFile localized = entry; if (localized.canonical_category.empty()) { localized.canonical_category = entry.category; } if (localized.canonical_subcategory.empty()) { localized.canonical_subcategory = entry.subcategory; } if (const auto translated = get_category_translation(entry.taxonomy_id, language)) { localized.category = translated->category; localized.subcategory = translated->subcategory; } return localized; } bool DatabaseManager::upsert_category_translation(int taxonomy_id, CategoryLanguage language, const std::string& category, const std::string& subcategory) { if (!db || taxonomy_id <= 0 || language == CategoryLanguage::English) { return false; } const std::string sanitized_category = Utils::sanitize_path_label(category); const std::string sanitized_subcategory = Utils::sanitize_path_label(subcategory); if (sanitized_category.empty() || sanitized_subcategory.empty()) { return false; } const std::string normalized_category = normalize_label(sanitized_category); const std::string normalized_subcategory = normalize_label(sanitized_subcategory); const std::string language_key = language_storage_key(language); const char* sql = R"( INSERT INTO category_translation (taxonomy_id, language, category, subcategory, normalized_category, normalized_subcategory, updated_at) VALUES (?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP) ON CONFLICT(taxonomy_id, language) DO UPDATE SET category = excluded.category, subcategory = excluded.subcategory, normalized_category = excluded.normalized_category, normalized_subcategory = excluded.normalized_subcategory, updated_at = CURRENT_TIMESTAMP; )"; sqlite3_stmt* stmt = nullptr; if (sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr) != SQLITE_OK) { db_log(spdlog::level::err, "Failed to prepare translation upsert: {}", sqlite3_errmsg(db)); return false; } sqlite3_bind_int(stmt, 1, taxonomy_id); sqlite3_bind_text(stmt, 2, language_key.c_str(), -1, SQLITE_TRANSIENT); sqlite3_bind_text(stmt, 3, sanitized_category.c_str(), -1, SQLITE_TRANSIENT); sqlite3_bind_text(stmt, 4, sanitized_subcategory.c_str(), -1, SQLITE_TRANSIENT); sqlite3_bind_text(stmt, 5, normalized_category.c_str(), -1, SQLITE_TRANSIENT); sqlite3_bind_text(stmt, 6, normalized_subcategory.c_str(), -1, SQLITE_TRANSIENT); const bool success = sqlite3_step(stmt) == SQLITE_DONE; if (!success) { db_log(spdlog::level::err, "Failed to upsert category translation: {}", sqlite3_errmsg(db)); } sqlite3_finalize(stmt); if (!success) { return false; } const ResolvedCategory translated{taxonomy_id, sanitized_category, sanitized_subcategory}; translation_entries[make_translation_entry_key(taxonomy_id, language)] = translated; translation_lookup[make_translation_lookup_key(language, normalized_category, normalized_subcategory)] = taxonomy_id; return true; } bool DatabaseManager::insert_or_update_file_with_categorization( const std::string &file_name, const std::string &file_type, const std::string &dir_path, const ResolvedCategory &resolved, bool used_consistency_hints, const std::string &suggested_name, bool rename_only, bool rename_applied) { if (!db) return false; const char *sql = R"( INSERT INTO file_categorization (file_name, file_type, dir_path, category, subcategory, suggested_name, taxonomy_id, categorization_style, rename_only, rename_applied) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT(file_name, file_type, dir_path) DO UPDATE SET category = excluded.category, subcategory = excluded.subcategory, suggested_name = excluded.suggested_name, taxonomy_id = excluded.taxonomy_id, categorization_style = excluded.categorization_style, rename_only = excluded.rename_only, rename_applied = CASE WHEN excluded.rename_applied = 1 THEN 1 ELSE rename_applied END; )"; sqlite3_stmt *stmt = nullptr; if (sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr) != SQLITE_OK) { db_log(spdlog::level::err, "SQL prepare error: {}", sqlite3_errmsg(db)); return false; } sqlite3_bind_text(stmt, 1, file_name.c_str(), -1, SQLITE_TRANSIENT); sqlite3_bind_text(stmt, 2, file_type.c_str(), -1, SQLITE_TRANSIENT); sqlite3_bind_text(stmt, 3, dir_path.c_str(), -1, SQLITE_TRANSIENT); sqlite3_bind_text(stmt, 4, resolved.category.c_str(), -1, SQLITE_TRANSIENT); sqlite3_bind_text(stmt, 5, resolved.subcategory.c_str(), -1, SQLITE_TRANSIENT); sqlite3_bind_text(stmt, 6, suggested_name.c_str(), -1, SQLITE_TRANSIENT); if (resolved.taxonomy_id > 0) { sqlite3_bind_int(stmt, 7, resolved.taxonomy_id); } else { sqlite3_bind_null(stmt, 7); } sqlite3_bind_int(stmt, 8, used_consistency_hints ? 1 : 0); sqlite3_bind_int(stmt, 9, rename_only ? 1 : 0); sqlite3_bind_int(stmt, 10, rename_applied ? 1 : 0); bool success = true; if (sqlite3_step(stmt) != SQLITE_DONE) { db_log(spdlog::level::err, "SQL error during insert/update: {}", sqlite3_errmsg(db)); success = false; } sqlite3_finalize(stmt); if (success && resolved.taxonomy_id > 0) { increment_taxonomy_frequency(resolved.taxonomy_id); } return success; } bool DatabaseManager::remove_file_categorization(const std::string& dir_path, const std::string& file_name, const FileType file_type) { if (!db) { return false; } const char* sql = "DELETE FROM file_categorization WHERE dir_path = ? AND file_name = ? AND file_type = ?;"; sqlite3_stmt* stmt = nullptr; if (sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr) != SQLITE_OK) { db_log(spdlog::level::err, "Failed to prepare delete categorization statement: {}", sqlite3_errmsg(db)); return false; } const std::string type_str = (file_type == FileType::File) ? "F" : "D"; sqlite3_bind_text(stmt, 1, dir_path.c_str(), -1, SQLITE_TRANSIENT); sqlite3_bind_text(stmt, 2, file_name.c_str(), -1, SQLITE_TRANSIENT); sqlite3_bind_text(stmt, 3, type_str.c_str(), -1, SQLITE_TRANSIENT); const bool success = sqlite3_step(stmt) == SQLITE_DONE; if (!success) { db_log(spdlog::level::err, "Failed to delete cached categorization for '{}': {}", file_name, sqlite3_errmsg(db)); } sqlite3_finalize(stmt); return success; } bool DatabaseManager::clear_directory_categorizations(const std::string& dir_path, bool recursive) { if (!db) { return false; } const char* sql = recursive ? "DELETE FROM file_categorization WHERE dir_path = ? OR dir_path LIKE ? ESCAPE '\\';" : "DELETE FROM file_categorization WHERE dir_path = ?;"; sqlite3_stmt* stmt = nullptr; if (sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr) != SQLITE_OK) { db_log(spdlog::level::err, "Failed to prepare directory cache clear statement: {}", sqlite3_errmsg(db)); return false; } sqlite3_bind_text(stmt, 1, dir_path.c_str(), -1, SQLITE_TRANSIENT); if (recursive) { const std::string pattern = build_recursive_dir_pattern(dir_path); sqlite3_bind_text(stmt, 2, pattern.c_str(), -1, SQLITE_TRANSIENT); } const bool success = sqlite3_step(stmt) == SQLITE_DONE; if (!success) { db_log(spdlog::level::err, "Failed to clear cached categorizations for '{}': {}", dir_path, sqlite3_errmsg(db)); } sqlite3_finalize(stmt); cached_results.clear(); return success; } bool DatabaseManager::has_categorization_style_conflict(const std::string& dir_path, bool desired_style, bool recursive) const { if (!db) { return false; } const char* sql = recursive ? "SELECT 1 FROM file_categorization " "WHERE (dir_path = ? OR dir_path LIKE ? ESCAPE '\\') " "AND IFNULL(categorization_style, 0) != ? " "LIMIT 1;" : "SELECT 1 FROM file_categorization " "WHERE dir_path = ? AND IFNULL(categorization_style, 0) != ? " "LIMIT 1;"; sqlite3_stmt* stmt = nullptr; if (sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr) != SQLITE_OK) { db_log(spdlog::level::warn, "Failed to prepare cached style conflict query: {}", sqlite3_errmsg(db)); return false; } sqlite3_bind_text(stmt, 1, dir_path.c_str(), -1, SQLITE_TRANSIENT); int bind_index = 2; if (recursive) { const std::string pattern = build_recursive_dir_pattern(dir_path); sqlite3_bind_text(stmt, bind_index++, pattern.c_str(), -1, SQLITE_TRANSIENT); } sqlite3_bind_int(stmt, bind_index, desired_style ? 1 : 0); const bool conflict = sqlite3_step(stmt) == SQLITE_ROW; sqlite3_finalize(stmt); return conflict; } std::optional DatabaseManager::get_directory_categorization_style(const std::string& dir_path) const { if (!db) { return std::nullopt; } const char* sql = "SELECT categorization_style FROM file_categorization WHERE dir_path = ? LIMIT 1;"; sqlite3_stmt* stmt = nullptr; if (sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr) != SQLITE_OK) { db_log(spdlog::level::warn, "Failed to prepare cached style query: {}", sqlite3_errmsg(db)); return std::nullopt; } sqlite3_bind_text(stmt, 1, dir_path.c_str(), -1, SQLITE_TRANSIENT); std::optional result; if (sqlite3_step(stmt) == SQLITE_ROW) { // If the column exists but is NULL (older rows), treat as "false" (refined) to compare // against the user's current preference. result = (sqlite3_column_type(stmt, 0) != SQLITE_NULL) ? (sqlite3_column_int(stmt, 0) != 0) : false; } sqlite3_finalize(stmt); return result; } std::vector DatabaseManager::remove_empty_categorizations(const std::string& dir_path) { std::vector removed; if (!db) { return removed; } const char* sql = R"( SELECT file_name, file_type, IFNULL(category, ''), IFNULL(subcategory, ''), taxonomy_id FROM file_categorization WHERE dir_path = ? AND (category IS NULL OR TRIM(category) = '' OR subcategory IS NULL OR TRIM(subcategory) = '') AND (suggested_name IS NULL OR TRIM(suggested_name) = '') AND IFNULL(rename_only, 0) = 0; )"; sqlite3_stmt* stmt = nullptr; if (sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr) != SQLITE_OK) { db_log(spdlog::level::err, "Failed to prepare empty categorization query: {}", sqlite3_errmsg(db)); return removed; } if (sqlite3_bind_text(stmt, 1, dir_path.c_str(), -1, SQLITE_TRANSIENT) != SQLITE_OK) { db_log(spdlog::level::err, "Failed to bind directory path for empty categorization query: {}", sqlite3_errmsg(db)); sqlite3_finalize(stmt); return removed; } while (sqlite3_step(stmt) == SQLITE_ROW) { const char* name = reinterpret_cast(sqlite3_column_text(stmt, 0)); const char* type = reinterpret_cast(sqlite3_column_text(stmt, 1)); const char* category = reinterpret_cast(sqlite3_column_text(stmt, 2)); const char* subcategory = reinterpret_cast(sqlite3_column_text(stmt, 3)); std::string file_name = name ? name : ""; std::string type_str = type ? type : ""; FileType entry_type = (type_str == "D") ? FileType::Directory : FileType::File; int taxonomy_id = 0; if (sqlite3_column_type(stmt, 4) != SQLITE_NULL) { taxonomy_id = sqlite3_column_int(stmt, 4); } removed.push_back({dir_path, file_name, entry_type, category ? category : "", subcategory ? subcategory : "", taxonomy_id}); } sqlite3_finalize(stmt); for (const auto& entry : removed) { remove_file_categorization(entry.file_path, entry.file_name, entry.type); } return removed; } void DatabaseManager::increment_taxonomy_frequency(int taxonomy_id) { if (!db || taxonomy_id <= 0) return; const char *sql = "UPDATE category_taxonomy " "SET frequency = (SELECT COUNT(*) FROM file_categorization WHERE taxonomy_id = ?) " "WHERE id = ?;"; sqlite3_stmt *stmt = nullptr; if (sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr) != SQLITE_OK) { db_log(spdlog::level::err, "Failed to prepare frequency update: {}", sqlite3_errmsg(db)); return; } sqlite3_bind_int(stmt, 1, taxonomy_id); sqlite3_bind_int(stmt, 2, taxonomy_id); if (sqlite3_step(stmt) != SQLITE_DONE) { db_log(spdlog::level::err, "Failed to increment taxonomy frequency: {}", sqlite3_errmsg(db)); } sqlite3_finalize(stmt); } std::vector DatabaseManager::get_categorized_files(const std::string &directory_path) { std::vector categorized_files; if (!db) return categorized_files; const char *sql = "SELECT dir_path, file_name, file_type, category, subcategory, suggested_name, taxonomy_id, " "categorization_style, rename_only, rename_applied " "FROM file_categorization WHERE dir_path = ?;"; StatementPtr stmt = prepare_statement(db, sql); if (!stmt) { return categorized_files; } if (sqlite3_bind_text(stmt.get(), 1, directory_path.c_str(), -1, SQLITE_TRANSIENT) != SQLITE_OK) { db_log(spdlog::level::err, "Failed to bind directory_path: {}", sqlite3_errmsg(db)); return categorized_files; } while (sqlite3_step(stmt.get()) == SQLITE_ROW) { if (auto entry = build_categorized_entry(stmt.get())) { categorized_files.push_back(std::move(*entry)); } } return categorized_files; } std::vector DatabaseManager::get_categorized_files_recursive(const std::string& directory_path) { std::vector categorized_files; if (!db) { return categorized_files; } const char* sql = "SELECT dir_path, file_name, file_type, category, subcategory, suggested_name, taxonomy_id, " "categorization_style, rename_only, rename_applied " "FROM file_categorization " "WHERE dir_path = ? OR dir_path LIKE ? ESCAPE '\\';"; StatementPtr stmt = prepare_statement(db, sql); if (!stmt) { return categorized_files; } if (sqlite3_bind_text(stmt.get(), 1, directory_path.c_str(), -1, SQLITE_TRANSIENT) != SQLITE_OK) { db_log(spdlog::level::err, "Failed to bind directory_path: {}", sqlite3_errmsg(db)); return categorized_files; } const std::string pattern = build_recursive_dir_pattern(directory_path); if (sqlite3_bind_text(stmt.get(), 2, pattern.c_str(), -1, SQLITE_TRANSIENT) != SQLITE_OK) { db_log(spdlog::level::err, "Failed to bind recursive directory pattern: {}", sqlite3_errmsg(db)); return categorized_files; } while (sqlite3_step(stmt.get()) == SQLITE_ROW) { if (auto entry = build_categorized_entry(stmt.get())) { categorized_files.push_back(std::move(*entry)); } } return categorized_files; } std::optional DatabaseManager::get_categorized_file(const std::string& dir_path, const std::string& file_name, FileType file_type) { if (!db) { return std::nullopt; } const char *sql = "SELECT dir_path, file_name, file_type, category, subcategory, suggested_name, taxonomy_id, " "categorization_style, rename_only, rename_applied " "FROM file_categorization " "WHERE dir_path = ? AND file_name = ? AND file_type = ? " "LIMIT 1;"; StatementPtr stmt = prepare_statement(db, sql); if (!stmt) { return std::nullopt; } if (sqlite3_bind_text(stmt.get(), 1, dir_path.c_str(), -1, SQLITE_TRANSIENT) != SQLITE_OK) { return std::nullopt; } if (sqlite3_bind_text(stmt.get(), 2, file_name.c_str(), -1, SQLITE_TRANSIENT) != SQLITE_OK) { return std::nullopt; } const std::string type_str = (file_type == FileType::File) ? "F" : "D"; if (sqlite3_bind_text(stmt.get(), 3, type_str.c_str(), -1, SQLITE_TRANSIENT) != SQLITE_OK) { return std::nullopt; } if (sqlite3_step(stmt.get()) == SQLITE_ROW) { return build_categorized_entry(stmt.get()); } return std::nullopt; } std::vector DatabaseManager::get_categorization_from_db(const std::string& dir_path, const std::string& file_name, FileType file_type) { std::vector categorization; if (!db) return categorization; const char *sql = "SELECT category, subcategory FROM file_categorization " "WHERE dir_path = ? AND file_name = ? AND file_type = ?;"; sqlite3_stmt *stmtcat = nullptr; if (sqlite3_prepare_v2(db, sql, -1, &stmtcat, nullptr) != SQLITE_OK) { return categorization; } if (sqlite3_bind_text(stmtcat, 1, dir_path.c_str(), -1, SQLITE_TRANSIENT) != SQLITE_OK) { sqlite3_finalize(stmtcat); return categorization; } std::string file_type_str = (file_type == FileType::File) ? "F" : "D"; if (sqlite3_bind_text(stmtcat, 2, file_name.c_str(), -1, SQLITE_TRANSIENT) != SQLITE_OK) { sqlite3_finalize(stmtcat); return categorization; } if (sqlite3_bind_text(stmtcat, 3, file_type_str.c_str(), -1, SQLITE_TRANSIENT) != SQLITE_OK) { sqlite3_finalize(stmtcat); return categorization; } if (sqlite3_step(stmtcat) == SQLITE_ROW) { const char *category = reinterpret_cast(sqlite3_column_text(stmtcat, 0)); const char *subcategory = reinterpret_cast(sqlite3_column_text(stmtcat, 1)); categorization.emplace_back(category ? category : ""); categorization.emplace_back(subcategory ? subcategory : ""); } sqlite3_finalize(stmtcat); return categorization; } bool DatabaseManager::is_file_already_categorized(const std::string &file_name) { if (!db) return false; const char *sql = "SELECT 1 FROM file_categorization WHERE file_name = ? LIMIT 1;"; sqlite3_stmt *stmt = nullptr; if (sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr) != SQLITE_OK) { return false; } sqlite3_bind_text(stmt, 1, file_name.c_str(), -1, SQLITE_TRANSIENT); bool exists = sqlite3_step(stmt) == SQLITE_ROW; sqlite3_finalize(stmt); return exists; } std::vector DatabaseManager::get_dir_contents_from_db(const std::string &dir_path) { std::vector results; if (!db) return results; const char *sql = "SELECT file_name FROM file_categorization WHERE dir_path = ?;"; sqlite3_stmt *stmt = nullptr; if (sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr) != SQLITE_OK) { return results; } sqlite3_bind_text(stmt, 1, dir_path.c_str(), -1, SQLITE_TRANSIENT); while (sqlite3_step(stmt) == SQLITE_ROW) { const char *name = reinterpret_cast(sqlite3_column_text(stmt, 0)); results.emplace_back(name ? name : ""); } sqlite3_finalize(stmt); return results; } std::vector> DatabaseManager::get_taxonomy_snapshot( std::size_t max_entries, CategoryLanguage language) const { std::vector> snapshot; if (max_entries == 0) { max_entries = taxonomy_entries.size(); } snapshot.reserve(std::min(max_entries, taxonomy_entries.size())); for (const auto& entry : taxonomy_entries) { if (snapshot.size() >= max_entries) { break; } ResolvedCategory resolved{entry.id, entry.category, entry.subcategory}; const ResolvedCategory localized = localize_category(resolved, language); snapshot.emplace_back(localized.category, localized.subcategory); } return snapshot; } bool DatabaseManager::is_duplicate_category( const std::vector>& results, const std::pair& candidate) { return std::any_of(results.begin(), results.end(), [&candidate](const auto& existing) { return existing.first == candidate.first && existing.second == candidate.second; }); } std::optional> DatabaseManager::build_recent_category_candidate( const char* file_name_text, const char* category_text, const char* subcategory_text, const std::string& normalized_extension, bool has_extension) const { std::string file_name = file_name_text ? file_name_text : ""; if (file_name.empty()) { return std::nullopt; } const std::string candidate_extension = extract_extension_lower(file_name); if (has_extension) { if (candidate_extension != normalized_extension) { return std::nullopt; } } else if (!candidate_extension.empty()) { return std::nullopt; } std::string category = category_text ? category_text : ""; if (category.empty()) { return std::nullopt; } std::string subcategory = subcategory_text ? subcategory_text : ""; return std::make_pair(std::move(category), std::move(subcategory)); } std::vector> DatabaseManager::get_recent_categories_for_extension(const std::string& extension, FileType file_type, std::size_t limit) const { std::vector> results; if (!db || limit == 0) { return results; } sqlite3_stmt* stmt = nullptr; const char* sql = "SELECT file_name, category, subcategory FROM file_categorization " "WHERE file_type = ? ORDER BY timestamp DESC LIMIT ?"; if (sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr) != SQLITE_OK) { db_log(spdlog::level::warn, "Failed to prepare recent category lookup: {}", sqlite3_errmsg(db)); return results; } const std::string type_code(1, file_type == FileType::File ? 'F' : 'D'); sqlite3_bind_text(stmt, 1, type_code.c_str(), -1, SQLITE_TRANSIENT); const std::size_t fetch_limit = std::max(limit * 5, limit); sqlite3_bind_int(stmt, 2, static_cast(fetch_limit)); const std::string normalized_extension = to_lower_copy(extension); const bool has_extension = !normalized_extension.empty(); while (sqlite3_step(stmt) == SQLITE_ROW) { const char* file_name_text = reinterpret_cast(sqlite3_column_text(stmt, 0)); const char* category_text = reinterpret_cast(sqlite3_column_text(stmt, 1)); const char* subcategory_text = reinterpret_cast(sqlite3_column_text(stmt, 2)); const auto candidate = build_recent_category_candidate(file_name_text, category_text, subcategory_text, normalized_extension, has_extension); if (!candidate.has_value()) { continue; } if (is_duplicate_category(results, *candidate)) { continue; } results.push_back(*candidate); if (results.size() >= limit) { break; } } sqlite3_finalize(stmt); return results; } std::string DatabaseManager::get_cached_category(const std::string &file_name) { auto iter = cached_results.find(file_name); if (iter != cached_results.end()) { return iter->second; } return {}; } void DatabaseManager::load_cache() { cached_results.clear(); } bool DatabaseManager::file_exists_in_db(const std::string &file_name, const std::string &file_path) { if (!db) return false; const char *sql = "SELECT 1 FROM file_categorization WHERE file_name = ? AND dir_path = ? LIMIT 1;"; sqlite3_stmt *stmt = nullptr; if (sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr) != SQLITE_OK) { return false; } sqlite3_bind_text(stmt, 1, file_name.c_str(), -1, SQLITE_TRANSIENT); sqlite3_bind_text(stmt, 2, file_path.c_str(), -1, SQLITE_TRANSIENT); bool exists = sqlite3_step(stmt) == SQLITE_ROW; sqlite3_finalize(stmt); return exists; } ================================================ FILE: app/lib/DialogUtils.cpp ================================================ #include "DialogUtils.hpp" #include #include #include void DialogUtils::show_error_dialog(QWidget* parent, const std::string& message) { QMessageBox::critical(parent, QObject::tr("Error"), QString::fromStdString(message)); } ================================================ FILE: app/lib/DocumentTextAnalyzer.cpp ================================================ #include "DocumentTextAnalyzer.hpp" #include "ILLMClient.hpp" #include #include #include #if defined(AI_FILE_SORTER_USE_PDFIUM) #include "fpdf_doc.h" #include "fpdf_text.h" #include "fpdfview.h" #endif #if defined(AI_FILE_SORTER_USE_LIBZIP) #include #endif #if defined(AI_FILE_SORTER_USE_PUGIXML) #include #endif #if __has_include() #include #elif __has_include() #include #else #error "jsoncpp headers not found. Install jsoncpp development files." #endif #include #include #include #include #include #include #include #include #include #include #include namespace { constexpr size_t kDefaultMaxChars = 8000; constexpr int kDefaultMaxTokens = 256; constexpr size_t kMaxProcessOutput = 200000; std::string to_lower_copy(std::string value) { std::transform(value.begin(), value.end(), value.begin(), [](unsigned char ch) { return static_cast(std::tolower(ch)); }); return value; } std::string trim_copy(const std::string& value) { auto result = value; const auto not_space = [](unsigned char ch) { return !std::isspace(ch); }; result.erase(result.begin(), std::find_if(result.begin(), result.end(), not_space)); result.erase(std::find_if(result.rbegin(), result.rend(), not_space).base(), result.end()); return result; } std::string collapse_whitespace(const std::string& value) { std::string collapsed; collapsed.reserve(value.size()); bool last_space = false; for (unsigned char ch : value) { if (std::isspace(ch)) { if (!last_space) { collapsed.push_back(' '); last_space = true; } } else { collapsed.push_back(static_cast(ch)); last_space = false; } } return trim_copy(collapsed); } QString sanitize_utf8_text(const std::string& value) { QString cleaned = QString::fromUtf8(value.c_str()); cleaned.remove(QChar::ReplacementCharacter); return cleaned.normalized(QString::NormalizationForm_C); } std::vector split_words(const QString& value) { std::vector words; QString current; for (const QChar ch : value) { if (ch.isLetterOrNumber()) { current.append(ch.toLower()); } else if (!current.isEmpty()) { words.emplace_back(current.toUtf8().toStdString()); current.clear(); } } if (!current.isEmpty()) { words.emplace_back(current.toUtf8().toStdString()); } return words; } std::string strip_xml_tags(const std::string& xml) { std::string output; output.reserve(xml.size()); bool in_tag = false; for (char ch : xml) { if (ch == '<') { in_tag = true; continue; } if (ch == '>') { in_tag = false; continue; } if (!in_tag) { output.push_back(ch); } } return output; } void replace_all(std::string& value, std::string_view from, std::string_view to) { if (from.empty()) { return; } size_t pos = 0; while ((pos = value.find(from.data(), pos, from.size())) != std::string::npos) { value.replace(pos, from.size(), to.data(), to.size()); pos += to.size(); } } std::string decode_basic_entities(std::string value) { replace_all(value, "&", "&"); replace_all(value, "<", "<"); replace_all(value, ">", ">"); replace_all(value, """, "\""); replace_all(value, "'", "'"); return value; } #if defined(AI_FILE_SORTER_USE_PUGIXML) void append_node_text(const pugi::xml_node& node, std::string& out) { if (node.type() == pugi::node_pcdata || node.type() == pugi::node_cdata) { out.append(node.value()); out.push_back(' '); } for (const auto& child : node.children()) { append_node_text(child, out); } } #endif std::string extract_xml_text(const std::string& xml) { #if defined(AI_FILE_SORTER_USE_PUGIXML) pugi::xml_document doc; pugi::xml_parse_result result = doc.load_string(xml.c_str(), pugi::parse_default | pugi::parse_ws_pcdata); if (result) { std::string out; out.reserve(xml.size()); append_node_text(doc, out); return out; } #endif return strip_xml_tags(xml); } std::optional run_process(const QString& program, const QStringList& args, int timeout_ms) { QProcess process; process.start(program, args); if (!process.waitForStarted()) { return std::nullopt; } if (!process.waitForFinished(timeout_ms)) { process.kill(); process.waitForFinished(); return std::nullopt; } if (process.exitStatus() != QProcess::NormalExit || process.exitCode() != 0) { return std::nullopt; } const QByteArray output = process.readAllStandardOutput(); std::string result(output.constData(), static_cast(output.size())); if (result.size() > kMaxProcessOutput) { result.resize(kMaxProcessOutput); } return result; } std::optional find_executable(const QString& name) { const QString exe = QStandardPaths::findExecutable(name); if (exe.isEmpty()) { return std::nullopt; } return exe; } #if defined(AI_FILE_SORTER_USE_LIBZIP) std::optional extract_zip_member_libzip(const std::filesystem::path& path, std::initializer_list members) { int error_code = 0; zip_t* archive = zip_open(path.string().c_str(), ZIP_RDONLY, &error_code); if (!archive) { return std::nullopt; } for (const auto& member : members) { const QByteArray member_name = member.toUtf8(); zip_file_t* file = zip_fopen(archive, member_name.constData(), 0); if (!file) { continue; } std::string output; output.reserve(kMaxProcessOutput); std::array buffer{}; zip_int64_t read = 0; while ((read = zip_fread(file, buffer.data(), buffer.size())) > 0) { output.append(buffer.data(), static_cast(read)); if (output.size() >= kMaxProcessOutput) { output.resize(kMaxProcessOutput); break; } } zip_fclose(file); if (!output.empty()) { zip_close(archive); return output; } } zip_close(archive); return std::nullopt; } #endif std::optional extract_zip_member(const std::filesystem::path& path, std::initializer_list members, int timeout_ms) { #if defined(AI_FILE_SORTER_USE_LIBZIP) if (auto output = extract_zip_member_libzip(path, members)) { return output; } #endif const auto unzip = find_executable(QStringLiteral("unzip")); if (!unzip) { return std::nullopt; } const QString file_path = QString::fromStdString(path.string()); for (const auto& member : members) { if (auto output = run_process(*unzip, {QStringLiteral("-p"), file_path, member}, timeout_ms)) { if (!output->empty()) { return output; } } } return std::nullopt; } std::string read_file_prefix(const std::filesystem::path& path, size_t max_chars) { std::ifstream file(path, std::ios::binary); if (!file) { return {}; } std::string buffer; buffer.resize(max_chars); file.read(buffer.data(), static_cast(buffer.size())); buffer.resize(static_cast(file.gcount())); buffer.erase(std::remove(buffer.begin(), buffer.end(), '\0'), buffer.end()); return buffer; } std::string truncate_excerpt(const std::string& text, size_t max_chars) { if (text.size() <= max_chars) { return text; } const size_t head = max_chars * 3 / 4; const size_t tail = max_chars - head; return text.substr(0, head) + "\n...\n" + text.substr(text.size() - tail); } std::optional normalize_date(const std::string& input) { std::smatch match; static const std::regex kIsoDate(R"((\d{4})-(\d{2})-(\d{2}))"); if (std::regex_search(input, match, kIsoDate)) { return match.str(1) + "-" + match.str(2); } static const std::regex kPdfDate(R"(D:(\d{4})(\d{2})(\d{2}))"); if (std::regex_search(input, match, kPdfDate)) { return match.str(1) + "-" + match.str(2); } static const std::regex kCompact(R"(\b(\d{4})(\d{2})(\d{2})\b)"); if (std::regex_search(input, match, kCompact)) { return match.str(1) + "-" + match.str(2); } return std::nullopt; } std::optional extract_docx_date(const std::filesystem::path& path) { auto xml = extract_zip_member(path, {QStringLiteral("docProps/core.xml")}, 5000); if (!xml) { return std::nullopt; } static const std::regex kCreatedTag(R"(]*>([^<]+))"); std::smatch match; if (std::regex_search(*xml, match, kCreatedTag)) { return normalize_date(match.str(1)); } static const std::regex kAltCreatedTag(R"(]*>([^<]+))"); if (std::regex_search(*xml, match, kAltCreatedTag)) { return normalize_date(match.str(1)); } return std::nullopt; } std::optional extract_pdf_date(const std::filesystem::path& path) { const QString file_path = QString::fromStdString(path.string()); if (const auto pdfinfo = find_executable(QStringLiteral("pdfinfo"))) { if (auto output = run_process(*pdfinfo, {file_path}, 4000)) { std::istringstream iss(*output); std::string line; while (std::getline(iss, line)) { if (line.rfind("CreationDate", 0) == 0 || line.rfind("Creation Date", 0) == 0) { if (auto parsed = normalize_date(line)) { return parsed; } } } } } std::string raw = read_file_prefix(path, 200000); if (raw.empty()) { return std::nullopt; } static const std::regex kCreation(R"(/CreationDate\s*\(([^\)]*)\))"); std::smatch match; if (std::regex_search(raw, match, kCreation)) { return normalize_date(match.str(1)); } return std::nullopt; } #if defined(AI_FILE_SORTER_USE_PDFIUM) class PdfiumLibraryGuard { public: PdfiumLibraryGuard() { FPDF_InitLibrary(); } ~PdfiumLibraryGuard() { FPDF_DestroyLibrary(); } }; PdfiumLibraryGuard& pdfium_library() { static PdfiumLibraryGuard guard; return guard; } std::string extract_pdf_text_pdfium(const std::filesystem::path& path, size_t max_chars) { pdfium_library(); const std::string pdf_path = path.string(); FPDF_DOCUMENT doc = FPDF_LoadDocument(pdf_path.c_str(), nullptr); if (!doc) { return {}; } const int page_count = FPDF_GetPageCount(doc); std::string result; for (int i = 0; i < page_count && result.size() < max_chars; ++i) { FPDF_PAGE page = FPDF_LoadPage(doc, i); if (!page) { continue; } FPDF_TEXTPAGE text_page = FPDFText_LoadPage(page); if (!text_page) { FPDF_ClosePage(page); continue; } const int total_chars = FPDFText_CountChars(text_page); const int chunk = 4096; int offset = 0; while (offset < total_chars && result.size() < max_chars) { const int take = std::min(chunk, total_chars - offset); std::vector buffer(static_cast(take + 1)); const int extracted = FPDFText_GetText(text_page, offset, take, buffer.data()); if (extracted <= 0) { break; } const int count = std::max(0, extracted - 1); QString text = QString::fromUtf16(reinterpret_cast(buffer.data()), count); result.append(text.toStdString()); if (result.size() >= max_chars) { result.resize(max_chars); break; } offset += take; } FPDFText_ClosePage(text_page); FPDF_ClosePage(page); } FPDF_CloseDocument(doc); return result; } #endif const std::unordered_set kDocumentExtensions = { ".txt", ".md", ".markdown", ".rtf", ".csv", ".tsv", ".log", ".json", ".xml", ".yml", ".yaml", ".ini", ".cfg", ".conf", ".html", ".htm", ".tex", ".rst", ".pdf", ".docx", ".xlsx", ".pptx", ".odt", ".ods", ".odp" }; const std::unordered_set kTextExtensions = { ".txt", ".md", ".markdown", ".rtf", ".csv", ".tsv", ".log", ".json", ".xml", ".yml", ".yaml", ".ini", ".cfg", ".conf", ".html", ".htm", ".tex", ".rst" }; const std::unordered_set kStopwords = { "a", "an", "and", "are", "as", "at", "based", "be", "by", "category", "chapter", "description", "details", "document", "documents", "file", "files", "filename", "for", "from", "has", "in", "is", "it", "of", "on", "only", "page", "pages", "pdf", "doc", "docx", "rtf", "text", "this", "to", "txt", "with", "report", "notes", "note", "summary", "overview", "information", "data", "untitled", "ppt", "pptx", "xls", "xlsx", "odt", "ods", "odp", "presentation", "slides", "spreadsheet" }; struct ParsedAnalysis { std::string summary; std::string filename; }; std::optional parse_analysis_json(const std::string& response) { Json::CharReaderBuilder reader; Json::Value root; std::string errors; auto try_parse = [&](const std::string& payload) -> bool { std::istringstream stream(payload); return Json::parseFromStream(reader, stream, &root, &errors); }; if (!try_parse(response)) { const auto first = response.find('{'); const auto last = response.rfind('}'); if (first == std::string::npos || last == std::string::npos || last <= first) { return std::nullopt; } if (!try_parse(response.substr(first, last - first + 1))) { return std::nullopt; } } if (!root.isObject()) { return std::nullopt; } ParsedAnalysis parsed; if (root.isMember("summary")) { parsed.summary = root["summary"].asString(); } else if (root.isMember("description")) { parsed.summary = root["description"].asString(); } if (root.isMember("filename")) { parsed.filename = root["filename"].asString(); } else if (root.isMember("name")) { parsed.filename = root["name"].asString(); } else if (root.isMember("suggested_name")) { parsed.filename = root["suggested_name"].asString(); } return parsed; } std::string first_words(const std::string& text, size_t max_words) { std::istringstream iss(text); std::string word; std::string result; size_t count = 0; while (iss >> word) { if (!result.empty()) { result.push_back(' '); } result += word; if (++count >= max_words) { break; } } return result; } } // namespace DocumentTextAnalyzer::DocumentTextAnalyzer() : DocumentTextAnalyzer(Settings{}) {} DocumentTextAnalyzer::DocumentTextAnalyzer(Settings settings) : settings_(settings) { if (settings_.max_characters == 0) { settings_.max_characters = kDefaultMaxChars; } if (settings_.max_tokens <= 0) { settings_.max_tokens = kDefaultMaxTokens; } if (settings_.max_filename_words == 0) { settings_.max_filename_words = 3; } if (settings_.max_filename_length == 0) { settings_.max_filename_length = 50; } } DocumentAnalysisResult DocumentTextAnalyzer::analyze(const std::filesystem::path& document_path, ILLMClient& llm) const { DocumentAnalysisResult result; const std::string raw_text = extract_text(document_path); if (raw_text.empty()) { throw std::runtime_error("No extractable text"); } const std::string excerpt = truncate_excerpt(raw_text, settings_.max_characters); const std::string prompt = build_prompt(excerpt, document_path.filename().string()); const std::string response = llm.complete_prompt(prompt, settings_.max_tokens); std::string summary; std::string filename; if (auto parsed = parse_analysis_json(response)) { summary = trim(parsed->summary); filename = trim(parsed->filename); } if (summary.empty()) { summary = trim(first_words(excerpt, 120)); } std::string sanitized = sanitize_filename(filename, settings_.max_filename_words, settings_.max_filename_length); if (sanitized.empty()) { sanitized = sanitize_filename(summary, settings_.max_filename_words, settings_.max_filename_length); } if (sanitized.empty()) { sanitized = "document_" + slugify(document_path.stem().string()); } result.summary = summary; result.suggested_name = normalize_filename(sanitized, document_path); return result; } bool DocumentTextAnalyzer::is_supported_document(const std::filesystem::path& path) { if (!path.has_extension()) { return false; } const std::string ext = to_lower_copy(path.extension().string()); return kDocumentExtensions.find(ext) != kDocumentExtensions.end(); } std::optional DocumentTextAnalyzer::extract_creation_date(const std::filesystem::path& path) { if (!path.has_extension()) { return std::nullopt; } const std::string ext = to_lower_copy(path.extension().string()); if (ext == ".pdf") { return extract_pdf_date(path); } if (ext == ".docx") { return extract_docx_date(path); } return std::nullopt; } std::string DocumentTextAnalyzer::extract_text(const std::filesystem::path& path) const { if (!path.has_extension()) { return {}; } const std::string ext = to_lower_copy(path.extension().string()); if (kTextExtensions.find(ext) != kTextExtensions.end()) { std::string text = read_file_prefix(path, settings_.max_characters); return collapse_whitespace(text); } if (ext == ".pdf") { #if defined(AI_FILE_SORTER_USE_PDFIUM) if (auto output = extract_pdf_text_pdfium(path, settings_.max_characters); !output.empty()) { return collapse_whitespace(output); } #endif const auto pdftotext = find_executable(QStringLiteral("pdftotext")); if (!pdftotext) { return {}; } const QString file_path = QString::fromStdString(path.string()); auto output = run_process(*pdftotext, {QStringLiteral("-layout"), QStringLiteral("-q"), file_path, QStringLiteral("-")}, 15000); if (!output) { return {}; } if (output->size() > settings_.max_characters) { output->resize(settings_.max_characters); } return collapse_whitespace(*output); } if (ext == ".docx") { auto xml = extract_zip_member(path, {QStringLiteral("word/document.xml")}, 7000); if (!xml) { return {}; } std::string text = extract_xml_text(*xml); text = decode_basic_entities(text); if (text.size() > settings_.max_characters) { text.resize(settings_.max_characters); } return collapse_whitespace(text); } if (ext == ".xlsx") { auto xml = extract_zip_member( path, {QStringLiteral("xl/sharedStrings.xml"), QStringLiteral("xl/worksheets/sheet1.xml"), QStringLiteral("xl/worksheets/sheet2.xml")}, 7000); if (!xml) { return {}; } std::string text = extract_xml_text(*xml); text = decode_basic_entities(text); if (text.size() > settings_.max_characters) { text.resize(settings_.max_characters); } return collapse_whitespace(text); } if (ext == ".pptx") { auto xml = extract_zip_member( path, {QStringLiteral("ppt/slides/slide1.xml"), QStringLiteral("ppt/slides/slide2.xml")}, 7000); if (!xml) { return {}; } std::string text = extract_xml_text(*xml); text = decode_basic_entities(text); if (text.size() > settings_.max_characters) { text.resize(settings_.max_characters); } return collapse_whitespace(text); } if (ext == ".odt" || ext == ".ods" || ext == ".odp") { auto xml = extract_zip_member(path, {QStringLiteral("content.xml")}, 7000); if (!xml) { return {}; } std::string text = extract_xml_text(*xml); text = decode_basic_entities(text); if (text.size() > settings_.max_characters) { text.resize(settings_.max_characters); } return collapse_whitespace(text); } return {}; } std::string DocumentTextAnalyzer::build_prompt(const std::string& excerpt, const std::string& file_name) const { std::ostringstream oss; oss << "Summarize the document excerpt below in at most 120 words. " << "Then propose a short descriptive filename (max 3 words, nouns only). " << "Use underscores between words, avoid generic words like 'document', 'file', or extensions. " << "Return JSON only in the format: {\"summary\":\"...\",\"filename\":\"...\"}.\n\n"; oss << "Document filename: " << file_name << "\n"; oss << "Document excerpt:\n" << excerpt << "\n\n"; oss << "JSON:"; return oss.str(); } std::string DocumentTextAnalyzer::sanitize_filename(const std::string& value, size_t max_words, size_t max_length) const { QString cleaned = sanitize_utf8_text(value).trimmed(); const QString prefix = QStringLiteral("filename:"); if (cleaned.startsWith(prefix, Qt::CaseInsensitive)) { cleaned = cleaned.mid(prefix.size()).trimmed(); } const int newline = cleaned.indexOf('\n'); if (newline != -1) { cleaned = cleaned.left(newline); } const int carriage = cleaned.indexOf('\r'); if (carriage != -1) { cleaned = cleaned.left(carriage); } if (cleaned.size() >= 2) { const QChar first = cleaned.front(); const QChar last = cleaned.back(); if ((first == '"' && last == '"') || (first == '\'' && last == '\'')) { cleaned = cleaned.mid(1, cleaned.size() - 2); } } auto words = split_words(cleaned); std::vector filtered; filtered.reserve(words.size()); std::unordered_set seen; for (const auto& word : words) { if (word.empty()) { continue; } if (kStopwords.find(word) != kStopwords.end()) { continue; } if (seen.insert(word).second) { filtered.push_back(word); } if (filtered.size() >= max_words) { break; } } if (filtered.empty()) { return std::string(); } QString joined; for (size_t i = 0; i < filtered.size(); ++i) { if (i > 0) { joined.append('_'); } joined.append(QString::fromUtf8(filtered[i].c_str())); } if (joined.size() > static_cast(max_length)) { joined = joined.left(static_cast(max_length)); } while (!joined.isEmpty() && joined.endsWith('_')) { joined.chop(1); } return joined.toUtf8().toStdString(); } std::string DocumentTextAnalyzer::trim(std::string value) { return trim_copy(value); } std::string DocumentTextAnalyzer::slugify(const std::string& value) { const QString input = sanitize_utf8_text(value); QString slug; slug.reserve(input.size()); bool last_sep = false; for (const QChar ch : input) { if (ch.isLetterOrNumber()) { slug.append(ch.toLower()); last_sep = false; } else if (!last_sep && !slug.isEmpty()) { slug.append('_'); last_sep = true; } } if (!slug.isEmpty() && slug.endsWith('_')) { slug.chop(1); } if (slug.isEmpty()) { slug = QStringLiteral("document"); } return slug.toUtf8().toStdString(); } std::string DocumentTextAnalyzer::normalize_filename(const std::string& base, const std::filesystem::path& original_path) { const std::string ext = original_path.extension().string(); if (base.empty()) { return original_path.filename().string(); } return ext.empty() ? base : base + ext; } ================================================ FILE: app/lib/DryRunPreviewDialog.cpp ================================================ #include "DryRunPreviewDialog.hpp" #include #include #include #include #include DryRunPreviewDialog::DryRunPreviewDialog(const std::vector& entries, QWidget* parent) : QDialog(parent) { setWindowTitle(tr("Dry run preview")); resize(900, 480); setup_ui(entries); } void DryRunPreviewDialog::setup_ui(const std::vector& entries) { auto* layout = new QVBoxLayout(this); table_ = new QTableWidget(this); table_->setColumnCount(3); table_->setHorizontalHeaderLabels(QStringList{tr("From"), tr(""), tr("To")}); table_->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch); table_->horizontalHeader()->setSectionResizeMode(1, QHeaderView::ResizeToContents); table_->horizontalHeader()->setSectionResizeMode(2, QHeaderView::Stretch); table_->verticalHeader()->setVisible(false); table_->setEditTriggers(QAbstractItemView::NoEditTriggers); table_->setSelectionMode(QAbstractItemView::NoSelection); table_->setAlternatingRowColors(true); table_->setRowCount(static_cast(entries.size())); int row = 0; for (const auto& entry : entries) { auto* from_item = new QTableWidgetItem(QString::fromStdString(entry.from_label)); from_item->setToolTip(QString::fromStdString(entry.source_tooltip)); auto* arrow_item = new QTableWidgetItem(QStringLiteral("→")); auto* to_item = new QTableWidgetItem(QString::fromStdString(entry.to_label)); to_item->setToolTip(QString::fromStdString(entry.destination_tooltip)); table_->setItem(row, 0, from_item); table_->setItem(row, 1, arrow_item); table_->setItem(row, 2, to_item); ++row; } layout->addWidget(table_, 1); auto* button_layout = new QHBoxLayout(); button_layout->addStretch(1); auto* close_button = new QPushButton(tr("Close"), this); connect(close_button, &QPushButton::clicked, this, &QDialog::accept); button_layout->addWidget(close_button); layout->addLayout(button_layout); } ================================================ FILE: app/lib/EmbeddedEnv.cpp ================================================ #include "EmbeddedEnv.hpp" #include "Logger.hpp" #include #include #include #include #include #include #include EmbeddedEnv::EmbeddedEnv(const std::string& resource_path) : resource_path_(resource_path) { } void EmbeddedEnv::load_env() { auto logger = Logger::get_logger("core_logger"); if (logger) { // logger->debug("Loading embedded environment from {}", resource_path_); } std::string env_content = extract_env_content(); parse_env(env_content); if (logger) { // logger->info("Embedded environment loaded from {}", resource_path_); } } std::string EmbeddedEnv::extract_env_content() { QFile file(QString::fromStdString(resource_path_)); if (!file.open(QIODevice::ReadOnly)) { const std::string error_message = "Failed to load embedded .env file from resource: " + resource_path_; if (auto logger = Logger::get_logger("core_logger")) { logger->error("{}", error_message); } throw std::runtime_error(error_message); } const QByteArray data = file.readAll(); return std::string(data.constData(), static_cast(data.size())); } void EmbeddedEnv::parse_env(const std::string& env_content) { std::istringstream stream(env_content); std::string line; size_t loaded_entries = 0; while (std::getline(stream, line)) { if (line.empty() || line[0] == '#') { continue; } std::size_t equal_pos = line.find('='); if (equal_pos == std::string::npos) { std::string message = "Invalid .env line: " + line; if (auto logger = Logger::get_logger("core_logger")) { logger->warn("{}", message); } throw std::runtime_error(message); } std::string key = line.substr(0, equal_pos); std::string value = line.substr(equal_pos + 1); key = trim(key); value = trim(value); // Set the environment variable #if defined(_WIN32) _putenv_s(key.c_str(), value.c_str()); // Windows-specific #else setenv(key.c_str(), value.c_str(), 1); // POSIX-compliant #endif ++loaded_entries; if (auto logger = Logger::get_logger("core_logger")) { // logger->debug("Loaded env key '{}'", key); } } if (auto logger = Logger::get_logger("core_logger")) { logger->info("Loaded {} environment variable(s) from embedded resource", loaded_entries); } } std::string EmbeddedEnv::trim(const std::string& str) { const char* whitespace = " \t\n\r\f\v"; std::size_t start = str.find_first_not_of(whitespace); std::size_t end = str.find_last_not_of(whitespace); if (start == std::string::npos || end == std::string::npos) { return ""; } return str.substr(start, end - start + 1); } ================================================ FILE: app/lib/FileScanner.cpp ================================================ #include "FileScanner.hpp" #include "Logger.hpp" #include "Utils.hpp" #include #include #include #include #include #ifdef _WIN32 #include #endif namespace fs = std::filesystem; namespace { constexpr fs::directory_options kIteratorOptions = fs::directory_options::skip_permission_denied; } // namespace struct FileScanner::ScanContext { bool include_files{false}; bool include_directories{false}; bool include_hidden{false}; std::shared_ptr logger; }; std::vector FileScanner::get_directory_entries(const std::string &directory_path, FileScanOptions options) { std::vector file_paths_and_names; auto logger = Logger::get_logger("core_logger"); if (logger) { logger->debug("Scanning directory '{}' with options mask {}", directory_path, static_cast(options)); } ScanContext context; context.include_files = has_flag(options, FileScanOptions::Files); context.include_directories = has_flag(options, FileScanOptions::Directories); context.include_hidden = has_flag(options, FileScanOptions::HiddenFiles); context.logger = logger; const bool recursive = has_flag(options, FileScanOptions::Recursive); try { const fs::path scan_path = Utils::utf8_to_path(directory_path); if (!recursive) { scan_non_recursive(scan_path, context, file_paths_and_names); } else { scan_recursive(scan_path, context, file_paths_and_names); } } catch (const fs::filesystem_error& ex) { if (logger) { logger->warn("Error while scanning '{}': {}", directory_path, ex.what()); } throw; } if (logger) { logger->info("Directory scan complete for '{}': {} item(s) queued", directory_path, file_paths_and_names.size()); } return file_paths_and_names; } void FileScanner::scan_non_recursive(const fs::path& scan_path, const ScanContext& context, std::vector& results) { std::error_code ec; fs::directory_iterator it(scan_path, kIteratorOptions, ec); if (ec) { throw fs::filesystem_error("directory_iterator", scan_path, ec); } const fs::directory_iterator end; while (it != end) { fs::directory_entry entry = *it; std::error_code increment_ec; it.increment(increment_ec); if (auto entry_info = build_entry(entry, context)) { results.push_back(std::move(*entry_info)); } if (increment_ec) { log_scan_warning(context, scan_path, increment_ec, "Stopping scan of directory after filesystem error"); break; } } } void FileScanner::scan_recursive(const fs::path& scan_path, const ScanContext& context, std::vector& results) { std::vector pending_dirs; pending_dirs.push_back(scan_path); while (!pending_dirs.empty()) { const fs::path current_dir = pending_dirs.back(); pending_dirs.pop_back(); std::error_code open_ec; fs::directory_iterator it(current_dir, kIteratorOptions, open_ec); if (open_ec) { if (current_dir == scan_path) { throw fs::filesystem_error("directory_iterator", current_dir, open_ec); } log_scan_warning(context, current_dir, open_ec, "Skipping directory after filesystem error"); continue; } const fs::directory_iterator end; while (it != end) { fs::directory_entry entry = *it; const fs::path entry_path = entry.path(); const std::string full_path = Utils::path_to_utf8(entry_path); const std::string file_name = Utils::path_to_utf8(entry_path.filename()); std::error_code dir_ec; const bool is_directory = entry.is_directory(dir_ec); if (dir_ec) { log_scan_warning(context, entry_path, dir_ec, "Skipping entry after filesystem error"); } else { const bool bundle = is_file_bundle(entry_path, is_directory); const bool skip_entry = should_skip_entry(entry_path, file_name, context, full_path); if (!skip_entry) { if (auto type = classify_entry(entry, bundle, is_directory, context)) { results.push_back(FileEntry{full_path, file_name, *type}); } } if (is_directory && !bundle && !skip_entry) { pending_dirs.push_back(entry_path); } } std::error_code increment_ec; it.increment(increment_ec); if (increment_ec) { log_scan_warning(context, current_dir, increment_ec, "Stopping scan of directory after filesystem error"); break; } } } } void FileScanner::log_scan_warning(const ScanContext& context, const fs::path& path, const std::error_code& error, const char* action) const { if (!context.logger) { return; } context.logger->warn("{} '{}': {}", action, Utils::path_to_utf8(path), error.message()); } bool FileScanner::is_file_hidden(const fs::path &path) const { #ifdef _WIN32 DWORD attrs = GetFileAttributesW(path.c_str()); return (attrs != INVALID_FILE_ATTRIBUTES) && (attrs & FILE_ATTRIBUTE_HIDDEN); #else return path.filename().string().starts_with("."); #endif } bool FileScanner::is_junk_file(const std::string& name) const { static const std::unordered_set junk = { ".DS_Store", "Thumbs.db", "desktop.ini" }; return junk.contains(name); } bool FileScanner::is_file_bundle(const fs::path& path, bool is_directory) const { static const std::unordered_set bundle_extensions = { ".app", ".utm", ".vmwarevm", ".pvm", ".vbox", ".pkg", ".mpkg", ".prefPane", ".plugin", ".framework", ".kext", ".qlgenerator", ".mdimporter", ".wdgt", ".scptd", ".nib", ".xib" }; if (!is_directory) { return false; } std::string ext = Utils::path_to_utf8(path.extension()); std::transform(ext.begin(), ext.end(), ext.begin(), ::tolower); return bundle_extensions.contains(ext); } std::optional FileScanner::build_entry(const fs::directory_entry& entry, const ScanContext& context) { const fs::path& entry_path = entry.path(); std::string full_path = Utils::path_to_utf8(entry_path); std::string file_name = Utils::path_to_utf8(entry_path.filename()); if (should_skip_entry(entry_path, file_name, context, full_path)) { return std::nullopt; } std::error_code dir_ec; const bool is_directory = entry.is_directory(dir_ec); if (dir_ec) { log_scan_warning(context, entry_path, dir_ec, "Skipping entry after filesystem error"); return std::nullopt; } const bool bundle = is_file_bundle(entry_path, is_directory); if (auto type = classify_entry(entry, bundle, is_directory, context)) { return FileEntry{std::move(full_path), std::move(file_name), *type}; } return std::nullopt; } bool FileScanner::should_skip_entry(const fs::path& entry_path, const std::string& file_name, const ScanContext& context, const std::string& full_path) const { if (is_junk_file(file_name)) { return true; } if (is_file_hidden(entry_path) && !context.include_hidden) { if (context.logger) { context.logger->trace("Skipping hidden entry '{}'", full_path); } return true; } return false; } std::optional FileScanner::classify_entry(const fs::directory_entry& entry, bool bundle, bool is_directory, const ScanContext& context) const { std::error_code regular_file_ec; const bool is_regular_file = entry.is_regular_file(regular_file_ec); if (regular_file_ec) { log_scan_warning(context, entry.path(), regular_file_ec, "Skipping entry after filesystem error"); return std::nullopt; } const bool is_file = bundle || is_regular_file; if (context.include_files && is_file) { return FileType::File; } if (context.include_directories && !bundle && is_directory) { return FileType::Directory; } return std::nullopt; } ================================================ FILE: app/lib/GeminiClient.cpp ================================================ #include "GeminiClient.hpp" #include "Logger.hpp" #include "LLMErrors.hpp" #include "Utils.hpp" #include #if __has_include() #include #elif __has_include() #include #else #error "jsoncpp headers not found. Install jsoncpp development files." #endif #include #include #include #include #include #include #include #include namespace { size_t WriteCallback(void* contents, size_t size, size_t nmemb, std::string* response) { const size_t total_size = size * nmemb; response->append(static_cast(contents), total_size); return total_size; } std::string escape_json(const std::string& input) { std::string out; out.reserve(input.size() * 2); for (char c : input) { switch (c) { case '"': out += "\\\""; break; case '\\': out += "\\\\"; break; case '\n': out += "\\n"; break; case '\r': out += "\\r"; break; case '\t': out += "\\t"; break; default: out += c; } } return out; } struct CurlRequest { CURL* handle{nullptr}; curl_slist* headers{nullptr}; CurlRequest() = default; CurlRequest(const CurlRequest&) = delete; CurlRequest& operator=(const CurlRequest&) = delete; CurlRequest(CurlRequest&& other) noexcept : handle(other.handle), headers(other.headers) { other.handle = nullptr; other.headers = nullptr; } CurlRequest& operator=(CurlRequest&& other) noexcept { if (this != &other) { cleanup(); handle = other.handle; headers = other.headers; other.handle = nullptr; other.headers = nullptr; } return *this; } ~CurlRequest() { cleanup(); } private: void cleanup() { if (handle) { curl_easy_cleanup(handle); handle = nullptr; } if (headers) { curl_slist_free_all(headers); headers = nullptr; } } }; CurlRequest create_curl_request(const std::shared_ptr& logger) { CurlRequest request; request.handle = curl_easy_init(); if (!request.handle) { if (logger) { logger->critical("Failed to initialize cURL handle for Gemini request"); } throw std::runtime_error("Initialization Error: Failed to initialize cURL."); } #ifdef _WIN32 try { const auto cert_path = Utils::ensure_ca_bundle(); curl_easy_setopt(request.handle, CURLOPT_CAINFO, cert_path.string().c_str()); } catch (const std::exception& ex) { throw std::runtime_error(std::string("Failed to stage CA bundle: ") + ex.what()); } #endif return request; } void configure_request_payload(CurlRequest& request, const std::string& api_url, const std::string& payload, std::string& response_buffer) { curl_easy_setopt(request.handle, CURLOPT_URL, api_url.c_str()); curl_easy_setopt(request.handle, CURLOPT_POST, 1L); curl_easy_setopt(request.handle, CURLOPT_TIMEOUT, 5L); request.headers = curl_slist_append(request.headers, "Content-Type: application/json"); curl_easy_setopt(request.handle, CURLOPT_HTTPHEADER, request.headers); curl_easy_setopt(request.handle, CURLOPT_POSTFIELDS, payload.c_str()); curl_easy_setopt(request.handle, CURLOPT_WRITEFUNCTION, WriteCallback); curl_easy_setopt(request.handle, CURLOPT_WRITEDATA, &response_buffer); } long perform_request(CurlRequest& request, const std::shared_ptr& logger) { const CURLcode res = curl_easy_perform(request.handle); if (res != CURLE_OK) { if (logger) { logger->error("cURL request failed: {}", curl_easy_strerror(res)); } throw std::runtime_error("Network Error: " + std::string(curl_easy_strerror(res))); } long http_code = 0; curl_easy_getinfo(request.handle, CURLINFO_RESPONSE_CODE, &http_code); return http_code; } std::string parse_text_response(const std::string& payload, long http_code, const std::shared_ptr& logger) { Json::CharReaderBuilder reader_builder; Json::Value root; std::istringstream response_stream(payload); std::string errors; if (!Json::parseFromStream(reader_builder, response_stream, &root, &errors)) { if (logger) { logger->error("Failed to parse JSON response: {}", errors); } throw std::runtime_error("Response Error: Failed to parse JSON response. " + errors); } if (http_code == 401) { throw std::runtime_error("Authentication Error: Invalid or missing Gemini API key."); } if (http_code == 403) { throw std::runtime_error("Authorization Error: Gemini API key does not have sufficient permissions."); } if (http_code >= 400) { const auto& error_obj = root["error"]; const std::string message = error_obj.isObject() ? error_obj["message"].asString() : std::string(); const std::string status = error_obj.isObject() ? error_obj["status"].asString() : std::string(); if (status == "RESOURCE_EXHAUSTED") { int retry_secs = 0; if (!message.empty()) { std::regex retry_regex(R"(retry in ([0-9]+(?:\.[0-9]+)?)s)", std::regex::icase); std::smatch match; if (std::regex_search(message, match, retry_regex) && match.size() > 1) { try { retry_secs = static_cast(std::ceil(std::stod(match[1].str()))); } catch (...) { retry_secs = 0; } } } throw BackoffError(message.empty() ? "Gemini quota reached" : "Gemini quota reached: " + message, retry_secs); } std::ostringstream oss; oss << "Gemini API error"; if (!status.empty()) { oss << " (" << status << ")"; } if (!message.empty()) { oss << ": " << message; } else { oss << " (HTTP " << http_code << ")"; } throw std::runtime_error(oss.str()); } const auto& candidates = root["candidates"]; if (!candidates.isArray() || candidates.empty()) { throw std::runtime_error("Response Error: Gemini response contained no candidates."); } const auto& parts = candidates[0]["content"]["parts"]; if (!parts.isArray() || parts.empty()) { throw std::runtime_error("Response Error: Gemini response missing content parts."); } return parts[0]["text"].asString(); } } // namespace GeminiClient::GeminiClient(std::string api_key, std::string model) : api_key_(std::move(api_key)), model_(std::move(model)) { } void GeminiClient::set_prompt_logging_enabled(bool enabled) { prompt_logging_enabled_ = enabled; } std::string GeminiClient::send_api_request(const std::string& json_payload) { if (api_key_.empty()) { throw std::runtime_error("Missing Gemini API key."); } const std::string model_path = effective_model().starts_with("models/") ? effective_model() : "models/" + effective_model(); const std::vector api_versions = {"v1", "v1beta"}; std::string last_error; for (size_t i = 0; i < api_versions.size(); ++i) { std::string response_string; const std::string base_url = "https://generativelanguage.googleapis.com/" + api_versions[i] + "/" + model_path + ":generateContent"; const std::string api_url = base_url + "?key=" + api_key_; auto logger = Logger::get_logger("core_logger"); if (logger) { logger->debug("Dispatching remote LLM request to {}", base_url); } try { CurlRequest request = create_curl_request(logger); configure_request_payload(request, api_url, json_payload, response_string); const long http_code = perform_request(request, logger); if (http_code == 404 && i + 1 < api_versions.size()) { // Fallback to next version (e.g., v1beta) on 404. last_error = "HTTP 404 on " + api_versions[i]; continue; } return parse_text_response(response_string, http_code, logger); } catch (const std::exception& ex) { last_error = ex.what(); if (i + 1 < api_versions.size()) { continue; } throw; } } throw std::runtime_error(last_error.empty() ? "Gemini request failed" : last_error); } std::string GeminiClient::effective_model() const { return model_.empty() ? "gemini-2.5-flash-lite" : model_; } std::string GeminiClient::categorize_file(const std::string& file_name, const std::string& file_path, FileType file_type, const std::string& consistency_context) { if (auto logger = Logger::get_logger("core_logger")) { if (!file_path.empty()) { logger->debug("Requesting Gemini categorization for '{}' ({}) at '{}'", file_name, to_string(file_type), file_path); } else { logger->debug("Requesting Gemini categorization for '{}' ({})", file_name, to_string(file_type)); } } std::string json_payload = make_categorization_payload(file_name, file_path, file_type, consistency_context); if (prompt_logging_enabled_ && !last_prompt_.empty()) { std::cout << "\n[DEV][PROMPT] Categorization request\n" << last_prompt_ << "\n"; } std::string category = send_api_request(json_payload); if (prompt_logging_enabled_) { std::cout << "[DEV][RESPONSE] Categorization reply\n" << category << "\n"; } return category; } std::string GeminiClient::make_categorization_payload(const std::string& file_name, const std::string& file_path, FileType file_type, const std::string& consistency_context) { std::string prompt; std::string sanitized_path = file_path; if (!sanitized_path.empty()) { prompt = "Categorize the item with full path: " + sanitized_path + "\n"; prompt += "File name: " + file_name; } else { prompt = "Categorize file: " + file_name; } if (file_type == FileType::Directory) { if (!sanitized_path.empty()) { prompt = "Categorize the directory with full path: " + sanitized_path + "\nDirectory name: " + file_name; } else { prompt = "Categorize directory: " + file_name; } } if (!consistency_context.empty()) { prompt += "\n\n" + consistency_context; } last_prompt_ = prompt; const std::string system_prompt = "You are a file categorization assistant. If it's an installer, describe the type of software it installs. " "Consider the filename, extension, and any directory context provided. Always reply with one line in the " "format
: . Main category must be broad (one or two words, plural). Subcategory " "must be specific, relevant, and must not repeat the main category."; std::ostringstream payload; const std::string merged_prompt = system_prompt + "\n\n" + prompt; payload << "{"; payload << "\"contents\":["; payload << "{\"role\":\"user\",\"parts\":[{\"text\":\"" << escape_json(merged_prompt) << "\"}]}"; payload << "]"; payload << "}"; return payload.str(); } std::string GeminiClient::make_generic_payload(const std::string& system_prompt, const std::string& user_prompt, int max_tokens) const { const std::string merged_prompt = system_prompt + "\n\n" + user_prompt; std::ostringstream payload; payload << "{"; payload << "\"contents\":["; payload << "{\"role\":\"user\",\"parts\":[{\"text\":\"" << escape_json(merged_prompt) << "\"}]}"; payload << "]"; if (max_tokens > 0) { payload << ",\"generationConfig\":{\"maxOutputTokens\":" << max_tokens << "}"; } payload << "}"; return payload.str(); } std::string GeminiClient::complete_prompt(const std::string& prompt, int max_tokens) { static const std::string kSystem = "You are a precise assistant that returns well-formed JSON responses."; std::string json_payload = make_generic_payload(kSystem, prompt, max_tokens); return send_api_request(json_payload); } ================================================ FILE: app/lib/GgmlRuntimePaths.cpp ================================================ #include "GgmlRuntimePaths.hpp" #include #include namespace GgmlRuntimePaths { namespace { bool ends_with(const std::string& value, const std::string& suffix) { if (suffix.size() > value.size()) { return false; } return std::equal(suffix.rbegin(), suffix.rend(), value.rbegin()); } } // namespace bool has_payload(const std::filesystem::path& dir) { std::error_code ec; if (!std::filesystem::exists(dir, ec) || !std::filesystem::is_directory(dir, ec)) { return false; } for (const auto& entry : std::filesystem::directory_iterator( dir, std::filesystem::directory_options::skip_permission_denied, ec)) { if (ec || !entry.is_regular_file()) { continue; } const std::string filename = entry.path().filename().string(); if (filename.rfind("libggml-", 0) != 0) { continue; } if (ends_with(filename, ".so") || ends_with(filename, ".dylib")) { return true; } } return false; } std::vector macos_candidate_dirs( const std::filesystem::path& exe_path, std::string_view ggml_subdir) { if (exe_path.empty()) { return {}; } const std::filesystem::path exe_dir = exe_path.parent_path(); const std::filesystem::path subdir(ggml_subdir); return { exe_dir / "../lib" / "precompiled-m1", exe_dir / "../lib" / "precompiled-m2", exe_dir / "../lib" / "precompiled-intel", exe_dir / "../lib" / subdir, exe_dir / "../../lib" / subdir, exe_dir / "../lib" / "aifilesorter", exe_dir / "../../lib" / "aifilesorter", exe_dir / "../lib", exe_dir / "../../lib", }; } std::optional resolve_macos_backend_dir( const std::optional& current_dir, const std::filesystem::path& exe_path, std::string_view ggml_subdir) { if (current_dir && has_payload(*current_dir)) { return current_dir->lexically_normal(); } for (const auto& candidate : macos_candidate_dirs(exe_path, ggml_subdir)) { if (has_payload(candidate)) { return candidate.lexically_normal(); } } return std::nullopt; } } // namespace GgmlRuntimePaths ================================================ FILE: app/lib/ImageRenameMetadataService.cpp ================================================ #include "ImageRenameMetadataService.hpp" #include "Utils.hpp" #include #if __has_include() #include #elif __has_include() #include #else #error "jsoncpp headers not found. Install jsoncpp development files." #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace { constexpr char kExifPrefix[] = "Exif\0\0"; constexpr char kDefaultNominatimUrl[] = "https://nominatim.openstreetmap.org/reverse"; constexpr std::chrono::seconds kMinReverseInterval{1}; constexpr std::array kPngSignature = { 0x89, 'P', 'N', 'G', 0x0D, 0x0A, 0x1A, 0x0A }; constexpr size_t kHeifProbeOutputLimit = 256 * 1024; constexpr uint16_t kTagDateTime = 0x0132; constexpr uint16_t kTagExifIfd = 0x8769; constexpr uint16_t kTagGpsIfd = 0x8825; constexpr uint16_t kTagDateTimeOriginal = 0x9003; constexpr uint16_t kTagCreateDate = 0x9004; constexpr uint16_t kTagGpsLatitudeRef = 0x0001; constexpr uint16_t kTagGpsLatitude = 0x0002; constexpr uint16_t kTagGpsLongitudeRef = 0x0003; constexpr uint16_t kTagGpsLongitude = 0x0004; struct TiffEntry { uint16_t tag{0}; uint16_t type{0}; uint32_t count{0}; uint32_t value_or_offset{0}; size_t raw_offset{0}; }; struct ParsedExifMetadata { std::optional capture_date; std::optional latitude; std::optional longitude; }; size_t write_callback(void* contents, size_t size, size_t nmemb, void* userp) { const size_t total = size * nmemb; auto* output = static_cast(userp); output->append(static_cast(contents), total); return total; } void configure_tls(CURL* curl) { #if defined(_WIN32) const auto cert_path = Utils::ensure_ca_bundle(); curl_easy_setopt(curl, CURLOPT_CAINFO, cert_path.string().c_str()); #else (void)curl; #endif } bool read_byte(std::ifstream& in, uint8_t& value) { char ch = 0; if (!in.get(ch)) { return false; } value = static_cast(static_cast(ch)); return true; } bool read_exact(std::ifstream& in, uint8_t* data, size_t size) { if (size == 0) { return true; } in.read(reinterpret_cast(data), static_cast(size)); return in.good(); } std::optional> read_jpeg_exif_payload(const std::filesystem::path& image_path) { std::ifstream in(image_path, std::ios::binary); if (!in) { return std::nullopt; } uint8_t soi[2] = {0, 0}; if (!read_exact(in, soi, sizeof(soi)) || soi[0] != 0xFF || soi[1] != 0xD8) { return std::nullopt; } while (true) { uint8_t prefix = 0; if (!read_byte(in, prefix)) { break; } if (prefix != 0xFF) { continue; } uint8_t marker = 0; do { if (!read_byte(in, marker)) { return std::nullopt; } } while (marker == 0xFF); if (marker == 0x00) { continue; } if (marker == 0xD9 || marker == 0xDA) { break; } if (marker == 0x01 || (marker >= 0xD0 && marker <= 0xD7)) { continue; } uint8_t length_bytes[2] = {0, 0}; if (!read_exact(in, length_bytes, sizeof(length_bytes))) { break; } const uint16_t segment_length = static_cast((static_cast(length_bytes[0]) << 8) | length_bytes[1]); if (segment_length < 2) { break; } const size_t payload_size = static_cast(segment_length - 2); if (marker == 0xE1) { std::vector payload(payload_size); if (!read_exact(in, payload.data(), payload.size())) { break; } if (payload.size() >= sizeof(kExifPrefix) - 1 && std::memcmp(payload.data(), kExifPrefix, sizeof(kExifPrefix) - 1) == 0) { return std::vector(payload.begin() + static_cast(sizeof(kExifPrefix) - 1), payload.end()); } continue; } in.seekg(static_cast(payload_size), std::ios::cur); if (!in) { break; } } return std::nullopt; } std::optional> read_file_bytes(const std::filesystem::path& path) { std::ifstream in(path, std::ios::binary | std::ios::ate); if (!in) { return std::nullopt; } const std::streamoff size = in.tellg(); if (size < 0) { return std::nullopt; } std::vector bytes(static_cast(size)); in.seekg(0, std::ios::beg); if (!read_exact(in, bytes.data(), bytes.size())) { return std::nullopt; } return bytes; } bool starts_with_bytes(const std::vector& data, const char* prefix, size_t prefix_size) { if (data.size() < prefix_size) { return false; } return std::memcmp(data.data(), prefix, prefix_size) == 0; } bool looks_like_tiff_payload(const std::vector& data) { if (data.size() < 4) { return false; } const bool little_endian = (data[0] == 'I' && data[1] == 'I'); const bool big_endian = (data[0] == 'M' && data[1] == 'M'); if (!little_endian && !big_endian) { return false; } if (little_endian) { return data[2] == 42 && data[3] == 0; } return data[2] == 0 && data[3] == 42; } std::optional> read_tiff_exif_payload(const std::filesystem::path& image_path) { const auto bytes = read_file_bytes(image_path); if (!bytes || bytes->size() < 8) { return std::nullopt; } if (looks_like_tiff_payload(*bytes)) { return bytes; } if (starts_with_bytes(*bytes, kExifPrefix, sizeof(kExifPrefix) - 1)) { std::vector payload(bytes->begin() + static_cast(sizeof(kExifPrefix) - 1), bytes->end()); if (looks_like_tiff_payload(payload)) { return payload; } } return std::nullopt; } std::optional> read_png_exif_payload(const std::filesystem::path& image_path) { std::ifstream in(image_path, std::ios::binary); if (!in) { return std::nullopt; } std::array signature{}; if (!read_exact(in, signature.data(), signature.size()) || signature != kPngSignature) { return std::nullopt; } while (true) { uint8_t chunk_header[8] = {0}; if (!read_exact(in, chunk_header, sizeof(chunk_header))) { return std::nullopt; } const uint32_t chunk_length = (static_cast(chunk_header[0]) << 24) | (static_cast(chunk_header[1]) << 16) | (static_cast(chunk_header[2]) << 8) | static_cast(chunk_header[3]); const std::array chunk_type = { static_cast(chunk_header[4]), static_cast(chunk_header[5]), static_cast(chunk_header[6]), static_cast(chunk_header[7]) }; std::vector chunk_data(chunk_length); if (!read_exact(in, chunk_data.data(), chunk_data.size())) { return std::nullopt; } uint8_t crc[4] = {0}; if (!read_exact(in, crc, sizeof(crc))) { return std::nullopt; } if (chunk_type == std::array{'e', 'X', 'I', 'f'}) { if (starts_with_bytes(chunk_data, kExifPrefix, sizeof(kExifPrefix) - 1)) { return std::vector(chunk_data.begin() + static_cast(sizeof(kExifPrefix) - 1), chunk_data.end()); } return chunk_data; } if (chunk_type == std::array{'I', 'E', 'N', 'D'}) { break; } } return std::nullopt; } std::string to_lower_ascii(std::string value) { std::transform(value.begin(), value.end(), value.begin(), [](unsigned char ch) { return static_cast(std::tolower(ch)); }); return value; } std::string file_extension_lower(const std::filesystem::path& path) { return to_lower_ascii(Utils::path_to_utf8(path.extension())); } bool has_extension(const std::string& extension, std::initializer_list choices) { for (const char* choice : choices) { if (extension == choice) { return true; } } return false; } size_t tiff_type_size(uint16_t type) { switch (type) { case 1: return 1; // BYTE case 2: return 1; // ASCII case 3: return 2; // SHORT case 4: return 4; // LONG case 5: return 8; // RATIONAL default: return 0; } } std::optional read_u16(const std::vector& data, size_t offset, bool little_endian) { if (offset + 2 > data.size()) { return std::nullopt; } const uint16_t b0 = data[offset]; const uint16_t b1 = data[offset + 1]; if (little_endian) { return static_cast((b1 << 8) | b0); } return static_cast((b0 << 8) | b1); } std::optional read_u32(const std::vector& data, size_t offset, bool little_endian) { if (offset + 4 > data.size()) { return std::nullopt; } const uint32_t b0 = data[offset]; const uint32_t b1 = data[offset + 1]; const uint32_t b2 = data[offset + 2]; const uint32_t b3 = data[offset + 3]; if (little_endian) { return (b3 << 24) | (b2 << 16) | (b1 << 8) | b0; } return (b0 << 24) | (b1 << 16) | (b2 << 8) | b3; } bool parse_ifd_entries(const std::vector& tiff, bool little_endian, uint32_t ifd_offset, std::vector& entries) { entries.clear(); if (ifd_offset + 2 > tiff.size()) { return false; } const auto count_opt = read_u16(tiff, ifd_offset, little_endian); if (!count_opt.has_value()) { return false; } const size_t entry_count = *count_opt; size_t cursor = static_cast(ifd_offset + 2); if (cursor + entry_count * 12 > tiff.size()) { return false; } entries.reserve(entry_count); for (size_t i = 0; i < entry_count; ++i) { const size_t entry_offset = cursor + i * 12; const auto tag_opt = read_u16(tiff, entry_offset, little_endian); const auto type_opt = read_u16(tiff, entry_offset + 2, little_endian); const auto count_value_opt = read_u32(tiff, entry_offset + 4, little_endian); const auto value_opt = read_u32(tiff, entry_offset + 8, little_endian); if (!tag_opt || !type_opt || !count_value_opt || !value_opt) { return false; } entries.push_back(TiffEntry{*tag_opt, *type_opt, *count_value_opt, *value_opt, entry_offset}); } return true; } const TiffEntry* find_entry(const std::vector& entries, uint16_t tag) { for (const auto& entry : entries) { if (entry.tag == tag) { return &entry; } } return nullptr; } std::optional value_data_offset(const std::vector& tiff, const TiffEntry& entry) { const size_t unit = tiff_type_size(entry.type); if (unit == 0) { return std::nullopt; } const size_t value_size = static_cast(entry.count) * unit; if (value_size == 0) { return std::nullopt; } if (value_size <= 4) { const size_t inline_offset = entry.raw_offset + 8; if (inline_offset + value_size > tiff.size()) { return std::nullopt; } return inline_offset; } const size_t data_offset = static_cast(entry.value_or_offset); if (data_offset + value_size > tiff.size()) { return std::nullopt; } return data_offset; } std::string trim_copy(std::string value) { const auto not_space = [](unsigned char ch) { return !std::isspace(ch); }; value.erase(value.begin(), std::find_if(value.begin(), value.end(), not_space)); value.erase(std::find_if(value.rbegin(), value.rend(), not_space).base(), value.end()); return value; } std::optional read_ascii_value(const std::vector& tiff, const TiffEntry& entry) { if (entry.type != 2 || entry.count == 0) { return std::nullopt; } const auto data_offset = value_data_offset(tiff, entry); if (!data_offset) { return std::nullopt; } size_t length = static_cast(entry.count); if (length == 0) { return std::nullopt; } const char* begin = reinterpret_cast(tiff.data() + *data_offset); const char* end = begin + length; const char* first_null = std::find(begin, end, '\0'); std::string value(begin, first_null); value = trim_copy(value); if (value.empty()) { return std::nullopt; } return value; } std::optional> read_rational_triplet(const std::vector& tiff, const TiffEntry& entry, bool little_endian) { if (entry.type != 5 || entry.count < 3) { return std::nullopt; } const auto data_offset = value_data_offset(tiff, entry); if (!data_offset) { return std::nullopt; } std::array values{}; for (size_t i = 0; i < 3; ++i) { const size_t pair_offset = *data_offset + i * 8; const auto numerator = read_u32(tiff, pair_offset, little_endian); const auto denominator = read_u32(tiff, pair_offset + 4, little_endian); if (!numerator || !denominator || *denominator == 0) { return std::nullopt; } values[i] = static_cast(*numerator) / static_cast(*denominator); } return values; } std::optional decode_gps_coordinate(const std::array& dms, char hemisphere) { const double degrees = dms[0]; const double minutes = dms[1]; const double seconds = dms[2]; if (!std::isfinite(degrees) || !std::isfinite(minutes) || !std::isfinite(seconds)) { return std::nullopt; } double value = degrees + (minutes / 60.0) + (seconds / 3600.0); if (hemisphere == 'S' || hemisphere == 'W') { value = -value; } if (!std::isfinite(value)) { return std::nullopt; } return value; } std::optional normalize_exif_date_value(const std::string& value) { static const std::regex kDatePattern(R"((\d{4})[:\-](\d{2})[:\-](\d{2}))"); std::smatch match; if (!std::regex_search(value, match, kDatePattern)) { return std::nullopt; } const std::string year = match.str(1); const std::string month = match.str(2); const std::string day = match.str(3); if (year.size() != 4 || month.size() != 2 || day.size() != 2) { return std::nullopt; } return year + "-" + month + "-" + day; } ParsedExifMetadata parse_tiff_metadata(const std::vector& tiff) { ParsedExifMetadata metadata; if (tiff.size() < 8) { return metadata; } bool little_endian = false; if (tiff[0] == 'I' && tiff[1] == 'I') { little_endian = true; } else if (tiff[0] == 'M' && tiff[1] == 'M') { little_endian = false; } else { return metadata; } const auto magic = read_u16(tiff, 2, little_endian); if (!magic || *magic != 42) { return metadata; } const auto ifd0_offset = read_u32(tiff, 4, little_endian); if (!ifd0_offset) { return metadata; } std::vector ifd0_entries; if (!parse_ifd_entries(tiff, little_endian, *ifd0_offset, ifd0_entries)) { return metadata; } if (const TiffEntry* dt = find_entry(ifd0_entries, kTagDateTime)) { if (const auto parsed = read_ascii_value(tiff, *dt)) { metadata.capture_date = normalize_exif_date_value(*parsed); } } uint32_t exif_ifd_offset = 0; if (const TiffEntry* exif_ptr = find_entry(ifd0_entries, kTagExifIfd)) { if (exif_ptr->count == 1 && exif_ptr->type == 4) { exif_ifd_offset = exif_ptr->value_or_offset; } } if (exif_ifd_offset != 0) { std::vector exif_entries; if (parse_ifd_entries(tiff, little_endian, exif_ifd_offset, exif_entries)) { if (const TiffEntry* original = find_entry(exif_entries, kTagDateTimeOriginal)) { if (const auto parsed = read_ascii_value(tiff, *original)) { metadata.capture_date = normalize_exif_date_value(*parsed); } } if (!metadata.capture_date.has_value()) { if (const TiffEntry* created = find_entry(exif_entries, kTagCreateDate)) { if (const auto parsed = read_ascii_value(tiff, *created)) { metadata.capture_date = normalize_exif_date_value(*parsed); } } } } } uint32_t gps_ifd_offset = 0; if (const TiffEntry* gps_ptr = find_entry(ifd0_entries, kTagGpsIfd)) { if (gps_ptr->count == 1 && gps_ptr->type == 4) { gps_ifd_offset = gps_ptr->value_or_offset; } } if (gps_ifd_offset != 0) { std::vector gps_entries; if (parse_ifd_entries(tiff, little_endian, gps_ifd_offset, gps_entries)) { char lat_ref = '\0'; char lon_ref = '\0'; std::optional> lat_dms; std::optional> lon_dms; if (const TiffEntry* lat_ref_entry = find_entry(gps_entries, kTagGpsLatitudeRef)) { if (const auto text = read_ascii_value(tiff, *lat_ref_entry); text && !text->empty()) { lat_ref = static_cast(std::toupper(static_cast((*text)[0]))); } } if (const TiffEntry* lon_ref_entry = find_entry(gps_entries, kTagGpsLongitudeRef)) { if (const auto text = read_ascii_value(tiff, *lon_ref_entry); text && !text->empty()) { lon_ref = static_cast(std::toupper(static_cast((*text)[0]))); } } if (const TiffEntry* lat_entry = find_entry(gps_entries, kTagGpsLatitude)) { lat_dms = read_rational_triplet(tiff, *lat_entry, little_endian); } if (const TiffEntry* lon_entry = find_entry(gps_entries, kTagGpsLongitude)) { lon_dms = read_rational_triplet(tiff, *lon_entry, little_endian); } if (lat_dms && lon_dms && (lat_ref == 'N' || lat_ref == 'S') && (lon_ref == 'E' || lon_ref == 'W')) { const auto latitude = decode_gps_coordinate(*lat_dms, lat_ref); const auto longitude = decode_gps_coordinate(*lon_dms, lon_ref); if (latitude && longitude && std::abs(*latitude) <= 90.0 && std::abs(*longitude) <= 180.0) { metadata.latitude = *latitude; metadata.longitude = *longitude; } } } } return metadata; } std::string shell_quote_argument(const std::string& raw) { #if defined(_WIN32) std::string output; output.reserve(raw.size() + 2); output.push_back('"'); for (char ch : raw) { if (ch == '"') { output += "\\\""; } else { output.push_back(ch); } } output.push_back('"'); return output; #else std::string output; output.reserve(raw.size() + 2); output.push_back('\''); for (char ch : raw) { if (ch == '\'') { output += "'\"'\"'"; } else { output.push_back(ch); } } output.push_back('\''); return output; #endif } std::optional run_command_capture_output(const std::string& command) { #if defined(_WIN32) FILE* pipe = _popen(command.c_str(), "rb"); #else FILE* pipe = popen(command.c_str(), "r"); #endif if (!pipe) { return std::nullopt; } std::array buffer{}; std::string output; while (std::fgets(buffer.data(), static_cast(buffer.size()), pipe) != nullptr) { output.append(buffer.data()); if (output.size() > kHeifProbeOutputLimit) { break; } } #if defined(_WIN32) const int exit_code = _pclose(pipe); #else const int exit_code = pclose(pipe); #endif if (exit_code != 0) { return std::nullopt; } return output; } std::optional json_string_field(const Json::Value& object, const char* key) { if (!object.isObject() || !key || !object.isMember(key) || !object[key].isString()) { return std::nullopt; } const std::string value = trim_copy(object[key].asString()); if (value.empty()) { return std::nullopt; } return value; } std::optional json_number_field(const Json::Value& object, const char* key) { if (!object.isObject() || !key || !object.isMember(key)) { return std::nullopt; } const Json::Value& value = object[key]; if (value.isDouble() || value.isInt() || value.isUInt() || value.isInt64() || value.isUInt64()) { return value.asDouble(); } if (value.isString()) { const std::string text = trim_copy(value.asString()); if (text.empty()) { return std::nullopt; } try { size_t consumed = 0; const double numeric = std::stod(text, &consumed); if (consumed == text.size()) { return numeric; } } catch (const std::exception&) { return std::nullopt; } } return std::nullopt; } ParsedExifMetadata extract_heif_metadata_with_exiftool(const std::filesystem::path& image_path) { ParsedExifMetadata metadata; const std::string path_utf8 = Utils::path_to_utf8(image_path); if (path_utf8.empty()) { return metadata; } std::ostringstream command; #if defined(_WIN32) command << "exiftool -j -n -DateTimeOriginal -CreateDate -DateTime -GPSLatitude -GPSLongitude -- " << shell_quote_argument(path_utf8) << " 2>NUL"; #else command << "exiftool -j -n -DateTimeOriginal -CreateDate -DateTime -GPSLatitude -GPSLongitude -- " << shell_quote_argument(path_utf8) << " 2>/dev/null"; #endif const auto output = run_command_capture_output(command.str()); if (!output || output->empty()) { return metadata; } Json::CharReaderBuilder reader_builder; Json::Value root; std::string errors; std::istringstream stream(*output); if (!Json::parseFromStream(reader_builder, stream, &root, &errors) || !root.isArray() || root.empty() || !root[0].isObject()) { return metadata; } const Json::Value& item = root[0]; if (const auto date = json_string_field(item, "DateTimeOriginal")) { metadata.capture_date = normalize_exif_date_value(*date); } if (!metadata.capture_date.has_value()) { if (const auto date = json_string_field(item, "CreateDate")) { metadata.capture_date = normalize_exif_date_value(*date); } } if (!metadata.capture_date.has_value()) { if (const auto date = json_string_field(item, "DateTime")) { metadata.capture_date = normalize_exif_date_value(*date); } } const auto latitude = json_number_field(item, "GPSLatitude"); const auto longitude = json_number_field(item, "GPSLongitude"); if (latitude && longitude && std::isfinite(*latitude) && std::isfinite(*longitude) && std::abs(*latitude) <= 90.0 && std::abs(*longitude) <= 180.0) { metadata.latitude = *latitude; metadata.longitude = *longitude; } return metadata; } std::optional pick_place_name(const Json::Value& root) { static const std::array kAddressKeys = { "city", "town", "village", "hamlet", "municipality", "suburb", "county", "state", "country" }; if (root.isMember("address") && root["address"].isObject()) { const auto& address = root["address"]; for (const char* key : kAddressKeys) { if (address.isMember(key) && address[key].isString()) { const std::string value = trim_copy(address[key].asString()); if (!value.empty()) { return value; } } } } if (root.isMember("name") && root["name"].isString()) { const std::string value = trim_copy(root["name"].asString()); if (!value.empty()) { return value; } } if (root.isMember("display_name") && root["display_name"].isString()) { std::string display = root["display_name"].asString(); const auto comma = display.find(','); if (comma != std::string::npos) { display = display.substr(0, comma); } display = trim_copy(display); if (!display.empty()) { return display; } } return std::nullopt; } } // namespace ImageRenameMetadataService::ImageRenameMetadataService(std::string config_dir) : config_dir_(std::move(config_dir)) { open_cache_db(); } ImageRenameMetadataService::~ImageRenameMetadataService() { if (cache_db_) { sqlite3_close(cache_db_); cache_db_ = nullptr; } } bool ImageRenameMetadataService::open_cache_db() { if (cache_db_) { return true; } if (config_dir_.empty()) { return false; } std::error_code ec; const auto config_path = Utils::utf8_to_path(config_dir_); std::filesystem::create_directories(config_path, ec); if (ec) { return false; } const auto db_path = config_path / "image_place_cache.db"; if (sqlite3_open(db_path.string().c_str(), &cache_db_) != SQLITE_OK) { if (cache_db_) { sqlite3_close(cache_db_); cache_db_ = nullptr; } return false; } const char* create_sql = R"( CREATE TABLE IF NOT EXISTS reverse_geocode_cache ( latitude_key TEXT NOT NULL, longitude_key TEXT NOT NULL, place_slug TEXT, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY(latitude_key, longitude_key) ); )"; char* error = nullptr; if (sqlite3_exec(cache_db_, create_sql, nullptr, nullptr, &error) != SQLITE_OK) { if (error) { sqlite3_free(error); } sqlite3_close(cache_db_); cache_db_ = nullptr; return false; } return true; } ImageRenameMetadataService::ExifMetadata ImageRenameMetadataService::extract_exif_metadata( const std::filesystem::path& image_path) const { ExifMetadata metadata; const std::string extension = file_extension_lower(image_path); const bool is_heif = has_extension(extension, {".heic", ".heif", ".hif"}); std::optional> exif_tiff; if (has_extension(extension, {".jpg", ".jpeg"})) { exif_tiff = read_jpeg_exif_payload(image_path); } else if (has_extension(extension, {".tif", ".tiff"})) { exif_tiff = read_tiff_exif_payload(image_path); } else if (has_extension(extension, {".png"})) { exif_tiff = read_png_exif_payload(image_path); } if (!exif_tiff) { exif_tiff = read_jpeg_exif_payload(image_path); } if (!exif_tiff) { exif_tiff = read_tiff_exif_payload(image_path); } if (!exif_tiff) { exif_tiff = read_png_exif_payload(image_path); } if (exif_tiff) { const ParsedExifMetadata parsed = parse_tiff_metadata(*exif_tiff); metadata.capture_date = parsed.capture_date; metadata.latitude = parsed.latitude; metadata.longitude = parsed.longitude; return metadata; } if (is_heif) { const ParsedExifMetadata parsed = extract_heif_metadata_with_exiftool(image_path); metadata.capture_date = parsed.capture_date; metadata.latitude = parsed.latitude; metadata.longitude = parsed.longitude; } return metadata; } ImageRenameMetadataService::CacheLookup ImageRenameMetadataService::lookup_cache( const std::string& lat_key, const std::string& lon_key) const { CacheLookup lookup; if (!cache_db_) { return lookup; } sqlite3_stmt* stmt = nullptr; const char* query_sql = "SELECT place_slug FROM reverse_geocode_cache WHERE latitude_key = ? AND longitude_key = ?;"; if (sqlite3_prepare_v2(cache_db_, query_sql, -1, &stmt, nullptr) != SQLITE_OK) { return lookup; } sqlite3_bind_text(stmt, 1, lat_key.c_str(), -1, SQLITE_TRANSIENT); sqlite3_bind_text(stmt, 2, lon_key.c_str(), -1, SQLITE_TRANSIENT); const int step = sqlite3_step(stmt); if (step == SQLITE_ROW) { lookup.found = true; if (sqlite3_column_type(stmt, 0) != SQLITE_NULL) { const char* text = reinterpret_cast(sqlite3_column_text(stmt, 0)); if (text && *text != '\0') { lookup.place = text; } } } sqlite3_finalize(stmt); return lookup; } void ImageRenameMetadataService::upsert_cache(const std::string& lat_key, const std::string& lon_key, const std::optional& place) const { if (!cache_db_) { return; } sqlite3_stmt* stmt = nullptr; const char* upsert_sql = R"( INSERT INTO reverse_geocode_cache (latitude_key, longitude_key, place_slug, updated_at) VALUES (?, ?, ?, CURRENT_TIMESTAMP) ON CONFLICT(latitude_key, longitude_key) DO UPDATE SET place_slug = excluded.place_slug, updated_at = CURRENT_TIMESTAMP; )"; if (sqlite3_prepare_v2(cache_db_, upsert_sql, -1, &stmt, nullptr) != SQLITE_OK) { return; } sqlite3_bind_text(stmt, 1, lat_key.c_str(), -1, SQLITE_TRANSIENT); sqlite3_bind_text(stmt, 2, lon_key.c_str(), -1, SQLITE_TRANSIENT); if (place.has_value() && !place->empty()) { sqlite3_bind_text(stmt, 3, place->c_str(), -1, SQLITE_TRANSIENT); } else { sqlite3_bind_null(stmt, 3); } sqlite3_step(stmt); sqlite3_finalize(stmt); } ImageRenameMetadataService::ReverseGeocodeResult ImageRenameMetadataService::reverse_geocode( double latitude, double longitude) { ReverseGeocodeResult result; CURL* curl = curl_easy_init(); if (!curl) { return result; } std::ostringstream url_builder; const char* endpoint = std::getenv("AI_FILE_SORTER_NOMINATIM_URL"); url_builder << ((endpoint && endpoint[0] != '\0') ? endpoint : kDefaultNominatimUrl) << "?format=jsonv2&addressdetails=1&zoom=10&lat=" << std::fixed << std::setprecision(7) << latitude << "&lon=" << std::fixed << std::setprecision(7) << longitude; std::string response; curl_easy_setopt(curl, CURLOPT_URL, url_builder.str().c_str()); curl_easy_setopt(curl, CURLOPT_TIMEOUT, 8L); curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &write_callback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response); curl_easy_setopt(curl, CURLOPT_USERAGENT, "AIFileSorter/1.7 (reverse-geocoder)"); configure_tls(curl); curl_slist* headers = nullptr; headers = curl_slist_append(headers, "Accept: application/json"); if (headers) { curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); } const CURLcode code = curl_easy_perform(curl); long http_status = 0; curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_status); if (headers) { curl_slist_free_all(headers); } curl_easy_cleanup(curl); if (code != CURLE_OK || http_status != 200) { return result; } Json::CharReaderBuilder reader_builder; Json::Value root; std::string errors; std::istringstream stream(response); if (!Json::parseFromStream(reader_builder, stream, &root, &errors)) { return result; } const auto place_name = pick_place_name(root); result.success = true; if (place_name.has_value()) { const std::string place_slug = slugify(*place_name); if (!place_slug.empty()) { result.place = place_slug; } } return result; } std::optional ImageRenameMetadataService::resolve_place_prefix(double latitude, double longitude) { // Requirement: no network available -> no place prefix. if (!network_available()) { return std::nullopt; } const std::string lat_key = format_coord_key(latitude); const std::string lon_key = format_coord_key(longitude); const CacheLookup cached = lookup_cache(lat_key, lon_key); if (cached.found) { return cached.place; } const auto now = std::chrono::steady_clock::now(); if (last_geocode_request_.time_since_epoch().count() != 0) { const auto elapsed = now - last_geocode_request_; if (elapsed < kMinReverseInterval) { std::this_thread::sleep_for(kMinReverseInterval - elapsed); } } const auto geocode = reverse_geocode(latitude, longitude); last_geocode_request_ = std::chrono::steady_clock::now(); if (geocode.success) { upsert_cache(lat_key, lon_key, geocode.place); } return geocode.place; } std::string ImageRenameMetadataService::enrich_suggested_name( const std::filesystem::path& image_path, const std::string& suggested_name) { if (suggested_name.empty()) { return suggested_name; } const ExifMetadata metadata = extract_exif_metadata(image_path); std::optional place_prefix; if (metadata.latitude.has_value() && metadata.longitude.has_value()) { place_prefix = resolve_place_prefix(*metadata.latitude, *metadata.longitude); } return apply_prefix_to_filename(suggested_name, metadata.capture_date, place_prefix); } std::optional ImageRenameMetadataService::extract_capture_date( const std::filesystem::path& image_path) const { return extract_exif_metadata(image_path).capture_date; } std::string ImageRenameMetadataService::apply_prefix_to_filename( const std::string& suggested_name, const std::optional& date_prefix, const std::optional& place_prefix) { if (suggested_name.empty()) { return suggested_name; } std::vector prefix_parts; if (date_prefix.has_value() && !date_prefix->empty()) { prefix_parts.push_back(*date_prefix); } if (place_prefix.has_value() && !place_prefix->empty()) { const std::string place_slug = slugify(*place_prefix); if (!place_slug.empty()) { prefix_parts.push_back(place_slug); } } if (prefix_parts.empty()) { return suggested_name; } const auto suggested_path = Utils::utf8_to_path(suggested_name); std::string stem = Utils::path_to_utf8(suggested_path.stem()); std::string ext = Utils::path_to_utf8(suggested_path.extension()); if (stem.empty()) { stem = suggested_name; ext.clear(); } std::ostringstream prefix_builder; for (size_t index = 0; index < prefix_parts.size(); ++index) { if (index > 0) { prefix_builder << '_'; } prefix_builder << prefix_parts[index]; } const std::string prefix = prefix_builder.str(); if (prefix.empty()) { return suggested_name; } if (stem == prefix || stem.rfind(prefix + "_", 0) == 0) { return suggested_name; } const std::string prefixed_stem = prefix + "_" + stem; return ext.empty() ? prefixed_stem : prefixed_stem + ext; } std::string ImageRenameMetadataService::slugify(const std::string& value) { std::string output; output.reserve(value.size()); bool last_sep = true; for (unsigned char ch : value) { if (std::isalnum(ch)) { output.push_back(static_cast(std::tolower(ch))); last_sep = false; continue; } if (!last_sep && !output.empty()) { output.push_back('_'); last_sep = true; } } while (!output.empty() && output.back() == '_') { output.pop_back(); } return output; } std::optional ImageRenameMetadataService::normalize_exif_date(const std::string& value) { return normalize_exif_date_value(value); } std::string ImageRenameMetadataService::format_coord_key(double value) { std::ostringstream out; out << std::fixed << std::setprecision(4) << value; return out.str(); } bool ImageRenameMetadataService::network_available() { if (!network_checked_) { network_available_ = Utils::is_network_available(); network_checked_ = true; } return network_available_; } ================================================ FILE: app/lib/IniConfig.cpp ================================================ #include "IniConfig.hpp" #include "Logger.hpp" #include #include #include #include #include #include namespace { template void ini_log(spdlog::level::level_enum level, const char* fmt, Args&&... args) { auto message = fmt::format(fmt::runtime(fmt), std::forward(args)...); if (auto logger = Logger::get_logger("core_logger")) { logger->log(level, "{}", message); } else { std::fprintf(stderr, "%s\n", message.c_str()); } } std::string trim_copy(const std::string& input) { const auto begin = input.find_first_not_of(" \t"); if (begin == std::string::npos) { return {}; } const auto end = input.find_last_not_of(" \t"); return input.substr(begin, end - begin + 1); } bool should_skip_line(const std::string& line) { return line.empty() || line.front() == ';' || line.front() == '#'; } bool parse_section_header(const std::string& line, std::string& section) { if (line.size() >= 2 && line.front() == '[' && line.back() == ']') { section = line.substr(1, line.size() - 2); return true; } return false; } std::optional> parse_key_value(const std::string& line) { const auto delimiter = line.find('='); if (delimiter == std::string::npos) { return std::nullopt; } std::string key = trim_copy(line.substr(0, delimiter)); std::string value = trim_copy(line.substr(delimiter + 1)); if (key.empty()) { return std::nullopt; } return std::make_pair(std::move(key), std::move(value)); } } bool IniConfig::load(const std::string &filename) { std::ifstream file(filename); if (!file.is_open()) { ini_log(spdlog::level::err, "Failed to open config file: {}", filename); return false; } std::string raw_line; std::string section; while (std::getline(file, raw_line)) { const std::string line = trim_copy(raw_line); if (should_skip_line(line)) { continue; } if (parse_section_header(line, section)) { continue; } if (auto key_value = parse_key_value(line)) { data[section][key_value->first] = key_value->second; } } return true; } std::string IniConfig::getValue(const std::string §ion, const std::string &key, const std::string &default_value) const { auto sec_it = data.find(section); if (sec_it != data.end()) { auto key_it = sec_it->second.find(key); if (key_it != sec_it->second.end()) { return key_it->second; } } return default_value; } void IniConfig::setValue(const std::string §ion, const std::string &key, const std::string &value) { data[section][key] = value; } bool IniConfig::save(const std::string &filename) const { std::ofstream file(filename); if (!file.is_open()) { ini_log(spdlog::level::err, "Failed to open config file: {}", filename); return false; } for (const auto §ion : data) { file << "[" << section.first << "]\n"; for (const auto &pair : section.second) { file << pair.first << " = " << pair.second << "\n"; } file << "\n"; } return true; } bool IniConfig::hasValue(const std::string& section, const std::string& key) const { const auto sec_it = data.find(section); if (sec_it == data.end()) { return false; } const auto key_it = sec_it->second.find(key); return key_it != sec_it->second.end(); } ================================================ FILE: app/lib/LLMClient.cpp ================================================ #include "LLMClient.hpp" #include "Types.hpp" #include "Utils.hpp" #include "Logger.hpp" #include #include #include #if __has_include() #include #elif __has_include() #include #else #error "jsoncpp headers not found. Install jsoncpp development files." #endif #include #include #include #include #include // Helper function to write the response from curl into a string static size_t WriteCallback(void *contents, size_t size, size_t nmemb, std::string *response) { size_t totalSize = size * nmemb; response->append(static_cast(contents), totalSize); return totalSize; } namespace { std::string trim_ws(const std::string& value); std::string escape_json(const std::string& input) { std::string out; out.reserve(input.size() * 2); for (char c : input) { switch (c) { case '"': out += "\\\""; break; case '\\': out += "\\\\"; break; case '\n': out += "\\n"; break; case '\r': out += "\\r"; break; case '\t': out += "\\t"; break; default: out += c; } } return out; } long resolve_custom_timeout_seconds() { const char* env = std::getenv("AI_FILE_SORTER_CUSTOM_LLM_TIMEOUT"); if (env && *env) { char* end = nullptr; const long value = std::strtol(env, &end, 10); if (end != env && value > 0) { return value; } } return 60L; } long resolve_openai_timeout_seconds() { return 5L; } long resolve_timeout_seconds(const std::string& base_url) { const std::string trimmed = trim_ws(base_url); if (trimmed.empty()) { return resolve_openai_timeout_seconds(); } return resolve_custom_timeout_seconds(); } std::string trim_ws(const std::string& value) { const char* whitespace = " \t\n\r\f\v"; const auto start = value.find_first_not_of(whitespace); const auto end = value.find_last_not_of(whitespace); if (start == std::string::npos || end == std::string::npos) { return std::string(); } return value.substr(start, end - start + 1); } std::string trim_trailing_slashes(std::string value) { while (!value.empty() && value.back() == '/') { value.pop_back(); } return value; } bool ends_with(const std::string& value, const std::string& suffix) { if (suffix.size() > value.size()) { return false; } return std::equal(suffix.rbegin(), suffix.rend(), value.rbegin()); } struct CurlRequest { CURL* handle{nullptr}; curl_slist* headers{nullptr}; CurlRequest() = default; CurlRequest(const CurlRequest&) = delete; CurlRequest& operator=(const CurlRequest&) = delete; CurlRequest(CurlRequest&& other) noexcept : handle(other.handle), headers(other.headers) { other.handle = nullptr; other.headers = nullptr; } CurlRequest& operator=(CurlRequest&& other) noexcept { if (this != &other) { cleanup(); handle = other.handle; headers = other.headers; other.handle = nullptr; other.headers = nullptr; } return *this; } ~CurlRequest() { cleanup(); } private: void cleanup() { if (handle) { curl_easy_cleanup(handle); handle = nullptr; } if (headers) { curl_slist_free_all(headers); headers = nullptr; } } }; CurlRequest create_curl_request(const std::shared_ptr& logger) { CurlRequest request; request.handle = curl_easy_init(); if (!request.handle) { if (logger) { logger->critical("Failed to initialize cURL handle for remote request"); } throw std::runtime_error("Initialization Error: Failed to initialize cURL."); } #ifdef _WIN32 try { const auto cert_path = Utils::ensure_ca_bundle(); curl_easy_setopt(request.handle, CURLOPT_CAINFO, cert_path.string().c_str()); } catch (const std::exception& ex) { throw std::runtime_error(std::string("Failed to stage CA bundle: ") + ex.what()); } #endif return request; } void configure_request_payload(CurlRequest& request, const std::string& api_url, const std::string& payload, const std::string& api_key, long timeout_seconds, std::string& response_buffer) { curl_easy_setopt(request.handle, CURLOPT_URL, api_url.c_str()); curl_easy_setopt(request.handle, CURLOPT_POST, 1L); curl_easy_setopt(request.handle, CURLOPT_TIMEOUT, timeout_seconds); request.headers = curl_slist_append(request.headers, "Content-Type: application/json"); if (!api_key.empty()) { const std::string auth = "Authorization: Bearer " + api_key; request.headers = curl_slist_append(request.headers, auth.c_str()); } curl_easy_setopt(request.handle, CURLOPT_HTTPHEADER, request.headers); curl_easy_setopt(request.handle, CURLOPT_POSTFIELDS, payload.c_str()); curl_easy_setopt(request.handle, CURLOPT_WRITEFUNCTION, WriteCallback); curl_easy_setopt(request.handle, CURLOPT_WRITEDATA, &response_buffer); } long perform_request(CurlRequest& request, const std::shared_ptr& logger) { const CURLcode res = curl_easy_perform(request.handle); if (res != CURLE_OK) { if (logger) { logger->error("cURL request failed: {}", curl_easy_strerror(res)); } throw std::runtime_error("Network Error: " + std::string(curl_easy_strerror(res))); } long http_code = 0; curl_easy_getinfo(request.handle, CURLINFO_RESPONSE_CODE, &http_code); return http_code; } std::string parse_category_response(const std::string& payload, long http_code, const std::shared_ptr& logger) { Json::CharReaderBuilder reader_builder; Json::Value root; std::istringstream response_stream(payload); std::string errors; if (!Json::parseFromStream(reader_builder, response_stream, &root, &errors)) { if (logger) { logger->error("Failed to parse JSON response: {}", errors); } throw std::runtime_error("Response Error: Failed to parse JSON response. " + errors); } if (http_code == 401) { throw std::runtime_error("Authentication Error: Invalid or missing API key."); } if (http_code == 403) { throw std::runtime_error("Authorization Error: API key does not have sufficient permissions."); } if (http_code >= 500) { throw std::runtime_error("Server Error: Remote LLM server returned an error. Status code: " + std::to_string(http_code)); } if (http_code >= 400) { const std::string error_message = root["error"]["message"].asString(); throw std::runtime_error("Client Error: " + error_message); } return root["choices"][0]["message"]["content"].asString(); } } LLMClient::LLMClient(std::string api_key, std::string model, std::string base_url) : api_key(std::move(api_key)), model(std::move(model)), base_url(std::move(base_url)) {} LLMClient::~LLMClient() = default; void LLMClient::set_prompt_logging_enabled(bool enabled) { prompt_logging_enabled = enabled; } std::string LLMClient::send_api_request(std::string json_payload) { std::string response_string; const std::string api_url = resolve_api_url(); auto logger = Logger::get_logger("core_logger"); if (logger) { logger->debug("Dispatching remote LLM request to {}", api_url); } CurlRequest request = create_curl_request(logger); configure_request_payload(request, api_url, json_payload, api_key, resolve_timeout_seconds(base_url), response_string); const long http_code = perform_request(request, logger); return parse_category_response(response_string, http_code, logger); } std::string LLMClient::effective_model() const { return model.empty() ? "gpt-4o-mini" : model; } std::string LLMClient::resolve_api_url() const { static const std::string kDefaultApi = "https://api.openai.com/v1/chat/completions"; static const std::string kChatSuffix = "/chat/completions"; if (base_url.empty()) { return kDefaultApi; } std::string trimmed = trim_ws(base_url); if (trimmed.empty()) { return kDefaultApi; } trimmed = trim_trailing_slashes(trimmed); if (ends_with(trimmed, kChatSuffix)) { return trimmed; } return trimmed + kChatSuffix; } std::string LLMClient::categorize_file(const std::string& file_name, const std::string& file_path, FileType file_type, const std::string& consistency_context) { if (auto logger = Logger::get_logger("core_logger")) { if (!file_path.empty()) { logger->debug("Requesting remote categorization for '{}' ({}) at '{}'", file_name, to_string(file_type), file_path); } else { logger->debug("Requesting remote categorization for '{}' ({})", file_name, to_string(file_type)); } } std::string json_payload = make_payload(file_name, file_path, file_type, consistency_context); if (prompt_logging_enabled && !last_prompt.empty()) { std::cout << "\n[DEV][PROMPT] Categorization request\n" << last_prompt << "\n"; } std::string category = send_api_request(json_payload); if (prompt_logging_enabled) { std::cout << "[DEV][RESPONSE] Categorization reply\n" << category << "\n"; } return category; } std::string LLMClient::make_payload(const std::string& file_name, const std::string& file_path, const FileType file_type, const std::string& consistency_context) { std::string prompt; std::string sanitized_path = file_path; if (!sanitized_path.empty()) { prompt = "Categorize the item with full path: " + sanitized_path + "\n"; prompt += "File name: " + file_name; } else { prompt = "Categorize file: " + file_name; } if (file_type == FileType::File) { // already set above } else { if (!sanitized_path.empty()) { prompt = "Categorize the directory with full path: " + sanitized_path + "\nDirectory name: " + file_name; } else { prompt = "Categorize directory: " + file_name; } } if (!consistency_context.empty()) { prompt += "\n\n" + consistency_context; } last_prompt = prompt; const std::string escaped_prompt = escape_json(prompt); const std::string system_prompt = "You are a file categorization assistant. If it's an installer, describe the type of software it installs. " "Consider the filename, extension, and any directory context provided. Always reply with one line in the " "format
: . Main category must be broad (one or two words, plural). Subcategory " "must be specific, relevant, and must not repeat the main category."; const std::string escaped_system = escape_json(system_prompt); std::ostringstream payload; payload << "{\n" << " \"model\": \"" << escape_json(effective_model()) << "\",\n" << " \"messages\": [\n" << " {\"role\": \"system\", \"content\": \"" << escaped_system << "\"},\n" << " {\"role\": \"user\", \"content\": \"" << escaped_prompt << "\"}\n" << " ]\n" << "}"; return payload.str(); } std::string LLMClient::make_generic_payload(const std::string& system_prompt, const std::string& user_prompt, int max_tokens) const { std::ostringstream payload; payload << "{\"model\": \"" << escape_json(effective_model()) << "\","; payload << "\"messages\": ["; payload << "{\"role\": \"system\", \"content\": \"" << escape_json(system_prompt) << "\"},"; payload << "{\"role\": \"user\", \"content\": \"" << escape_json(user_prompt) << "\"}]"; if (max_tokens > 0) { payload << ",\"max_tokens\": " << max_tokens; } payload << "}"; return payload.str(); } std::string LLMClient::complete_prompt(const std::string& prompt, int max_tokens) { static const std::string kSystem = "You are a precise assistant that returns well-formed JSON responses."; std::string json_payload = make_generic_payload(kSystem, prompt, max_tokens); return send_api_request(json_payload); } ================================================ FILE: app/lib/LLMDownloader.cpp ================================================ #include "LLMDownloader.hpp" #include "Utils.hpp" #include "Logger.hpp" #include "TestHooks.hpp" #include #include #include #include #include #include #include #include #ifdef _WIN32 #include #endif namespace { constexpr const char kMetadataSuffix[] = ".aifs.meta"; constexpr const char kPartialDownloadSuffix[] = ".part"; bool replace_download_file(const std::filesystem::path& source, const std::filesystem::path& target, std::string& error) { #ifdef _WIN32 if (MoveFileExW(source.c_str(), target.c_str(), MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH)) { return true; } error = std::system_category().message(static_cast(GetLastError())); return false; #else std::error_code ec; std::filesystem::rename(source, target, ec); if (!ec) { return true; } error = ec.message(); return false; #endif } #ifdef AI_FILE_SORTER_TEST_BUILD TestHooks::LLMDownloadProbe& download_probe_slot() { static TestHooks::LLMDownloadProbe probe; return probe; } #endif } // namespace LLMDownloader::LLMDownloader(const std::string& download_url) : url(download_url), destination_dir(Utils::get_default_llm_destination()) { set_download_destination(); last_progress_update = std::chrono::steady_clock::now(); } void LLMDownloader::set_download_destination() { std::filesystem::create_directories(destination_dir); download_destination = Utils::make_default_path_to_file_from_download_url(url); load_cached_metadata(); migrate_legacy_partial_download_if_needed(); } std::string LLMDownloader::metadata_path() const { return download_destination + kMetadataSuffix; } std::string LLMDownloader::partial_download_path() const { return download_destination + kPartialDownloadSuffix; } void LLMDownloader::load_cached_metadata() { if (real_content_length > 0) { return; } std::ifstream in(metadata_path()); if (!in.is_open()) { return; } std::string cached_url; long long cached_length = 0; std::string line; constexpr const char kUrlPrefix[] = "url="; constexpr const char kLengthPrefix[] = "content_length="; while (std::getline(in, line)) { if (line.rfind(kUrlPrefix, 0) == 0) { cached_url = line.substr(sizeof(kUrlPrefix) - 1); continue; } if (line.rfind(kLengthPrefix, 0) == 0) { try { cached_length = std::stoll(line.substr(sizeof(kLengthPrefix) - 1)); } catch (const std::exception&) { cached_length = 0; } } } if (!cached_url.empty() && cached_url != url) { return; } if (cached_length > 0) { real_content_length = cached_length; } } void LLMDownloader::persist_cached_metadata() const { if (real_content_length <= 0) { return; } std::ofstream out(metadata_path(), std::ios::trunc); if (!out.is_open()) { return; } out << "url=" << url << "\n"; out << "content_length=" << real_content_length << "\n"; } void LLMDownloader::migrate_legacy_partial_download_if_needed() { if (real_content_length <= 0) { return; } const auto partial_path = std::filesystem::path(partial_download_path()); std::error_code ec; if (std::filesystem::exists(partial_path, ec) || ec) { return; } const auto final_path = std::filesystem::path(download_destination); const auto size = std::filesystem::file_size(final_path, ec); if (ec || size == 0 || static_cast(size) >= real_content_length) { return; } std::filesystem::rename(final_path, partial_path, ec); if (auto logger = Logger::get_logger("core_logger")) { if (ec) { logger->warn("Failed to migrate legacy partial download '{}' to '{}': {}", final_path.string(), partial_path.string(), ec.message()); } else { logger->info("Migrated legacy partial download '{}' to '{}'", final_path.string(), partial_path.string()); } } } void LLMDownloader::init_if_needed() { if (initialized) return; if (!Utils::is_network_available()) { // std::cerr << "Still no internet...\n"; return; } parse_headers(); set_download_destination(); initialized = true; } bool LLMDownloader::is_inited() { return initialized; } size_t LLMDownloader::write_data(void* ptr, size_t size, size_t nmemb, FILE* stream) { return fwrite(ptr, size, nmemb, stream); } size_t LLMDownloader::discard_callback(char* ptr, size_t size, size_t nmemb, void* userdata) { return size * nmemb; } void LLMDownloader::parse_headers() { CURL* curl = curl_easy_init(); if (!curl) { throw std::runtime_error("Failed to initialize CURL"); } std::lock_guard lock(mutex); curl_headers.clear(); resumable = false; real_content_length = 0; setup_header_curl_options(curl); CURLcode res = curl_easy_perform(curl); curl_off_t cl; if (curl_easy_getinfo(curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD_T, &cl) == CURLE_OK && cl > 0) { real_content_length = cl; } curl_easy_cleanup(curl); if (res != CURLE_OK) { throw std::runtime_error("CURL HEAD request failed: " + std::string(curl_easy_strerror(res))); } persist_cached_metadata(); } int LLMDownloader::progress_func(void* clientp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t, curl_off_t) { auto* self = static_cast(clientp); if (self->cancel_requested.load(std::memory_order_relaxed)) { return 1; } if (dltotal > 0 && self->on_status_text) { std::string msg = "Downloaded " + Utils::format_size(self->resume_offset + dlnow) + " / " + Utils::format_size(self->real_content_length); self->on_status_text(msg); } curl_off_t total_size = self->real_content_length; if (total_size == 0) { return 0; } double raw_progress = static_cast(self->resume_offset + dlnow) / static_cast(total_size); double clamped_progress = std::min(raw_progress, 1.0); auto now = std::chrono::steady_clock::now(); auto elapsed = std::chrono::duration_cast(now - self->last_progress_update); if (elapsed.count() > 100) { self->last_progress_update = now; if (self->progress_callback) { self->progress_callback(clamped_progress); } } return 0; } size_t LLMDownloader::header_callback(char* buffer, size_t size, size_t nitems, void* userdata) { size_t total_size = size * nitems; auto* self = static_cast(userdata); std::string header(buffer, total_size); // Normalize and parse header auto colon_pos = header.find(':'); if (colon_pos != std::string::npos) { std::string key = header.substr(0, colon_pos); std::string value = header.substr(colon_pos + 1); // Trim spaces key.erase(std::remove_if(key.begin(), key.end(), ::isspace), key.end()); value.erase(0, value.find_first_not_of(" \t\r\n")); value.erase(value.find_last_not_of(" \t\r\n") + 1); // Lowercase key std::transform(key.begin(), key.end(), key.begin(), ::tolower); // Store all headers self->curl_headers[key] = value; } return total_size; } void LLMDownloader::start_download(std::function progress_cb, std::function on_complete_cb, std::function on_status_text, std::function on_error_cb) { if (download_thread.joinable()) { download_thread.join(); } cancel_requested.store(false, std::memory_order_relaxed); this->progress_callback = std::move(progress_cb); this->on_download_complete = std::move(on_complete_cb); this->on_status_text = std::move(on_status_text); this->on_download_error = std::move(on_error_cb); download_thread = std::thread([this]() { try { perform_download(); } catch (const std::exception& ex) { if (auto logger = Logger::get_logger("core_logger")) { logger->error("LLM download failed: {}", ex.what()); } if (this->on_status_text) { this->on_status_text(std::string("Download error: ") + ex.what()); } if (this->on_download_error) { this->on_download_error(ex.what()); } } }); } void LLMDownloader::perform_download() { auto init_curl = []() -> CURL* { CURL* handle = curl_easy_init(); if (!handle) { throw std::runtime_error("Failed to initialize curl"); } return handle; }; CURL* curl = init_curl(); auto cleanup_curl = [&]() { if (curl) { curl_easy_cleanup(curl); curl = nullptr; } }; migrate_legacy_partial_download_if_needed(); long resume_from = determine_resume_offset(); resume_offset = resume_from; if (real_content_length > 0 && resume_from >= real_content_length) { notify_download_complete(); cleanup_curl(); return; } auto attempt_download = [&](long offset) -> CURLcode { #ifdef AI_FILE_SORTER_TEST_BUILD if (auto& probe = download_probe_slot()) { return probe(offset, partial_download_path()); } #endif FILE* fp = open_output_file(offset); if (!fp) { cleanup_curl(); throw std::runtime_error("Failed to open file: " + partial_download_path()); } setup_download_curl_options(curl, fp, offset); CURLcode result = curl_easy_perform(curl); fclose(fp); return result; }; bool retried_full_download = false; while (true) { CURLcode res = attempt_download(resume_from); if (res == CURLE_OK) { mark_download_resumable(); notify_download_complete(); cleanup_curl(); return; } cancel_requested.store(false, std::memory_order_relaxed); if (res == CURLE_ABORTED_BY_CALLBACK) { if (on_download_error) { on_download_error("Download cancelled"); } cleanup_curl(); return; } const bool range_error = res == CURLE_HTTP_RANGE_ERROR || res == CURLE_BAD_DOWNLOAD_RESUME #ifdef CURLE_RANGE_ERROR || res == CURLE_RANGE_ERROR #endif ; if (range_error && resume_from > 0 && !retried_full_download) { if (auto logger = Logger::get_logger("core_logger")) { logger->warn("Range resume failed ({}). Retrying full download.", curl_easy_strerror(res)); } retried_full_download = true; resume_from = 0; resume_offset = 0; std::error_code ec; std::filesystem::remove(partial_download_path(), ec); cleanup_curl(); curl = init_curl(); continue; } std::string error = std::string("Download failed: ") + curl_easy_strerror(res); cleanup_curl(); throw std::runtime_error(error); } } void LLMDownloader::mark_download_resumable() { std::lock_guard lock(mutex); resumable = true; } void LLMDownloader::notify_download_complete() { const auto partial_path = std::filesystem::path(partial_download_path()); const auto final_path = std::filesystem::path(download_destination); if (real_content_length <= 0) { std::error_code ec; const auto completed_path = std::filesystem::exists(partial_path, ec) && !ec ? partial_path : final_path; const auto size = std::filesystem::file_size(completed_path, ec); if (!ec) { real_content_length = static_cast(size); } } std::error_code exists_ec; if (std::filesystem::exists(partial_path, exists_ec) && !exists_ec) { std::string error; if (!replace_download_file(partial_path, final_path, error)) { throw std::runtime_error("Failed to finalize download: " + error); } } persist_cached_metadata(); if (on_download_complete) { on_download_complete(); } } void LLMDownloader::setup_common_curl_options(CURL* curl) { #ifdef _WIN32 try { const auto cert_path = Utils::ensure_ca_bundle(); curl_easy_setopt(curl, CURLOPT_CAINFO, cert_path.string().c_str()); } catch (const std::exception& ex) { throw std::runtime_error(std::string("Failed to stage CA bundle: ") + ex.what()); } #endif curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L); } void LLMDownloader::setup_header_curl_options(CURL* curl) { setup_common_curl_options(curl); curl_easy_setopt(curl, CURLOPT_NOBODY, 1L); curl_easy_setopt(curl, CURLOPT_HEADER, 1L); curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, &LLMDownloader::header_callback); curl_easy_setopt(curl, CURLOPT_HEADERDATA, this); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, discard_callback); // <-- avoids stdout curl_easy_setopt(curl, CURLOPT_WRITEDATA, nullptr); } void LLMDownloader::setup_download_curl_options(CURL* curl, FILE* fp, long resume_offset) { setup_common_curl_options(curl); curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &LLMDownloader::write_data); curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, &LLMDownloader::header_callback); curl_easy_setopt(curl, CURLOPT_HEADERDATA, this); curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L); curl_easy_setopt(curl, CURLOPT_VERBOSE, 0L); curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, &LLMDownloader::progress_func); curl_easy_setopt(curl, CURLOPT_XFERINFODATA, this); if (resume_offset > 0) { curl_easy_setopt(curl, CURLOPT_RESUME_FROM, resume_offset); } } long LLMDownloader::determine_resume_offset() const { if (!is_download_resumable()) return 0; FILE* fp = fopen(partial_download_path().c_str(), "rb"); if (!fp) return 0; fseek(fp, 0, SEEK_END); long offset = ftell(fp); fclose(fp); return offset; } FILE* LLMDownloader::open_output_file(long resume_offset) const { return fopen(partial_download_path().c_str(), resume_offset > 0 ? "ab" : "wb"); } bool LLMDownloader::has_existing_partial_download() const { try { const auto partial_path = partial_download_path(); if (std::filesystem::exists(partial_path)) { return std::filesystem::file_size(partial_path) > 0; } if (!std::filesystem::exists(download_destination)) { return false; } if (real_content_length <= 0) { return false; } const auto final_size = std::filesystem::file_size(download_destination); return final_size > 0 && static_cast(final_size) < real_content_length; } catch (const std::filesystem::filesystem_error& e) { if (auto logger = Logger::get_logger("core_logger")) { logger->warn("Unable to inspect download destination '{}': {}", download_destination, e.what()); } return false; } } bool LLMDownloader::has_valid_content_length(const std::string& value) const { try { return std::stoll(value) > 0; } catch (const std::exception& ex) { if (auto logger = Logger::get_logger("core_logger")) { logger->warn("Invalid Content-Length header '{}': {}", value, ex.what()); } return false; } } bool LLMDownloader::server_supports_resume_locked() const { const auto ranges_it = curl_headers.find("accept-ranges"); if (ranges_it == curl_headers.end() || ranges_it->second != "bytes") { return false; } const auto length_it = curl_headers.find("content-length"); if (length_it == curl_headers.end()) { return false; } return has_valid_content_length(length_it->second); } bool LLMDownloader::is_download_resumable() const { if (!has_existing_partial_download()) { return false; } std::lock_guard lock(mutex); return server_supports_resume_locked(); } bool LLMDownloader::is_download_complete() const { try { const auto partial_path = partial_download_path(); if (std::filesystem::exists(partial_path) && std::filesystem::file_size(partial_path) > 0) { return false; } auto file_size = std::filesystem::file_size(download_destination); return static_cast(file_size) >= real_content_length; } catch (const std::filesystem::filesystem_error&) { return false; } } // bool LLMDownloader::is_download_complete() const // { // FILE* fp = fopen(download_destination.c_str(), "rb"); // if (!fp) return false; // fseek(fp, 0, SEEK_END); // long size = ftell(fp); // fclose(fp); // return size >= real_content_length; // } long long LLMDownloader::get_real_content_length() const { return real_content_length; } LLMDownloader::DownloadStatus LLMDownloader::get_local_download_status() const { std::error_code ec; const auto partial_path = partial_download_path(); const auto partial_size = std::filesystem::file_size(partial_path, ec); if (!ec && partial_size > 0) { return DownloadStatus::InProgress; } ec.clear(); const auto size = std::filesystem::file_size(download_destination, ec); if (ec || size == 0) { return DownloadStatus::NotStarted; } const auto local_size = static_cast(size); if (real_content_length > 0 && local_size < real_content_length) { return DownloadStatus::InProgress; } return DownloadStatus::Complete; } std::string LLMDownloader::get_download_destination() const { return download_destination; } std::string LLMDownloader::get_partial_download_destination() const { return partial_download_path(); } LLMDownloader::DownloadStatus LLMDownloader::get_download_status() const { const auto local_status = get_local_download_status(); if (local_status != DownloadStatus::InProgress) { return local_status; } if (!initialized) { return DownloadStatus::InProgress; } if (is_download_complete()) { return DownloadStatus::Complete; } if (is_download_resumable()) { return DownloadStatus::InProgress; } return DownloadStatus::NotStarted; } void LLMDownloader::cancel_download() { std::lock_guard lock(mutex); cancel_requested.store(true, std::memory_order_relaxed); } LLMDownloader::~LLMDownloader() { if (download_thread.joinable()) { download_thread.join(); } } void LLMDownloader::set_download_url(const std::string& new_url) { if (new_url == url) return; url = new_url; initialized = false; curl_headers.clear(); resumable = false; real_content_length = 0; resume_offset = 0; try { set_download_destination(); } catch (const std::exception& ex) { // Log errors } } std::string LLMDownloader::get_download_url() { return url; } #ifdef AI_FILE_SORTER_TEST_BUILD namespace TestHooks { void set_llm_download_probe(LLMDownloadProbe probe) { download_probe_slot() = std::move(probe); } void reset_llm_download_probe() { download_probe_slot() = LLMDownloadProbe{}; } } // namespace TestHooks void LLMDownloader::LLMDownloaderTestAccess::set_real_content_length(LLMDownloader& downloader, long long length) { downloader.real_content_length = length; } void LLMDownloader::LLMDownloaderTestAccess::set_download_destination(LLMDownloader& downloader, const std::string& path) { downloader.destination_dir = std::filesystem::path(path).parent_path().string(); downloader.download_destination = path; } void LLMDownloader::LLMDownloaderTestAccess::set_resume_headers(LLMDownloader& downloader, long long content_length) { std::lock_guard lock(downloader.mutex); downloader.curl_headers["accept-ranges"] = "bytes"; downloader.curl_headers["content-length"] = std::to_string(content_length); downloader.real_content_length = content_length; } #endif ================================================ FILE: app/lib/LLMSelectionDialog.cpp ================================================ #include "LLMSelectionDialog.hpp" #include "DialogUtils.hpp" #include "LlmCatalog.hpp" #include "ErrorMessages.hpp" #include "Settings.hpp" #include "Utils.hpp" #include "CustomLLMDialog.hpp" #include "CustomApiDialog.hpp" #ifdef AI_FILE_SORTER_TEST_BUILD #include "LLMSelectionDialogTestAccess.hpp" #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace { QString format_markup_label(const QString& title, const QString& value, const QString& color) { return QStringLiteral("%1: %3") .arg(title, color, value.toHtmlEscaped()); } long long local_file_size_or_zero(const std::string& path) { std::error_code ec; const auto size = std::filesystem::file_size(path, ec); if (ec) { return 0; } return static_cast(size); } void set_fixed_progress_width(QProgressBar* bar, int multiplier) { if (!bar || multiplier <= 0) { return; } const QSize hint = bar->sizeHint(); int base_width = hint.width(); if (base_width <= 0) { base_width = 120; } bar->setFixedWidth(base_width * multiplier); int base_height = hint.height(); if (base_height <= 0) { base_height = std::max(12, bar->fontMetrics().height()); } bar->setMinimumHeight(base_height); bar->setMaximumHeight(base_height); } void apply_progress_style(QProgressBar* bar) { if (!bar) { return; } #if defined(__APPLE__) bar->setTextVisible(false); bar->setStyleSheet(QStringLiteral( "QProgressBar {" " border: 1px solid #d0d0d0;" " border-radius: 4px;" " background: #f4f4f4;" " }" "QProgressBar::chunk {" " background-color: #0a84ff;" " border-radius: 3px;" " }")); #endif } } // namespace LLMSelectionDialog::LLMSelectionDialog(Settings& settings, QWidget* parent) : QDialog(parent) , settings(settings) , downloads_expanded_(settings.get_llm_downloads_expanded()) { setWindowTitle(tr("Choose LLM Mode")); setModal(true); setup_ui(); connect_signals(); openai_api_key = settings.get_openai_api_key(); openai_model = settings.get_openai_model(); gemini_api_key = settings.get_gemini_api_key(); gemini_model = settings.get_gemini_model(); if (openai_api_key_edit) { openai_api_key_edit->setText(QString::fromStdString(openai_api_key)); } if (openai_model_edit) { openai_model_edit->setText(QString::fromStdString(openai_model)); } if (gemini_api_key_edit) { gemini_api_key_edit->setText(QString::fromStdString(gemini_api_key)); } if (gemini_model_edit) { gemini_model_edit->setText(QString::fromStdString(gemini_model)); } selected_choice = settings.get_llm_choice(); selected_custom_id = settings.get_active_custom_llm_id(); selected_custom_api_id = settings.get_active_custom_api_id(); switch (selected_choice) { case LLMChoice::Remote_OpenAI: openai_radio->setChecked(true); break; case LLMChoice::Remote_Gemini: gemini_radio->setChecked(true); break; case LLMChoice::Remote_Custom: custom_api_radio->setChecked(true); break; case LLMChoice::Local_3b: local3_radio->setChecked(true); break; case LLMChoice::Local_3b_legacy: if (local3_legacy_radio && local3_legacy_radio->isVisible()) { local3_legacy_radio->setChecked(true); } else { local3_radio->setChecked(true); selected_choice = LLMChoice::Local_3b; } break; case LLMChoice::Local_7b: local7_radio->setChecked(true); break; case LLMChoice::Custom: custom_radio->setChecked(true); break; default: local3_radio->setChecked(true); selected_choice = LLMChoice::Local_3b; break; } refresh_custom_lists(); refresh_custom_api_lists(); if (selected_choice == LLMChoice::Custom) { select_custom_by_id(selected_custom_id); } if (selected_choice == LLMChoice::Remote_Custom) { select_custom_api_by_id(selected_custom_api_id); } update_ui_for_choice(); adjust_dialog_size(); const int min_width = 620; if (width() < min_width) { resize(min_width, height()); } } LLMSelectionDialog::~LLMSelectionDialog() { if (downloader && is_downloading.load()) { downloader->cancel_download(); } if (llava_model_download.downloader && llava_model_download.is_downloading.load()) { llava_model_download.downloader->cancel_download(); } if (llava_mmproj_download.downloader && llava_mmproj_download.is_downloading.load()) { llava_mmproj_download.downloader->cancel_download(); } } void LLMSelectionDialog::setup_ui() { auto* outer_layout = new QVBoxLayout(this); scroll_area_ = new QScrollArea(this); scroll_area_->setWidgetResizable(true); scroll_area_->setFrameShape(QFrame::NoFrame); auto* content = new QWidget(scroll_area_); auto* layout = new QVBoxLayout(content); auto* title = new QLabel(tr("Select LLM Mode"), this); title->setAlignment(Qt::AlignHCenter); layout->addWidget(title); layout->setSpacing(8); auto* radio_container = new QWidget(this); auto* radio_layout = new QVBoxLayout(radio_container); radio_layout->setSpacing(10); local7_radio = new QRadioButton(default_llm_label_for_choice(LLMChoice::Local_7b), radio_container); local7_radio->setStyleSheet(QStringLiteral("color: #1f6feb;")); auto* local7_desc = new QLabel(tr("Larger local model. Slower on CPU, but performs much better with GPU acceleration.\nSupports: Nvidia (CUDA), Apple (Metal), CPU."), radio_container); local7_desc->setWordWrap(true); local3_radio = new QRadioButton(default_llm_label_for_choice(LLMChoice::Local_3b), radio_container); local3_radio->setStyleSheet(QStringLiteral("color: #1f6feb;")); auto* local3_row = new QWidget(radio_container); auto* local3_row_layout = new QHBoxLayout(local3_row); local3_row_layout->setContentsMargins(0, 0, 0, 0); auto* local3_recommended = new QLabel(tr("Recommended"), local3_row); local3_recommended->setStyleSheet(QStringLiteral("color: #1f6feb; font-weight: 700;")); local3_row_layout->addWidget(local3_radio); local3_row_layout->addWidget(local3_recommended); local3_row_layout->addStretch(1); auto* local3_desc = new QLabel(tr("Smaller local model that works quickly even on CPUs. Good for lightweight local use."), radio_container); local3_desc->setWordWrap(true); local3_legacy_radio = new QRadioButton(default_llm_label_for_choice(LLMChoice::Local_3b_legacy), radio_container); local3_legacy_radio->setStyleSheet(QStringLiteral("color: #1f6feb;")); local3_legacy_desc = new QLabel(tr("Legacy model kept for existing downloads."), radio_container); local3_legacy_desc->setWordWrap(true); const bool has_legacy_3b = legacy_local_3b_available(); local3_legacy_radio->setVisible(has_legacy_3b); local3_legacy_desc->setVisible(has_legacy_3b); gemini_radio = new QRadioButton(tr("Gemini (Google AI Studio API key)"), radio_container); gemini_radio->setStyleSheet(QStringLiteral("color: #1f6feb;")); auto* gemini_desc = new QLabel(tr("Use Google's Gemini models with your AI Studio API key (internet required)."), radio_container); gemini_desc->setWordWrap(true); gemini_inputs = new QWidget(radio_container); auto* gemini_form = new QFormLayout(gemini_inputs); gemini_form->setContentsMargins(24, 0, 0, 0); gemini_form->setHorizontalSpacing(10); gemini_form->setVerticalSpacing(6); gemini_api_key_edit = new QLineEdit(gemini_inputs); gemini_api_key_edit->setEchoMode(QLineEdit::Password); gemini_api_key_edit->setClearButtonEnabled(true); gemini_api_key_edit->setPlaceholderText(tr("AIza...")); show_gemini_api_key_checkbox = new QCheckBox(tr("Show"), gemini_inputs); auto* gemini_key_row = new QWidget(gemini_inputs); auto* gemini_key_layout = new QHBoxLayout(gemini_key_row); gemini_key_layout->setContentsMargins(0, 0, 0, 0); gemini_key_layout->addWidget(gemini_api_key_edit, 1); gemini_key_layout->addWidget(show_gemini_api_key_checkbox); auto* gemini_key_label = new QLabel(tr("Gemini API key"), gemini_inputs); gemini_key_label->setStyleSheet(QStringLiteral("color: #1f6feb;")); gemini_form->addRow(gemini_key_label, gemini_key_row); gemini_model_edit = new QLineEdit(gemini_inputs); gemini_model_edit->setPlaceholderText(tr("e.g. gemini-2.5-flash-lite, gemini-2.5-flash, gemini-2.5-pro")); auto* gemini_model_label = new QLabel(tr("Model"), gemini_inputs); gemini_model_label->setStyleSheet(QStringLiteral("color: #1f6feb;")); gemini_form->addRow(gemini_model_label, gemini_model_edit); gemini_help_label = new QLabel(tr("Your key is stored locally in the config file for this device."), gemini_inputs); gemini_help_label->setWordWrap(true); gemini_form->addRow(gemini_help_label); gemini_link_label = new QLabel(gemini_inputs); gemini_link_label->setTextFormat(Qt::RichText); gemini_link_label->setTextInteractionFlags(Qt::TextBrowserInteraction); gemini_link_label->setOpenExternalLinks(true); gemini_link_label->setText(tr("Get a Gemini API key")); gemini_form->addRow(gemini_link_label); gemini_inputs->setVisible(false); openai_radio = new QRadioButton(tr("ChatGPT (OpenAI API key)"), radio_container); openai_radio->setStyleSheet(QStringLiteral("color: #1f6feb;")); auto* openai_desc = new QLabel(tr("Use your own OpenAI API key to access ChatGPT models (internet required)."), radio_container); openai_desc->setWordWrap(true); openai_inputs = new QWidget(radio_container); auto* openai_form = new QFormLayout(openai_inputs); openai_form->setContentsMargins(24, 0, 0, 0); openai_form->setHorizontalSpacing(10); openai_form->setVerticalSpacing(6); openai_api_key_edit = new QLineEdit(openai_inputs); openai_api_key_edit->setEchoMode(QLineEdit::Password); openai_api_key_edit->setClearButtonEnabled(true); openai_api_key_edit->setPlaceholderText(tr("sk-...")); show_openai_api_key_checkbox = new QCheckBox(tr("Show"), openai_inputs); auto* openai_key_row = new QWidget(openai_inputs); auto* openai_key_layout = new QHBoxLayout(openai_key_row); openai_key_layout->setContentsMargins(0, 0, 0, 0); openai_key_layout->addWidget(openai_api_key_edit, 1); openai_key_layout->addWidget(show_openai_api_key_checkbox); auto* openai_key_label = new QLabel(tr("OpenAI API key"), openai_inputs); openai_key_label->setStyleSheet(QStringLiteral("color: #1f6feb;")); openai_form->addRow(openai_key_label, openai_key_row); openai_model_edit = new QLineEdit(openai_inputs); openai_model_edit->setPlaceholderText( tr("e.g. gpt-4o-mini, gpt-4.1, o3-mini")); auto* openai_model_label = new QLabel(tr("Model"), openai_inputs); openai_model_label->setStyleSheet(QStringLiteral("color: #1f6feb;")); openai_form->addRow(openai_model_label, openai_model_edit); openai_help_label = new QLabel( tr("Your key is stored locally in the config file for this device."), openai_inputs); openai_help_label->setWordWrap(true); openai_form->addRow(openai_help_label); openai_link_label = new QLabel(openai_inputs); openai_link_label->setTextFormat(Qt::RichText); openai_link_label->setTextInteractionFlags(Qt::TextBrowserInteraction); openai_link_label->setOpenExternalLinks(true); openai_link_label->setText( tr("Get an OpenAI API key")); openai_form->addRow(openai_link_label); openai_inputs->setVisible(false); custom_api_radio = new QRadioButton( tr("Custom OpenAI-compatible API (advanced)"), radio_container); custom_api_radio->setStyleSheet(QStringLiteral("color: #1f6feb;")); auto* custom_api_desc = new QLabel( tr("Use OpenAI-compatible endpoints such as LM Studio or Ollama (local or remote)."), radio_container); custom_api_desc->setWordWrap(true); auto* custom_api_row = new QWidget(radio_container); auto* custom_api_layout = new QHBoxLayout(custom_api_row); custom_api_layout->setContentsMargins(24, 0, 0, 0); custom_api_combo = new QComboBox(custom_api_row); custom_api_combo->setMinimumContentsLength(10); custom_api_combo->setSizeAdjustPolicy(QComboBox::AdjustToContents); custom_api_combo->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); custom_api_combo->setFixedWidth(360); add_custom_api_button = new QPushButton(tr("Add…"), custom_api_row); edit_custom_api_button = new QPushButton(tr("Edit…"), custom_api_row); delete_custom_api_button = new QPushButton(tr("Delete"), custom_api_row); add_custom_api_button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); edit_custom_api_button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); delete_custom_api_button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); custom_api_layout->addWidget(custom_api_combo); custom_api_layout->addWidget(add_custom_api_button); custom_api_layout->addWidget(edit_custom_api_button); custom_api_layout->addWidget(delete_custom_api_button); custom_api_layout->addStretch(1); custom_radio = new QRadioButton( tr("Custom local LLM (gguf)"), radio_container); custom_radio->setStyleSheet(QStringLiteral("color: #1f6feb;")); auto* custom_row = new QWidget(radio_container); auto* custom_layout = new QHBoxLayout(custom_row); custom_layout->setContentsMargins(24, 0, 0, 0); custom_combo = new QComboBox(custom_row); custom_combo->setMinimumContentsLength(10); custom_combo->setSizeAdjustPolicy(QComboBox::AdjustToContents); custom_combo->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); custom_combo->setFixedWidth(360); add_custom_button = new QPushButton(tr("Add…"), custom_row); edit_custom_button = new QPushButton(tr("Edit…"), custom_row); delete_custom_button = new QPushButton(tr("Delete"), custom_row); add_custom_button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); edit_custom_button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); delete_custom_button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); custom_layout->addWidget(custom_combo); custom_layout->addWidget(add_custom_button); custom_layout->addWidget(edit_custom_button); custom_layout->addWidget(delete_custom_button); custom_layout->addStretch(1); radio_layout->addWidget(local3_row); radio_layout->addWidget(local3_desc); radio_layout->addWidget(local7_radio); radio_layout->addWidget(local7_desc); radio_layout->addWidget(local3_legacy_radio); radio_layout->addWidget(local3_legacy_desc); radio_layout->addWidget(gemini_radio); radio_layout->addWidget(gemini_desc); radio_layout->addWidget(gemini_inputs); radio_layout->addWidget(openai_radio); radio_layout->addWidget(openai_desc); radio_layout->addWidget(openai_inputs); radio_layout->addWidget(custom_api_radio); radio_layout->addWidget(custom_api_desc); radio_layout->addWidget(custom_api_row); radio_layout->addWidget(custom_radio); radio_layout->addWidget(custom_row); auto* llm_group = new QButtonGroup(this); llm_group->setExclusive(true); llm_group->addButton(openai_radio); llm_group->addButton(gemini_radio); llm_group->addButton(custom_api_radio); llm_group->addButton(local3_radio); if (local3_legacy_radio) { llm_group->addButton(local3_legacy_radio); } llm_group->addButton(local7_radio); llm_group->addButton(custom_radio); layout->addWidget(radio_container); download_toggle_button = new QToolButton(this); download_toggle_button->setText(tr("Downloads")); download_toggle_button->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); download_toggle_button->setArrowType(Qt::RightArrow); download_toggle_button->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); download_toggle_button->setLayoutDirection(Qt::LeftToRight); download_toggle_button->setCheckable(true); download_toggle_button->setChecked(downloads_expanded_); download_toggle_button->setArrowType(downloads_expanded_ ? Qt::DownArrow : Qt::RightArrow); download_toggle_button->setStyleSheet(QStringLiteral("color: #1f6feb; font-weight: 600;")); auto* downloads_toggle_row = new QWidget(this); auto* downloads_toggle_layout = new QHBoxLayout(downloads_toggle_row); downloads_toggle_layout->setContentsMargins(0, 0, 0, 0); downloads_toggle_layout->addWidget(download_toggle_button); downloads_toggle_layout->addStretch(1); layout->addWidget(downloads_toggle_row); downloads_container = new QWidget(this); auto* downloads_layout = new QVBoxLayout(downloads_container); downloads_layout->setContentsMargins(0, 0, 0, 0); downloads_layout->setSpacing(10); download_section = new QWidget(downloads_container); auto* download_layout = new QVBoxLayout(download_section); download_layout->setSpacing(6); remote_url_label = new QLabel(download_section); remote_url_label->setTextInteractionFlags(Qt::TextSelectableByMouse); local_path_label = new QLabel(download_section); local_path_label->setTextInteractionFlags(Qt::TextSelectableByMouse); file_size_label = new QLabel(download_section); file_size_label->setTextInteractionFlags(Qt::TextSelectableByMouse); status_label = new QLabel(download_section); status_label->setTextInteractionFlags(Qt::TextSelectableByMouse); progress_bar = new QProgressBar(download_section); progress_bar->setRange(0, 100); progress_bar->setValue(0); progress_bar->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); set_fixed_progress_width(progress_bar, 3); apply_progress_style(progress_bar); progress_bar->setVisible(false); download_button = new QPushButton(tr("Download"), download_section); download_button->setEnabled(false); delete_download_button = new QPushButton(tr("Delete"), download_section); delete_download_button->setEnabled(false); auto* download_actions = new QWidget(download_section); auto* download_actions_layout = new QHBoxLayout(download_actions); download_actions_layout->setContentsMargins(0, 0, 0, 0); download_actions_layout->setSpacing(8); download_actions_layout->addWidget(download_button); download_actions_layout->addWidget(delete_download_button); download_actions_layout->addStretch(1); download_layout->addWidget(remote_url_label); download_layout->addWidget(local_path_label); download_layout->addWidget(file_size_label); download_layout->addWidget(status_label); download_layout->addWidget(progress_bar); download_layout->addWidget(download_actions, 0, Qt::AlignLeft); downloads_layout->addWidget(download_section); download_section->setVisible(false); visual_llm_download_section = new QGroupBox(tr("Image analysis models (LLaVA)"), downloads_container); auto* visual_layout = new QVBoxLayout(visual_llm_download_section); auto* visual_hint = new QLabel(tr("Download the visual LLM files required for image analysis."), visual_llm_download_section); visual_hint->setWordWrap(true); visual_layout->addWidget(visual_hint); setup_visual_llm_download_entry(llava_model_download, visual_llm_download_section, tr("LLaVA 1.6 Mistral 7B (text model)"), "LLAVA_MODEL_URL"); visual_layout->addWidget(llava_model_download.container); setup_visual_llm_download_entry(llava_mmproj_download, visual_llm_download_section, tr("LLaVA mmproj (vision encoder)"), "LLAVA_MMPROJ_URL"); visual_layout->addWidget(llava_mmproj_download.container); downloads_layout->addWidget(visual_llm_download_section); layout->addWidget(downloads_container); downloads_container->setVisible(false); button_box = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); ok_button = button_box->button(QDialogButtonBox::Ok); scroll_area_->setWidget(content); outer_layout->addWidget(scroll_area_); outer_layout->addWidget(button_box); } void LLMSelectionDialog::connect_signals() { auto update_handler = [this]() { update_ui_for_choice(); }; connect(openai_radio, &QRadioButton::toggled, this, update_handler); connect(gemini_radio, &QRadioButton::toggled, this, update_handler); connect(custom_api_radio, &QRadioButton::toggled, this, update_handler); connect(local3_radio, &QRadioButton::toggled, this, update_handler); if (local3_legacy_radio) { connect(local3_legacy_radio, &QRadioButton::toggled, this, update_handler); } connect(local7_radio, &QRadioButton::toggled, this, update_handler); connect(custom_radio, &QRadioButton::toggled, this, update_handler); connect(custom_combo, &QComboBox::currentTextChanged, this, update_handler); connect(custom_api_combo, &QComboBox::currentTextChanged, this, update_handler); connect(openai_api_key_edit, &QLineEdit::textChanged, this, update_handler); connect(openai_model_edit, &QLineEdit::textChanged, this, update_handler); connect(gemini_api_key_edit, &QLineEdit::textChanged, this, update_handler); connect(gemini_model_edit, &QLineEdit::textChanged, this, update_handler); connect(add_custom_button, &QPushButton::clicked, this, &LLMSelectionDialog::handle_add_custom); connect(edit_custom_button, &QPushButton::clicked, this, &LLMSelectionDialog::handle_edit_custom); connect(delete_custom_button, &QPushButton::clicked, this, &LLMSelectionDialog::handle_delete_custom); connect(add_custom_api_button, &QPushButton::clicked, this, &LLMSelectionDialog::handle_add_custom_api); connect(edit_custom_api_button, &QPushButton::clicked, this, &LLMSelectionDialog::handle_edit_custom_api); connect(delete_custom_api_button, &QPushButton::clicked, this, &LLMSelectionDialog::handle_delete_custom_api); if (delete_download_button) { connect(delete_download_button, &QPushButton::clicked, this, &LLMSelectionDialog::handle_delete_download); } if (download_toggle_button) { connect(download_toggle_button, &QToolButton::toggled, this, [this](bool checked) { downloads_expanded_ = checked; if (downloads_container) { downloads_container->setVisible(checked); } download_toggle_button->setArrowType(checked ? Qt::DownArrow : Qt::RightArrow); adjust_dialog_size(); }); } if (show_openai_api_key_checkbox) { connect(show_openai_api_key_checkbox, &QCheckBox::toggled, this, [this](bool checked) { if (openai_api_key_edit) { openai_api_key_edit->setEchoMode(checked ? QLineEdit::Normal : QLineEdit::Password); } }); } if (show_gemini_api_key_checkbox) { connect(show_gemini_api_key_checkbox, &QCheckBox::toggled, this, [this](bool checked) { if (gemini_api_key_edit) { gemini_api_key_edit->setEchoMode(checked ? QLineEdit::Normal : QLineEdit::Password); } }); } connect(download_button, &QPushButton::clicked, this, &LLMSelectionDialog::start_download); if (llava_model_download.download_button) { connect(llava_model_download.download_button, &QPushButton::clicked, this, [this]() { start_visual_llm_download(llava_model_download); }); } if (llava_mmproj_download.download_button) { connect(llava_mmproj_download.download_button, &QPushButton::clicked, this, [this]() { start_visual_llm_download(llava_mmproj_download); }); } connect(button_box, &QDialogButtonBox::accepted, this, &LLMSelectionDialog::accept); connect(button_box, &QDialogButtonBox::rejected, this, &LLMSelectionDialog::reject); } void LLMSelectionDialog::showEvent(QShowEvent* event) { QDialog::showEvent(event); QTimer::singleShot(0, this, [this]() { adjust_dialog_size(); }); } LLMChoice LLMSelectionDialog::get_selected_llm_choice() const { return selected_choice; } std::string LLMSelectionDialog::get_selected_custom_llm_id() const { return selected_custom_id; } std::string LLMSelectionDialog::get_selected_custom_api_id() const { return selected_custom_api_id; } std::string LLMSelectionDialog::get_openai_api_key() const { return openai_api_key; } std::string LLMSelectionDialog::get_openai_model() const { return openai_model; } std::string LLMSelectionDialog::get_gemini_api_key() const { return gemini_api_key; } std::string LLMSelectionDialog::get_gemini_model() const { return gemini_model; } bool LLMSelectionDialog::get_llm_downloads_expanded() const { return downloads_expanded_; } void LLMSelectionDialog::set_status_message(const QString& message) { status_label->setText(message); } bool LLMSelectionDialog::legacy_local_3b_available() const { const char* env_url = std::getenv("LOCAL_LLM_3B_LEGACY_DOWNLOAD_URL"); if (!env_url || *env_url == '\0') { return false; } std::string path; try { path = Utils::make_default_path_to_file_from_download_url(env_url); } catch (...) { return false; } std::error_code ec; return !path.empty() && std::filesystem::exists(path, ec); } void LLMSelectionDialog::update_legacy_local_3b_visibility() { if (!local3_legacy_radio || !local3_legacy_desc) { return; } const bool available = legacy_local_3b_available(); local3_legacy_radio->setVisible(available); local3_legacy_desc->setVisible(available); if (!available && local3_legacy_radio->isChecked() && local3_radio) { local3_radio->setChecked(true); } } void LLMSelectionDialog::update_ui_for_choice() { update_legacy_local_3b_visibility(); update_custom_buttons(); update_custom_api_buttons(); update_radio_selection(); update_custom_choice_ui(); update_custom_api_choice_ui(); update_visual_llm_downloads(); const bool is_local_builtin = (selected_choice == LLMChoice::Local_3b || selected_choice == LLMChoice::Local_3b_legacy || selected_choice == LLMChoice::Local_7b); if (selected_choice == LLMChoice::Custom || is_remote_choice(selected_choice) || !is_local_builtin) { return; } update_local_choice_ui(); } void LLMSelectionDialog::update_radio_selection() { if (openai_radio->isChecked()) { selected_choice = LLMChoice::Remote_OpenAI; } else if (gemini_radio->isChecked()) { selected_choice = LLMChoice::Remote_Gemini; } else if (custom_api_radio->isChecked()) { selected_choice = LLMChoice::Remote_Custom; } else if (local3_legacy_radio && local3_legacy_radio->isChecked()) { selected_choice = LLMChoice::Local_3b_legacy; } else if (local3_radio->isChecked()) { selected_choice = LLMChoice::Local_3b; } else if (local7_radio->isChecked()) { selected_choice = LLMChoice::Local_7b; } else if (custom_radio->isChecked()) { selected_choice = LLMChoice::Custom; } } void LLMSelectionDialog::update_custom_choice_ui() { if (!ok_button && button_box) { ok_button = button_box->button(QDialogButtonBox::Ok); } const bool is_local_builtin = (selected_choice == LLMChoice::Local_3b || selected_choice == LLMChoice::Local_3b_legacy || selected_choice == LLMChoice::Local_7b); const bool is_remote_openai = selected_choice == LLMChoice::Remote_OpenAI; const bool is_remote_gemini = selected_choice == LLMChoice::Remote_Gemini; const bool is_remote_custom = selected_choice == LLMChoice::Remote_Custom; const bool is_custom = selected_choice == LLMChoice::Custom; if (download_toggle_button) { download_toggle_button->setVisible(is_local_builtin); } if (downloads_container) { const bool show_downloads = is_local_builtin && download_toggle_button && download_toggle_button->isChecked(); downloads_container->setVisible(show_downloads); } download_section->setVisible(is_local_builtin); adjust_dialog_size(); if (openai_inputs) { openai_inputs->setVisible(is_remote_openai); openai_inputs->setEnabled(is_remote_openai); } if (gemini_inputs) { gemini_inputs->setVisible(is_remote_gemini); gemini_inputs->setEnabled(is_remote_gemini); } custom_combo->setEnabled(is_custom); edit_custom_button->setEnabled(is_custom && custom_combo->currentIndex() >= 0 && custom_combo->count() > 0); delete_custom_button->setEnabled(is_custom && custom_combo->currentIndex() >= 0 && custom_combo->count() > 0); if (is_custom) { if (custom_combo->currentIndex() >= 0) { selected_custom_id = custom_combo->currentData().toString().toStdString(); } else { selected_custom_id.clear(); } if (ok_button) ok_button->setEnabled(!selected_custom_id.empty()); progress_bar->setVisible(false); download_button->setVisible(false); set_status_message(selected_custom_id.empty() ? tr("Choose or add a custom model.") : tr("Custom model selected.")); return; } if (is_remote_custom) { return; } if (is_remote_openai) { update_openai_fields_state(); return; } if (is_remote_gemini) { update_gemini_fields_state(); return; } if (!is_local_builtin) { if (ok_button) ok_button->setEnabled(true); progress_bar->setVisible(false); download_button->setVisible(false); set_status_message(tr("Selection ready.")); return; } } void LLMSelectionDialog::update_custom_api_choice_ui() { if (!ok_button && button_box) { ok_button = button_box->button(QDialogButtonBox::Ok); } const bool is_custom_api = selected_choice == LLMChoice::Remote_Custom; if (custom_api_combo) { custom_api_combo->setEnabled(is_custom_api); } if (edit_custom_api_button) { edit_custom_api_button->setEnabled(is_custom_api && custom_api_combo && custom_api_combo->currentIndex() >= 0 && custom_api_combo->count() > 0); } if (delete_custom_api_button) { delete_custom_api_button->setEnabled(is_custom_api && custom_api_combo && custom_api_combo->currentIndex() >= 0 && custom_api_combo->count() > 0); } if (!is_custom_api) { return; } if (custom_api_combo && custom_api_combo->currentIndex() >= 0) { selected_custom_api_id = custom_api_combo->currentData().toString().toStdString(); } else { selected_custom_api_id.clear(); } if (ok_button) { ok_button->setEnabled(!selected_custom_api_id.empty()); } if (progress_bar) { progress_bar->setVisible(false); } if (download_button) { download_button->setVisible(false); } set_status_message(selected_custom_api_id.empty() ? tr("Choose or add a custom API endpoint.") : tr("Custom API selected.")); } void LLMSelectionDialog::update_openai_fields_state() { if (!ok_button && button_box) { ok_button = button_box->button(QDialogButtonBox::Ok); } const bool is_openai = selected_choice == LLMChoice::Remote_OpenAI; if (openai_inputs) { openai_inputs->setVisible(is_openai); } bool valid = false; if (is_openai) { openai_api_key = openai_api_key_edit ? openai_api_key_edit->text().trimmed().toStdString() : std::string(); openai_model = openai_model_edit ? openai_model_edit->text().trimmed().toStdString() : std::string(); valid = openai_inputs_valid(); set_status_message(valid ? tr("ChatGPT will use your API key and model.") : tr("Enter your OpenAI API key and model to continue.")); } if (ok_button) { ok_button->setEnabled(valid); } if (progress_bar) { progress_bar->setVisible(false); } if (download_button) { download_button->setVisible(false); download_button->setEnabled(false); } } void LLMSelectionDialog::update_gemini_fields_state() { if (!ok_button && button_box) { ok_button = button_box->button(QDialogButtonBox::Ok); } const bool is_gemini = selected_choice == LLMChoice::Remote_Gemini; if (gemini_inputs) { gemini_inputs->setVisible(is_gemini); } bool valid = false; if (is_gemini) { gemini_api_key = gemini_api_key_edit ? gemini_api_key_edit->text().trimmed().toStdString() : std::string(); gemini_model = gemini_model_edit ? gemini_model_edit->text().trimmed().toStdString() : std::string(); valid = gemini_inputs_valid(); set_status_message(valid ? tr("Gemini will use your API key and model.") : tr("Enter your Gemini API key and model to continue.")); } if (ok_button) { ok_button->setEnabled(valid); } if (progress_bar) { progress_bar->setVisible(false); } if (download_button) { download_button->setVisible(false); download_button->setEnabled(false); } } bool LLMSelectionDialog::openai_inputs_valid() const { const QString key_text = openai_api_key_edit ? openai_api_key_edit->text().trimmed() : QString(); const QString model_text = openai_model_edit ? openai_model_edit->text().trimmed() : QString(); return !key_text.isEmpty() && !model_text.isEmpty(); } bool LLMSelectionDialog::gemini_inputs_valid() const { const QString key_text = gemini_api_key_edit ? gemini_api_key_edit->text().trimmed() : QString(); const QString model_text = gemini_model_edit ? gemini_model_edit->text().trimmed() : QString(); return !key_text.isEmpty() && !model_text.isEmpty(); } void LLMSelectionDialog::update_local_choice_ui() { if (!ok_button && button_box) { ok_button = button_box->button(QDialogButtonBox::Ok); } refresh_downloader(); if (!downloader) { if (ok_button) ok_button->setEnabled(false); download_button->setEnabled(false); return; } update_download_info(); const auto status = downloader->get_download_status(); switch (status) { case LLMDownloader::DownloadStatus::Complete: progress_bar->setVisible(true); progress_bar->setValue(100); download_button->setEnabled(false); download_button->setVisible(false); if (delete_download_button) { delete_download_button->setVisible(true); delete_download_button->setEnabled(true); } if (ok_button) { ok_button->setEnabled(true); } set_status_message(tr("Model ready.")); break; case LLMDownloader::DownloadStatus::InProgress: progress_bar->setVisible(true); download_button->setVisible(true); download_button->setEnabled(!is_downloading.load()); download_button->setText(tr("Resume download")); if (delete_download_button) { delete_download_button->setVisible(true); delete_download_button->setEnabled(true); } if (ok_button) { ok_button->setEnabled(false); } set_status_message(tr("Partial download detected. You can resume.")); break; case LLMDownloader::DownloadStatus::NotStarted: default: progress_bar->setVisible(false); progress_bar->setValue(0); download_button->setVisible(true); download_button->setEnabled(!is_downloading.load()); download_button->setText(tr("Download")); if (delete_download_button) { delete_download_button->setVisible(true); delete_download_button->setEnabled(false); } if (ok_button) { ok_button->setEnabled(false); } set_status_message(tr("Download required.")); break; } } void LLMSelectionDialog::refresh_downloader() { const std::string env_var = current_download_env_var(); if (env_var.empty()) { downloader.reset(); set_status_message(tr("Unsupported LLM selection.")); return; } const char* env_url = std::getenv(env_var.c_str()); if (!env_url) { downloader.reset(); set_status_message(tr("Missing download URL environment variable (%1)." ).arg(QString::fromStdString(env_var))); return; } if (!downloader) { downloader = std::make_unique(env_url); } else { downloader->set_download_url(env_url); } if (downloader->get_local_download_status() == LLMDownloader::DownloadStatus::InProgress) { try { downloader->init_if_needed(); } catch (const std::exception& ex) { set_status_message(QString::fromStdString(ex.what())); downloader.reset(); } } } void LLMSelectionDialog::handle_delete_download() { if (!downloader) { return; } const std::string path = downloader->get_download_destination(); if (path.empty()) { return; } const QString model_label = default_llm_label_for_choice(selected_choice); const QString title = tr("Delete downloaded model?"); const QString prompt = tr("Delete the downloaded model %1?").arg(model_label); const auto answer = QMessageBox::question(this, title, prompt, QMessageBox::Yes | QMessageBox::No); if (answer != QMessageBox::Yes) { return; } downloader->cancel_download(); is_downloading.store(false); std::error_code ec; bool removed_any = false; if (std::filesystem::exists(path, ec)) { removed_any = std::filesystem::remove(path, ec) || removed_any; } const std::string partial_path = downloader->get_partial_download_destination(); if (std::filesystem::exists(partial_path, ec)) { removed_any = std::filesystem::remove(partial_path, ec) || removed_any; } const std::string meta_path = path + ".aifs.meta"; if (std::filesystem::exists(meta_path, ec)) { removed_any = std::filesystem::remove(meta_path, ec) || removed_any; } if (ec) { set_status_message(tr("Failed to delete downloaded model.")); } else if (removed_any) { set_status_message(tr("Deleted downloaded model.")); } else { set_status_message(tr("No downloaded model found to delete.")); } refresh_downloader(); update_download_info(); update_local_choice_ui(); } void LLMSelectionDialog::update_download_info() { if (!downloader) { return; } remote_url_label->setText(format_markup_label(tr("Remote URL"), QString::fromStdString(downloader->get_download_url()), QStringLiteral("#1565c0"))); local_path_label->setText(format_markup_label(tr("Local path"), QString::fromStdString(downloader->get_download_destination()), QStringLiteral("#2e7d32"))); long long size = downloader->get_real_content_length(); if (size <= 0 && downloader->get_local_download_status() == LLMDownloader::DownloadStatus::Complete) { size = local_file_size_or_zero(downloader->get_download_destination()); } if (size > 0) { file_size_label->setText(format_markup_label(tr("File size"), QString::fromStdString(Utils::format_size(size)), QStringLiteral("#333"))); } else { file_size_label->setText(tr("File size: unknown")); } } void LLMSelectionDialog::refresh_custom_lists() { if (!custom_combo) { return; } custom_combo->blockSignals(true); custom_combo->clear(); for (const auto& entry : settings.get_custom_llms()) { custom_combo->addItem(QString::fromStdString(entry.name), QString::fromStdString(entry.id)); } if (!selected_custom_id.empty()) { select_custom_by_id(selected_custom_id); } else if (custom_combo->count() > 0) { custom_combo->setCurrentIndex(0); selected_custom_id = custom_combo->currentData().toString().toStdString(); } custom_combo->blockSignals(false); update_custom_buttons(); } void LLMSelectionDialog::refresh_custom_api_lists() { if (!custom_api_combo) { return; } custom_api_combo->blockSignals(true); custom_api_combo->clear(); for (const auto& entry : settings.get_custom_api_endpoints()) { custom_api_combo->addItem(QString::fromStdString(entry.name), QString::fromStdString(entry.id)); } if (!selected_custom_api_id.empty()) { select_custom_api_by_id(selected_custom_api_id); } else if (custom_api_combo->count() > 0) { custom_api_combo->setCurrentIndex(0); selected_custom_api_id = custom_api_combo->currentData().toString().toStdString(); } custom_api_combo->blockSignals(false); update_custom_api_buttons(); } void LLMSelectionDialog::select_custom_by_id(const std::string& id) { for (int i = 0; i < custom_combo->count(); ++i) { if (custom_combo->itemData(i).toString().toStdString() == id) { custom_combo->setCurrentIndex(i); return; } } if (custom_combo->count() > 0) { custom_combo->setCurrentIndex(0); } } void LLMSelectionDialog::select_custom_api_by_id(const std::string& id) { if (!custom_api_combo) { return; } for (int i = 0; i < custom_api_combo->count(); ++i) { if (custom_api_combo->itemData(i).toString().toStdString() == id) { custom_api_combo->setCurrentIndex(i); return; } } if (custom_api_combo->count() > 0) { custom_api_combo->setCurrentIndex(0); } } void LLMSelectionDialog::handle_add_custom() { CustomLLMDialog editor(this); if (editor.exec() != QDialog::Accepted) { return; } CustomLLM entry = editor.result(); selected_custom_id = settings.upsert_custom_llm(entry); refresh_custom_lists(); select_custom_by_id(selected_custom_id); custom_radio->setChecked(true); update_ui_for_choice(); } void LLMSelectionDialog::handle_add_custom_api() { CustomApiDialog editor(this); if (editor.exec() != QDialog::Accepted) { return; } CustomApiEndpoint entry = editor.result(); selected_custom_api_id = settings.upsert_custom_api_endpoint(entry); refresh_custom_api_lists(); select_custom_api_by_id(selected_custom_api_id); custom_api_radio->setChecked(true); update_ui_for_choice(); } void LLMSelectionDialog::handle_edit_custom() { if (!custom_combo || custom_combo->currentIndex() < 0) { return; } const std::string id = custom_combo->currentData().toString().toStdString(); CustomLLM entry = settings.find_custom_llm(id); if (entry.id.empty()) { return; } CustomLLMDialog editor(this, entry); if (editor.exec() != QDialog::Accepted) { return; } CustomLLM updated = editor.result(); updated.id = entry.id; selected_custom_id = settings.upsert_custom_llm(updated); refresh_custom_lists(); select_custom_by_id(selected_custom_id); custom_radio->setChecked(true); update_ui_for_choice(); } void LLMSelectionDialog::handle_edit_custom_api() { if (!custom_api_combo || custom_api_combo->currentIndex() < 0) { return; } const std::string id = custom_api_combo->currentData().toString().toStdString(); CustomApiEndpoint entry = settings.find_custom_api_endpoint(id); if (entry.id.empty()) { return; } CustomApiDialog editor(this, entry); if (editor.exec() != QDialog::Accepted) { return; } CustomApiEndpoint updated = editor.result(); updated.id = entry.id; selected_custom_api_id = settings.upsert_custom_api_endpoint(updated); refresh_custom_api_lists(); select_custom_api_by_id(selected_custom_api_id); custom_api_radio->setChecked(true); update_ui_for_choice(); } void LLMSelectionDialog::handle_delete_custom() { if (!custom_combo || custom_combo->currentIndex() < 0) { return; } const std::string id = custom_combo->currentData().toString().toStdString(); const QString name = custom_combo->currentText(); const auto response = QMessageBox::question(this, tr("Delete custom model"), tr("Remove '%1' from your custom LLMs? This does not delete the file on disk.") .arg(name)); if (response != QMessageBox::Yes) { return; } settings.remove_custom_llm(id); if (selected_custom_id == id) { selected_custom_id.clear(); } refresh_custom_lists(); custom_radio->setChecked(custom_combo->count() > 0); update_ui_for_choice(); } void LLMSelectionDialog::handle_delete_custom_api() { if (!custom_api_combo || custom_api_combo->currentIndex() < 0) { return; } const std::string id = custom_api_combo->currentData().toString().toStdString(); const QString name = custom_api_combo->currentText(); const auto response = QMessageBox::question(this, tr("Delete custom API"), tr("Remove '%1' from your custom API list? This does not affect the server.") .arg(name)); if (response != QMessageBox::Yes) { return; } settings.remove_custom_api_endpoint(id); if (selected_custom_api_id == id) { selected_custom_api_id.clear(); } refresh_custom_api_lists(); custom_api_radio->setChecked(custom_api_combo->count() > 0); update_ui_for_choice(); } void LLMSelectionDialog::update_custom_buttons() { const bool has_selection = custom_combo && custom_combo->currentIndex() >= 0 && custom_combo->count() > 0; if (edit_custom_button) { edit_custom_button->setEnabled(has_selection && custom_radio->isChecked()); } if (delete_custom_button) { delete_custom_button->setEnabled(has_selection && custom_radio->isChecked()); } } void LLMSelectionDialog::update_custom_api_buttons() { const bool has_selection = custom_api_combo && custom_api_combo->currentIndex() >= 0 && custom_api_combo->count() > 0; if (edit_custom_api_button) { edit_custom_api_button->setEnabled(has_selection && custom_api_radio->isChecked()); } if (delete_custom_api_button) { delete_custom_api_button->setEnabled(has_selection && custom_api_radio->isChecked()); } } void LLMSelectionDialog::setup_visual_llm_download_entry(VisualLlmDownloadEntry& entry, QWidget* parent, const QString& title, const std::string& env_var) { entry.env_var = env_var; entry.display_name = title.toStdString(); auto* group = new QGroupBox(title, parent); entry.container = group; auto* entry_layout = new QVBoxLayout(group); entry_layout->setSpacing(6); entry.remote_url_label = new QLabel(group); entry.remote_url_label->setTextInteractionFlags(Qt::TextSelectableByMouse); entry.local_path_label = new QLabel(group); entry.local_path_label->setTextInteractionFlags(Qt::TextSelectableByMouse); entry.file_size_label = new QLabel(group); entry.file_size_label->setTextInteractionFlags(Qt::TextSelectableByMouse); entry.status_label = new QLabel(group); entry.status_label->setTextInteractionFlags(Qt::TextSelectableByMouse); entry.progress_bar = new QProgressBar(group); entry.progress_bar->setRange(0, 100); entry.progress_bar->setValue(0); entry.progress_bar->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); set_fixed_progress_width(entry.progress_bar, 3); apply_progress_style(entry.progress_bar); entry.progress_bar->setVisible(false); entry.download_button = new QPushButton(tr("Download"), group); entry.download_button->setEnabled(false); entry.delete_button = new QPushButton(tr("Delete"), group); entry.delete_button->setEnabled(false); auto* action_row = new QWidget(group); auto* action_layout = new QHBoxLayout(action_row); action_layout->setContentsMargins(0, 0, 0, 0); action_layout->setSpacing(8); action_layout->addWidget(entry.download_button); action_layout->addWidget(entry.delete_button); action_layout->addStretch(1); entry_layout->addWidget(entry.remote_url_label); entry_layout->addWidget(entry.local_path_label); entry_layout->addWidget(entry.file_size_label); entry_layout->addWidget(entry.status_label); entry_layout->addWidget(entry.progress_bar); entry_layout->addWidget(action_row, 0, Qt::AlignLeft); if (entry.delete_button) { auto* entry_ptr = &entry; connect(entry.delete_button, &QPushButton::clicked, this, [this, entry_ptr]() { handle_delete_visual_download(*entry_ptr); }); } } void LLMSelectionDialog::set_visual_status_message(VisualLlmDownloadEntry& entry, const QString& message) { if (entry.status_label) { entry.status_label->setText(message); } } void LLMSelectionDialog::refresh_visual_llm_download_entry(VisualLlmDownloadEntry& entry) { if (entry.env_var.empty()) { entry.downloader.reset(); set_visual_status_message(entry, tr("Missing download URL environment variable.")); if (entry.download_button) { entry.download_button->setEnabled(false); } return; } const char* env_url = std::getenv(entry.env_var.c_str()); if (!env_url) { entry.downloader.reset(); set_visual_status_message(entry, tr("Missing download URL environment variable (%1).") .arg(QString::fromStdString(entry.env_var))); if (entry.download_button) { entry.download_button->setEnabled(false); } return; } if (!entry.downloader) { entry.downloader = std::make_unique(env_url); } else { entry.downloader->set_download_url(env_url); } if (entry.downloader->get_local_download_status() == LLMDownloader::DownloadStatus::InProgress) { try { entry.downloader->init_if_needed(); } catch (const std::exception& ex) { set_visual_status_message(entry, QString::fromStdString(ex.what())); entry.downloader.reset(); } } } void LLMSelectionDialog::update_visual_llm_download_entry(VisualLlmDownloadEntry& entry) { if (!entry.downloader) { if (entry.progress_bar) { entry.progress_bar->setVisible(false); } if (entry.download_button) { entry.download_button->setVisible(true); entry.download_button->setEnabled(false); } if (entry.delete_button) { entry.delete_button->setVisible(true); entry.delete_button->setEnabled(false); } return; } if (entry.remote_url_label) { entry.remote_url_label->setText(format_markup_label(tr("Remote URL"), QString::fromStdString(entry.downloader->get_download_url()), QStringLiteral("#1565c0"))); } if (entry.local_path_label) { entry.local_path_label->setText(format_markup_label(tr("Local path"), QString::fromStdString(entry.downloader->get_download_destination()), QStringLiteral("#2e7d32"))); } const auto local_status = entry.downloader->get_local_download_status(); if (entry.file_size_label) { long long size = entry.downloader->get_real_content_length(); if (size <= 0 && local_status == LLMDownloader::DownloadStatus::Complete) { size = local_file_size_or_zero(entry.downloader->get_download_destination()); } if (size > 0) { entry.file_size_label->setText(format_markup_label(tr("File size"), QString::fromStdString(Utils::format_size(size)), QStringLiteral("#333"))); } else { entry.file_size_label->setText(tr("File size: unknown")); } } const auto status = entry.downloader->get_download_status(); switch (status) { case LLMDownloader::DownloadStatus::Complete: if (entry.progress_bar) { entry.progress_bar->setVisible(true); entry.progress_bar->setValue(100); } if (entry.download_button) { entry.download_button->setEnabled(false); entry.download_button->setVisible(false); } if (entry.delete_button) { entry.delete_button->setVisible(true); entry.delete_button->setEnabled(true); } set_visual_status_message(entry, tr("Model ready.")); break; case LLMDownloader::DownloadStatus::InProgress: if (entry.progress_bar) { entry.progress_bar->setVisible(true); } if (entry.download_button) { entry.download_button->setVisible(true); entry.download_button->setEnabled(!entry.is_downloading.load()); entry.download_button->setText(tr("Resume download")); } if (entry.delete_button) { entry.delete_button->setVisible(true); entry.delete_button->setEnabled(true); } set_visual_status_message(entry, tr("Partial download detected. You can resume.")); break; case LLMDownloader::DownloadStatus::NotStarted: default: if (entry.progress_bar) { entry.progress_bar->setVisible(false); entry.progress_bar->setValue(0); } if (entry.download_button) { entry.download_button->setVisible(true); entry.download_button->setEnabled(!entry.is_downloading.load()); entry.download_button->setText(tr("Download")); } if (entry.delete_button) { entry.delete_button->setVisible(true); entry.delete_button->setEnabled(false); } set_visual_status_message(entry, tr("Download required.")); break; } } void LLMSelectionDialog::update_visual_llm_downloads() { if (!visual_llm_download_section) { return; } refresh_visual_llm_download_entry(llava_model_download); update_visual_llm_download_entry(llava_model_download); refresh_visual_llm_download_entry(llava_mmproj_download); update_visual_llm_download_entry(llava_mmproj_download); } void LLMSelectionDialog::start_visual_llm_download(VisualLlmDownloadEntry& entry) { if (!entry.downloader || entry.is_downloading.load()) { return; } bool network_available = Utils::is_network_available(); #ifdef AI_FILE_SORTER_TEST_BUILD if (use_network_available_override_) { network_available = network_available_override_; } #endif if (!network_available) { DialogUtils::show_error_dialog(this, ERR_NO_INTERNET_CONNECTION); return; } try { entry.downloader->init_if_needed(); } catch (const std::exception& ex) { DialogUtils::show_error_dialog(this, ex.what()); return; } entry.is_downloading = true; if (entry.download_button) { entry.download_button->setEnabled(false); } if (entry.progress_bar) { entry.progress_bar->setVisible(true); entry.progress_bar->setValue(0); } set_visual_status_message(entry, tr("Downloading…")); auto* entry_ptr = &entry; entry.downloader->start_download( [this, entry_ptr](double fraction) { QMetaObject::invokeMethod(this, [entry_ptr, fraction]() { if (entry_ptr->progress_bar) { entry_ptr->progress_bar->setVisible(true); entry_ptr->progress_bar->setValue(static_cast(fraction * 100)); } }, Qt::QueuedConnection); }, [this, entry_ptr]() { QMetaObject::invokeMethod(this, [this, entry_ptr]() { entry_ptr->is_downloading = false; set_visual_status_message(*entry_ptr, tr("Download complete.")); update_visual_llm_download_entry(*entry_ptr); }, Qt::QueuedConnection); }, [this, entry_ptr](const std::string& text) { QMetaObject::invokeMethod(this, [this, entry_ptr, text]() { set_visual_status_message(*entry_ptr, QString::fromStdString(text)); }, Qt::QueuedConnection); }, [this, entry_ptr](const std::string& error_text) { QMetaObject::invokeMethod(this, [this, entry_ptr, error_text]() { entry_ptr->is_downloading = false; if (entry_ptr->progress_bar) { entry_ptr->progress_bar->setVisible(false); } if (entry_ptr->download_button) { entry_ptr->download_button->setEnabled(true); } const QString error = QString::fromStdString(error_text); if (error.compare(QStringLiteral("Download cancelled"), Qt::CaseInsensitive) == 0) { set_visual_status_message(*entry_ptr, tr("Download cancelled.")); } else { set_visual_status_message(*entry_ptr, tr("Download error: %1").arg(error)); } }, Qt::QueuedConnection); }); } void LLMSelectionDialog::handle_delete_visual_download(VisualLlmDownloadEntry& entry) { if (!entry.downloader) { return; } const std::string path = entry.downloader->get_download_destination(); if (path.empty()) { return; } const QString display_name = QString::fromStdString(entry.display_name); const QString title = tr("Delete downloaded model?"); const QString prompt = tr("Delete the downloaded model %1?").arg(display_name); const auto answer = QMessageBox::question(this, title, prompt, QMessageBox::Yes | QMessageBox::No); if (answer != QMessageBox::Yes) { return; } entry.downloader->cancel_download(); entry.is_downloading.store(false); std::error_code ec; bool removed_any = false; if (std::filesystem::exists(path, ec)) { removed_any = std::filesystem::remove(path, ec) || removed_any; } const std::string partial_path = entry.downloader->get_partial_download_destination(); if (std::filesystem::exists(partial_path, ec)) { removed_any = std::filesystem::remove(partial_path, ec) || removed_any; } const std::string meta_path = path + ".aifs.meta"; if (std::filesystem::exists(meta_path, ec)) { removed_any = std::filesystem::remove(meta_path, ec) || removed_any; } if (ec) { set_visual_status_message(entry, tr("Failed to delete downloaded model.")); } else if (removed_any) { set_visual_status_message(entry, tr("Deleted downloaded model.")); } else { set_visual_status_message(entry, tr("No downloaded model found to delete.")); } refresh_visual_llm_download_entry(entry); update_visual_llm_download_entry(entry); } void LLMSelectionDialog::adjust_dialog_size() { if (!scroll_area_) { return; } auto* widget = scroll_area_->widget(); if (!widget) { return; } widget->adjustSize(); const QSize content_hint = widget->sizeHint(); const int content_height = content_hint.height(); const int content_width = content_hint.width(); int scroll_height = content_height; const int button_height = button_box ? button_box->sizeHint().height() : 0; const int button_width = button_box ? button_box->sizeHint().width() : 0; QMargins margins; int spacing = 0; if (layout()) { margins = layout()->contentsMargins(); spacing = layout()->spacing(); } const int frame = scroll_area_->frameWidth() * 2; int desired_width = std::max(content_width + frame, button_width); desired_width += margins.left() + margins.right(); int desired_height = scroll_height + button_height + margins.top() + margins.bottom(); if (button_height > 0) { desired_height += spacing; } if (const QScreen* screen = this->screen()) { const QSize available = screen->availableGeometry().size(); const int max_width = static_cast(available.width() * 0.8); const int max_height = static_cast(available.height() * 0.8); const int max_scroll_height = std::max( 0, max_height - (button_height + margins.top() + margins.bottom() + (button_height > 0 ? spacing : 0))); int target_height = desired_height; const bool needs_scroll = target_height > max_height; if (needs_scroll) { scroll_area_->setMinimumHeight(0); scroll_area_->setMaximumHeight(max_scroll_height); target_height = max_height; } else { scroll_area_->setMinimumHeight(scroll_height); scroll_area_->setMaximumHeight(scroll_height); } int scrollbar_padding = 0; if (needs_scroll) { scrollbar_padding = scroll_area_->style()->pixelMetric(QStyle::PM_ScrollBarExtent, nullptr, scroll_area_); } const int min_width = 620; int target_width = std::min(desired_width + scrollbar_padding, max_width); target_width = std::max(target_width, min_width); resize(target_width, target_height); } else { scroll_area_->setMinimumHeight(scroll_height); scroll_area_->setMaximumHeight(scroll_height); adjustSize(); } widget->updateGeometry(); if (layout()) { layout()->invalidate(); layout()->activate(); } } void LLMSelectionDialog::start_download() { if (!downloader || is_downloading.load()) { return; } if (!Utils::is_network_available()) { DialogUtils::show_error_dialog(this, ERR_NO_INTERNET_CONNECTION); return; } try { downloader->init_if_needed(); } catch (const std::exception& ex) { DialogUtils::show_error_dialog(this, ex.what()); return; } is_downloading = true; download_button->setEnabled(false); progress_bar->setVisible(true); set_status_message(tr("Downloading…")); progress_bar->setValue(0); button_box->button(QDialogButtonBox::Ok)->setEnabled(false); downloader->start_download( [this](double fraction) { QMetaObject::invokeMethod(this, [this, fraction]() { progress_bar->setVisible(true); progress_bar->setValue(static_cast(fraction * 100)); }, Qt::QueuedConnection); }, [this]() { QMetaObject::invokeMethod(this, [this]() { is_downloading = false; set_status_message(tr("Download complete.")); update_ui_for_choice(); }, Qt::QueuedConnection); }, [this](const std::string& text) { QMetaObject::invokeMethod(this, [this, text]() { set_status_message(QString::fromStdString(text)); }, Qt::QueuedConnection); }, [this](const std::string& error_text) { QMetaObject::invokeMethod(this, [this, error_text]() { is_downloading = false; progress_bar->setVisible(false); download_button->setEnabled(true); const QString error = QString::fromStdString(error_text); if (error.compare(QStringLiteral("Download cancelled"), Qt::CaseInsensitive) == 0) { set_status_message(tr("Download cancelled.")); } else { set_status_message(tr("Download error: %1").arg(error)); } button_box->button(QDialogButtonBox::Ok)->setEnabled(false); }, Qt::QueuedConnection); }); } std::string LLMSelectionDialog::current_download_env_var() const { if (selected_choice == LLMChoice::Local_3b) { return "LOCAL_LLM_3B_DOWNLOAD_URL"; } if (selected_choice == LLMChoice::Local_3b_legacy) { return "LOCAL_LLM_3B_LEGACY_DOWNLOAD_URL"; } if (selected_choice == LLMChoice::Local_7b) { return "LOCAL_LLM_7B_DOWNLOAD_URL"; } return std::string(); } #if defined(AI_FILE_SORTER_TEST_BUILD) LLMSelectionDialogTestAccess::VisualEntryRefs LLMSelectionDialogTestAccess::llava_model_entry(LLMSelectionDialog& dialog) { return { dialog.llava_model_download.status_label, dialog.llava_model_download.download_button, dialog.llava_model_download.progress_bar, dialog.llava_model_download.downloader.get() }; } LLMSelectionDialogTestAccess::VisualEntryRefs LLMSelectionDialogTestAccess::llava_mmproj_entry(LLMSelectionDialog& dialog) { return { dialog.llava_mmproj_download.status_label, dialog.llava_mmproj_download.download_button, dialog.llava_mmproj_download.progress_bar, dialog.llava_mmproj_download.downloader.get() }; } void LLMSelectionDialogTestAccess::refresh_visual_downloads(LLMSelectionDialog& dialog) { dialog.update_visual_llm_downloads(); } void LLMSelectionDialogTestAccess::update_llava_model_entry(LLMSelectionDialog& dialog) { dialog.update_visual_llm_download_entry(dialog.llava_model_download); } void LLMSelectionDialogTestAccess::start_llava_model_download(LLMSelectionDialog& dialog) { dialog.start_visual_llm_download(dialog.llava_model_download); } void LLMSelectionDialogTestAccess::set_network_available_override(LLMSelectionDialog& dialog, std::optional value) { if (value.has_value()) { dialog.use_network_available_override_ = true; dialog.network_available_override_ = *value; } else { dialog.use_network_available_override_ = false; } } #endif // AI_FILE_SORTER_TEST_BUILD ================================================ FILE: app/lib/LlavaImageAnalyzer.cpp ================================================ #include "LlavaImageAnalyzer.hpp" #include "Logger.hpp" #include "LlamaModelParams.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef AI_FILE_SORTER_HAS_MTMD #include "ggml-backend.h" #include "llama.h" #include "mtmd.h" #include "mtmd-helper.h" #endif #ifdef AI_FILE_SORTER_HAS_MTMD extern "C" { #if defined(AI_FILE_SORTER_MTMD_PROGRESS_CALLBACK) typedef void (*mtmd_progress_callback_t)(const char* name, int32_t current_batch, int32_t total_batches, void* user_data); MTMD_API void mtmd_helper_set_progress_callback(mtmd_progress_callback_t callback, void* user_data); #endif #if defined(AI_FILE_SORTER_MTMD_LOG_CALLBACK) MTMD_API void mtmd_helper_log_set(ggml_log_callback log_callback, void* user_data); #endif } #endif namespace { constexpr size_t kMaxFilenameWords = 3; constexpr size_t kMaxFilenameLength = 50; #if defined(AI_FILE_SORTER_MTMD_LOG_CALLBACK) bool is_mtmd_prompt_log_line(std::string_view line) { return line.starts_with("add_text:"); } #endif std::string to_lower_copy(std::string value) { std::transform(value.begin(), value.end(), value.begin(), [](unsigned char ch) { return static_cast(std::tolower(ch)); }); return value; } std::optional read_env_bool(const char* key) { const char* value = std::getenv(key); if (!value || value[0] == '\0') { return std::nullopt; } std::string lowered = to_lower_copy(value); if (lowered == "1" || lowered == "true" || lowered == "yes" || lowered == "on") { return true; } if (lowered == "0" || lowered == "false" || lowered == "no" || lowered == "off") { return false; } return std::nullopt; } std::optional read_env_value(const char* key) { const char* value = std::getenv(key); if (!value) { return std::nullopt; } return std::string(value); } void set_env_value(const char* key, const std::optional& value) { #if defined(_WIN32) if (value.has_value()) { _putenv_s(key, value->c_str()); } else { _putenv_s(key, ""); } #else if (value.has_value()) { setenv(key, value->c_str(), 1); } else { unsetenv(key); } #endif } class ScopedEnvValue { public: ScopedEnvValue(const char* key, std::optional value) : key_(key), original_(read_env_value(key)) { set_env_value(key_, value); } ~ScopedEnvValue() { set_env_value(key_, original_); } ScopedEnvValue(const ScopedEnvValue&) = delete; ScopedEnvValue& operator=(const ScopedEnvValue&) = delete; private: const char* key_; std::optional original_; }; std::optional read_env_int(const char* key) { const char* value = std::getenv(key); if (!value || *value == '\0') { return std::nullopt; } char* end_ptr = nullptr; errno = 0; long parsed = std::strtol(value, &end_ptr, 10); if (end_ptr == value || *end_ptr != '\0' || errno == ERANGE) { return std::nullopt; } if (parsed < INT_MIN || parsed > INT_MAX) { return std::nullopt; } return static_cast(parsed); } std::optional resolve_visual_gpu_layer_override() { if (const auto visual_override = read_env_int("AI_FILE_SORTER_VISUAL_N_GPU_LAYERS")) { return visual_override; } return read_env_int("LLAVA_N_GPU_LAYERS"); } std::string read_env_lower(const char* key) { const char* value = std::getenv(key); if (!value || value[0] == '\0') { return {}; } return to_lower_copy(value); } std::string resolve_backend_name() { std::string backend = read_env_lower("AI_FILE_SORTER_GPU_BACKEND"); if (backend.empty()) { backend = read_env_lower("LLAMA_ARG_DEVICE"); } #ifdef GGML_USE_METAL if (backend.empty()) { backend = "metal"; } #endif return backend; } std::string trim_copy(const std::string& value) { auto result = value; const auto not_space = [](unsigned char ch) { return !std::isspace(ch); }; result.erase(result.begin(), std::find_if(result.begin(), result.end(), not_space)); result.erase(std::find_if(result.rbegin(), result.rend(), not_space).base(), result.end()); return result; } QString sanitize_utf8_text(const std::string& value) { QString cleaned = QString::fromUtf8(value.c_str()); cleaned.remove(QChar::ReplacementCharacter); return cleaned.normalized(QString::NormalizationForm_C); } std::vector split_words(const QString& value) { std::vector words; QString current; for (const QChar ch : value) { if (ch.isLetterOrNumber()) { current.append(ch.toLower()); } else if (!current.isEmpty()) { words.emplace_back(current.toUtf8().toStdString()); current.clear(); } } if (!current.isEmpty()) { words.emplace_back(current.toUtf8().toStdString()); } return words; } const std::unordered_set kStopwords = { "a", "an", "and", "are", "as", "at", "based", "be", "by", "category", "describes", "description", "depicts", "details", "document", "file", "filename", "for", "from", "gif", "has", "image", "in", "is", "it", "jpeg", "jpg", "of", "on", "only", "photo", "picture", "png", "shows", "the", "this", "to", "txt", "unknown", "with" }; bool case_insensitive_contains(std::string_view text, std::string_view needle) { if (needle.empty()) { return true; } std::string text_lower(text); std::string needle_lower(needle); std::transform(text_lower.begin(), text_lower.end(), text_lower.begin(), [](unsigned char c) { return static_cast(std::tolower(c)); }); std::transform(needle_lower.begin(), needle_lower.end(), needle_lower.begin(), [](unsigned char c) { return static_cast(std::tolower(c)); }); return text_lower.find(needle_lower) != std::string::npos; } int32_t resolve_default_visual_batch_size(bool gpu_enabled, std::string_view backend_name) { if (!gpu_enabled) { return 512; } if (case_insensitive_contains(backend_name, "metal")) { return 1024; } #if defined(_WIN32) // Windows GPU drivers are more sensitive to an initial oversized context // allocation, so keep image analysis at the proven 512-token batch. return 512; #else if (case_insensitive_contains(backend_name, "vulkan")) { return 512; } return 768; #endif } llama_model_params build_visual_model_params_for_path( const std::string& model_path, const std::shared_ptr& logger) { const auto visual_override = resolve_visual_gpu_layer_override(); const auto global_override = read_env_value("AI_FILE_SORTER_N_GPU_LAYERS"); const auto legacy_override = read_env_value("LLAMA_CPP_N_GPU_LAYERS"); std::optional ai_override_guard; std::optional legacy_override_guard; if (visual_override.has_value()) { const std::string override_value = std::to_string(*visual_override); ai_override_guard.emplace("AI_FILE_SORTER_N_GPU_LAYERS", override_value); legacy_override_guard.emplace("LLAMA_CPP_N_GPU_LAYERS", override_value); if (logger) { logger->info("Using visual-specific n_gpu_layers override={}", *visual_override); } } else { ai_override_guard.emplace("AI_FILE_SORTER_N_GPU_LAYERS", std::nullopt); legacy_override_guard.emplace("LLAMA_CPP_N_GPU_LAYERS", std::nullopt); if ((global_override.has_value() && !global_override->empty()) || (legacy_override.has_value() && !legacy_override->empty())) { if (logger) { logger->info( "Ignoring global n_gpu_layers override for visual analysis; " "set AI_FILE_SORTER_VISUAL_N_GPU_LAYERS to override image analysis specifically."); } } } return build_model_params_for_path(model_path, logger); } #ifdef AI_FILE_SORTER_HAS_MTMD struct BackendMemoryInfo { size_t free_bytes = 0; size_t total_bytes = 0; std::string name; }; std::optional query_backend_memory(std::string_view backend_name) { const size_t device_count = ggml_backend_dev_count(); BackendMemoryInfo best{}; bool found = false; for (size_t i = 0; i < device_count; ++i) { auto* device = ggml_backend_dev_get(i); if (!device) { continue; } if (ggml_backend_dev_type(device) != GGML_BACKEND_DEVICE_TYPE_GPU) { continue; } auto* reg = ggml_backend_dev_backend_reg(device); const char* reg_name = reg ? ggml_backend_reg_name(reg) : nullptr; if (!backend_name.empty() && !case_insensitive_contains(reg_name ? reg_name : "", backend_name)) { continue; } size_t free_bytes = 0; size_t total_bytes = 0; ggml_backend_dev_memory(device, &free_bytes, &total_bytes); if (free_bytes == 0 && total_bytes == 0) { continue; } if (!found || total_bytes > best.total_bytes) { best.free_bytes = free_bytes; best.total_bytes = (total_bytes != 0) ? total_bytes : free_bytes; const char* dev_name = ggml_backend_dev_name(device); best.name = dev_name ? dev_name : ""; found = true; } } if (found) { return best; } return std::nullopt; } bool should_enable_mmproj_gpu(const std::filesystem::path& mmproj_path, std::string_view backend_name, const std::shared_ptr& logger) { if (!case_insensitive_contains(backend_name, "vulkan")) { return true; } const auto memory = query_backend_memory("vulkan"); if (!memory.has_value()) { if (logger) { logger->warn("Vulkan memory metrics unavailable; using CPU for visual encoder to avoid OOM. " "Set AI_FILE_SORTER_VISUAL_USE_GPU=1 to force GPU."); } return false; } std::error_code ec; const auto file_size = std::filesystem::file_size(mmproj_path, ec); if (ec) { if (logger) { logger->warn("Failed to stat mmproj file '{}'; using CPU for visual encoder to avoid OOM. " "Set AI_FILE_SORTER_VISUAL_USE_GPU=1 to force GPU.", mmproj_path.string()); } return false; } constexpr size_t kMinHeadroomBytes = 512ULL * 1024ULL * 1024ULL; const size_t mmproj_bytes = static_cast( std::min(file_size, std::numeric_limits::max())); const size_t inflated_bytes = mmproj_bytes + (mmproj_bytes / 3); const size_t required_bytes = inflated_bytes + kMinHeadroomBytes; if (memory->free_bytes < required_bytes) { if (logger) { const double to_mib = 1024.0 * 1024.0; logger->warn( "Vulkan free memory {:.1f} MiB < {:.1f} MiB needed for mmproj; using CPU for visual encoder. " "Set AI_FILE_SORTER_VISUAL_USE_GPU=1 to force GPU.", memory->free_bytes / to_mib, required_bytes / to_mib); } return false; } return true; } struct BitmapDeleter { void operator()(mtmd_bitmap* ptr) const { if (ptr) { mtmd_bitmap_free(ptr); } } }; struct ChunkDeleter { void operator()(mtmd_input_chunks* ptr) const { if (ptr) { mtmd_input_chunks_free(ptr); } } }; using BitmapPtr = std::unique_ptr; using ChunkPtr = std::unique_ptr; llama_token greedy_sample(const float* logits, int vocab_size, float temperature) { const float temp = std::max(temperature, 1e-3f); int best_index = 0; float best_value = -std::numeric_limits::infinity(); for (int i = 0; i < vocab_size; ++i) { const float value = logits[i] / temp; if (value > best_value) { best_value = value; best_index = i; } } return static_cast(best_index); } #endif } // namespace #ifdef AI_FILE_SORTER_TEST_BUILD namespace LlavaImageAnalyzerTestAccess { int32_t default_visual_batch_size(bool gpu_enabled, std::string_view backend_name) { return resolve_default_visual_batch_size(gpu_enabled, backend_name); } int32_t visual_model_n_gpu_layers_for_model(const std::string& model_path) { return build_visual_model_params_for_path(model_path, nullptr).n_gpu_layers; } } #endif LlavaImageAnalyzer::LlavaImageAnalyzer(const std::filesystem::path& model_path, const std::filesystem::path& mmproj_path) : LlavaImageAnalyzer(model_path, mmproj_path, Settings{}) {} LlavaImageAnalyzer::LlavaImageAnalyzer(const std::filesystem::path& model_path, const std::filesystem::path& mmproj_path, Settings settings) #ifdef AI_FILE_SORTER_HAS_MTMD : model_path_(model_path) , mmproj_path_(mmproj_path) , settings_(settings) #else : settings_(settings) #endif { if (settings_.n_threads <= 0) { settings_.n_threads = static_cast(std::max(1u, std::thread::hardware_concurrency())); } #ifndef AI_FILE_SORTER_HAS_MTMD (void)model_path; (void)mmproj_path; if (auto logger = Logger::get_logger("core_logger")) { logger->error("Visual LLM support is not available in this build."); } return; #else visual_gpu_override_ = read_env_bool("AI_FILE_SORTER_VISUAL_USE_GPU"); if (visual_gpu_override_.has_value()) { settings_.use_gpu = *visual_gpu_override_; } auto logger = Logger::get_logger("core_logger"); const std::string backend_name = resolve_backend_name(); const auto cleanup = [this]() { if (vision_ctx_) { mtmd_free(vision_ctx_); vision_ctx_ = nullptr; } if (context_) { llama_free(context_); context_ = nullptr; } if (model_) { llama_model_free(model_); model_ = nullptr; } }; llama_model_params model_params = llama_model_default_params(); if (settings_.use_gpu) { model_params = build_visual_model_params_for_path(model_path.string(), logger); } else { model_params.n_gpu_layers = 0; } text_gpu_enabled_ = settings_.use_gpu && model_params.n_gpu_layers != 0; context_tokens_ = settings_.n_ctx; batch_size_ = resolve_default_visual_batch_size(text_gpu_enabled_, backend_name); model_ = llama_model_load_from_file(model_path.string().c_str(), model_params); if (!model_) { throw std::runtime_error("Failed to load LLaVA text model at " + model_path.string()); } vocab_ = llama_model_get_vocab(model_); bool mmproj_use_gpu = text_gpu_enabled_; if (mmproj_use_gpu && (!visual_gpu_override_.has_value() || !*visual_gpu_override_)) { mmproj_use_gpu = should_enable_mmproj_gpu(mmproj_path, backend_name, logger); } mmproj_gpu_enabled_ = mmproj_use_gpu; mtmd_context_params mm_params = mtmd_context_params_default(); mm_params.use_gpu = mmproj_gpu_enabled_; mm_params.n_threads = settings_.n_threads; vision_ctx_ = mtmd_init_from_file(mmproj_path.string().c_str(), model_, mm_params); if (!vision_ctx_) { cleanup(); throw std::runtime_error("Failed to load mmproj file at " + mmproj_path.string()); } if (!mtmd_support_vision(vision_ctx_)) { cleanup(); throw std::runtime_error("The provided mmproj file does not expose vision capabilities"); } try { initialize_context(); } catch (...) { cleanup(); throw; } #endif } LlavaImageAnalyzer::~LlavaImageAnalyzer() { #ifdef AI_FILE_SORTER_HAS_MTMD if (vision_ctx_) { mtmd_free(vision_ctx_); vision_ctx_ = nullptr; } if (context_) { llama_free(context_); context_ = nullptr; } if (model_) { llama_model_free(model_); model_ = nullptr; } #endif } #ifdef AI_FILE_SORTER_HAS_MTMD void LlavaImageAnalyzer::initialize_context() { auto logger = Logger::get_logger("core_logger"); const int32_t initial_ctx = context_tokens_ > 0 ? context_tokens_ : settings_.n_ctx; const int32_t initial_batch = batch_size_ > 0 ? batch_size_ : 512; auto try_init_context = [&](int32_t n_ctx, int32_t n_batch) -> bool { if (context_) { llama_free(context_); context_ = nullptr; } const int32_t bounded_ctx = std::max(1, n_ctx); const int32_t bounded_batch = std::max(1, std::min(n_batch, bounded_ctx)); llama_context_params ctx_params = llama_context_default_params(); ctx_params.n_ctx = bounded_ctx; ctx_params.n_batch = bounded_batch; ctx_params.n_ubatch = bounded_batch; ctx_params.n_threads = settings_.n_threads; ctx_params.n_threads_batch = settings_.n_threads; context_ = llama_init_from_model(model_, ctx_params); if (context_) { llama_set_n_threads(context_, settings_.n_threads, settings_.n_threads); } return context_ != nullptr; }; auto apply_context_limits = [&](int32_t n_ctx, int32_t n_batch) { context_tokens_ = std::max(1, n_ctx); batch_size_ = std::max(1, std::min(n_batch, context_tokens_)); }; bool context_ready = try_init_context(initial_ctx, initial_batch); if (context_ready) { apply_context_limits(initial_ctx, initial_batch); } else if (initial_batch > 512) { if (logger) { logger->warn("Failed to initialize llama_context (n_ctx={}, n_batch={}); retrying with smaller batch.", initial_ctx, initial_batch); } const int32_t smaller_batch = 512; context_ready = try_init_context(initial_ctx, smaller_batch); if (context_ready) { apply_context_limits(initial_ctx, smaller_batch); } } if (!context_ready) { if (logger) { logger->warn("Failed to initialize llama_context (n_ctx={}, n_batch={}); retrying with smaller buffers.", initial_ctx, std::min(initial_batch, 512)); } const int32_t reduced_ctx = std::min(initial_ctx, 2048); const int32_t reduced_batch = std::min(initial_batch, 512); context_ready = try_init_context(reduced_ctx, reduced_batch); if (context_ready) { apply_context_limits(reduced_ctx, reduced_batch); } else { const int32_t smaller_batch = std::min(reduced_batch, 256); context_ready = try_init_context(reduced_ctx, smaller_batch); if (context_ready) { apply_context_limits(reduced_ctx, smaller_batch); } else { const int32_t smaller_ctx = std::min(reduced_ctx, 1024); context_ready = try_init_context(smaller_ctx, smaller_batch); if (context_ready) { apply_context_limits(smaller_ctx, smaller_batch); } } } } if (!context_ready) { std::string hint; if (text_gpu_enabled_) { hint = " (try AI_FILE_SORTER_VISUAL_USE_GPU=0 to force CPU)"; } throw std::runtime_error("Failed to create llama_context" + hint); } reset_context_state(); } void LlavaImageAnalyzer::reset_context_state() { if (!context_) { return; } llama_memory_clear(llama_get_memory(context_), true); llama_synchronize(context_); llama_perf_context_reset(context_); } #endif bool LlavaImageAnalyzer::is_supported_image(const std::filesystem::path& path) { if (!path.has_extension()) { return false; } std::string ext = to_lower_copy(path.extension().string()); static const std::unordered_set kExtensions = { ".jpg", ".jpeg", ".png", ".bmp", ".gif", ".tga", ".psd", ".hdr", ".pic", ".pnm", ".ppm", ".pgm", ".pbm" }; return kExtensions.find(ext) != kExtensions.end(); } LlavaImageAnalysisResult LlavaImageAnalyzer::analyze(const std::filesystem::path& image_path) { #ifndef AI_FILE_SORTER_HAS_MTMD (void)image_path; throw std::runtime_error("Visual LLM support is not available in this build."); #else auto logger = Logger::get_logger("core_logger"); BitmapPtr bitmap(mtmd_helper_bitmap_init_from_file(vision_ctx_, image_path.string().c_str())); if (!bitmap) { throw std::runtime_error("Failed to load image for LLaVA: " + image_path.string()); } const std::string description = infer_text(bitmap.get(), build_description_prompt(), settings_.n_predict); const std::string raw_filename = infer_text(nullptr, build_filename_prompt(description), settings_.n_predict); if (logger) { logger->info("LLaVA raw filename: {}", raw_filename); } std::string filename_base = sanitize_filename(raw_filename, kMaxFilenameWords, kMaxFilenameLength); if (filename_base.empty()) { filename_base = sanitize_filename(description, kMaxFilenameWords, kMaxFilenameLength); } if (filename_base.empty()) { filename_base = "image_" + slugify(image_path.stem().string()); } LlavaImageAnalysisResult result; result.description = description; result.suggested_name = normalize_filename(filename_base, image_path); if (logger) { logger->info("LLaVA suggested filename: {}", result.suggested_name); } return result; #endif } std::string LlavaImageAnalyzer::build_description_prompt() const { std::ostringstream oss; oss << "Please provide a detailed description of this image, focusing on the main subject " << "and any important details.\n" << "Image: <__media__>\n" << "Description:"; return oss.str(); } std::string LlavaImageAnalyzer::build_filename_prompt(const std::string& description) const { std::ostringstream oss; oss << "Based on the description below, generate a specific and descriptive filename for the image.\n" << "Limit the filename to a maximum of 3 words. Use nouns and avoid starting with verbs like " << "'depicts', 'shows', 'presents', etc.\n" << "Do not include any data type words like 'image', 'jpg', 'png', etc. Use only letters and " << "connect words with underscores.\n\n" << "Description: " << description << "\n\n" << "Example:\n" << "Description: A photo of a sunset over the mountains.\n" << "Filename: sunset_over_mountains\n\n" << "Now generate the filename.\n\n" << "Output only the filename, without any additional text.\n\n" << "Filename:"; return oss.str(); } #ifdef AI_FILE_SORTER_HAS_MTMD void LlavaImageAnalyzer::mtmd_progress_callback(const char* name, int32_t current_batch, int32_t total_batches, void* user_data) { if (!user_data || total_batches <= 0 || current_batch <= 0) { return; } if (name && std::strcmp(name, "image") != 0) { return; } auto* self = static_cast(user_data); if (!self->settings_.batch_progress) { return; } self->settings_.batch_progress(current_batch, total_batches); } #if defined(AI_FILE_SORTER_MTMD_LOG_CALLBACK) void LlavaImageAnalyzer::mtmd_log_callback(enum ggml_log_level level, const char* text, void* user_data) { (void)level; if (!text) { return; } auto* self = static_cast(user_data); #if !defined(AI_FILE_SORTER_MTMD_PROGRESS_CALLBACK) if (self && self->settings_.batch_progress) { int current_batch = 0; int total_batches = 0; if (std::sscanf(text, "decoding image batch %d/%d", ¤t_batch, &total_batches) == 2) { if (current_batch > 0 && total_batches > 0) { self->settings_.batch_progress(current_batch, total_batches); } } } #endif if (!self || !self->settings_.log_visual_output) { return; } if (is_mtmd_prompt_log_line(text)) { return; } std::fputs(text, stderr); std::fflush(stderr); } #endif #endif #ifdef AI_FILE_SORTER_HAS_MTMD std::string LlavaImageAnalyzer::infer_text(mtmd_bitmap* bitmap, const std::string& prompt, int32_t max_tokens) { if (!context_) { initialize_context(); } reset_context_state(); ChunkPtr chunks(mtmd_input_chunks_init()); if (!chunks) { throw std::runtime_error("Failed to allocate mtmd input chunks"); } mtmd_input_text text{}; text.text = prompt.c_str(); text.add_special = true; text.parse_special = true; const mtmd_bitmap* bitmaps[] = { bitmap }; const mtmd_bitmap** bitmap_ptr = nullptr; int32_t bitmap_count = 0; if (bitmap) { bitmap_ptr = bitmaps; bitmap_count = 1; } #if defined(AI_FILE_SORTER_MTMD_LOG_CALLBACK) struct LogGuard { bool active{false}; explicit LogGuard(LlavaImageAnalyzer* self) : active(true) { mtmd_helper_log_set(&LlavaImageAnalyzer::mtmd_log_callback, self); } ~LogGuard() { if (!active) { return; } mtmd_helper_log_set(nullptr, nullptr); } }; LogGuard log_guard(this); #endif const int32_t tokenize_res = mtmd_tokenize( vision_ctx_, chunks.get(), &text, bitmap_ptr, bitmap_count); if (tokenize_res != 0) { throw std::runtime_error("mtmd_tokenize failed with code " + std::to_string(tokenize_res)); } #if defined(AI_FILE_SORTER_MTMD_PROGRESS_CALLBACK) struct ProgressGuard { bool active{false}; ProgressGuard(bool enabled, LlavaImageAnalyzer* self) : active(enabled) { if (!active) { return; } mtmd_helper_set_progress_callback(&LlavaImageAnalyzer::mtmd_progress_callback, self); } ~ProgressGuard() { if (!active) { return; } mtmd_helper_set_progress_callback(nullptr, nullptr); } }; const bool enable_progress = bitmap && settings_.batch_progress; ProgressGuard progress_guard(enable_progress, this); #endif llama_pos new_n_past = 0; if (mtmd_helper_eval_chunks(vision_ctx_, context_, chunks.get(), 0 /* n_past */, 0 /* seq_id */, (batch_size_ > 0 ? batch_size_ : 512) /* n_batch */, true /* logits_last */, &new_n_past) != 0) { throw std::runtime_error("mtmd_helper_eval_chunks failed"); } std::string response; response.reserve(256); const int vocab_size = llama_vocab_n_tokens(vocab_); for (int32_t i = 0; i < max_tokens; ++i) { const float* logits = llama_get_logits(context_); if (!logits) { throw std::runtime_error("llama_get_logits returned nullptr"); } llama_token token_id = greedy_sample(logits, vocab_size, settings_.temperature); if (llama_vocab_is_eog(vocab_, token_id)) { break; } char buffer[256]; const int n = llama_token_to_piece(vocab_, token_id, buffer, sizeof(buffer), 0, true); if (n < 0) { throw std::runtime_error("Failed to convert token to text piece"); } response.append(buffer, n); llama_batch batch = llama_batch_get_one(&token_id, 1); if (llama_decode(context_, batch) != 0) { throw std::runtime_error("llama_decode failed during generation"); } } return trim(response); } #else std::string LlavaImageAnalyzer::infer_text(void* bitmap, const std::string& prompt, int32_t max_tokens) { (void)bitmap; (void)prompt; (void)max_tokens; throw std::runtime_error("Visual LLM support is not available in this build."); } #endif std::string LlavaImageAnalyzer::sanitize_filename(const std::string& value, size_t max_words, size_t max_length) const { QString cleaned = sanitize_utf8_text(value).trimmed(); const QString prefix = QStringLiteral("filename:"); if (cleaned.startsWith(prefix, Qt::CaseInsensitive)) { cleaned = cleaned.mid(prefix.size()).trimmed(); } const int newline = cleaned.indexOf('\n'); if (newline != -1) { cleaned = cleaned.left(newline); } const int carriage = cleaned.indexOf('\r'); if (carriage != -1) { cleaned = cleaned.left(carriage); } if (cleaned.size() >= 2) { const QChar first = cleaned.front(); const QChar last = cleaned.back(); if ((first == '"' && last == '"') || (first == '\'' && last == '\'')) { cleaned = cleaned.mid(1, cleaned.size() - 2); } } auto words = split_words(cleaned); std::vector filtered; filtered.reserve(words.size()); std::unordered_set seen; for (const auto& word : words) { if (word.empty()) { continue; } if (kStopwords.find(word) != kStopwords.end()) { continue; } if (seen.insert(word).second) { filtered.push_back(word); } if (filtered.size() >= max_words) { break; } } if (filtered.empty()) { return std::string(); } QString joined; for (size_t i = 0; i < filtered.size(); ++i) { if (i > 0) { joined.append('_'); } joined.append(QString::fromUtf8(filtered[i].c_str())); } if (joined.size() > static_cast(max_length)) { joined = joined.left(static_cast(max_length)); } while (!joined.isEmpty() && joined.endsWith('_')) { joined.chop(1); } return joined.toUtf8().toStdString(); } std::string LlavaImageAnalyzer::trim(std::string value) { return trim_copy(value); } std::string LlavaImageAnalyzer::slugify(const std::string& value) { const QString input = sanitize_utf8_text(value); QString slug; slug.reserve(input.size()); bool last_sep = false; for (const QChar ch : input) { if (ch.isLetterOrNumber()) { slug.append(ch.toLower()); last_sep = false; } else if (!last_sep && !slug.isEmpty()) { slug.append('_'); last_sep = true; } } if (!slug.isEmpty() && slug.endsWith('_')) { slug.chop(1); } if (slug.isEmpty()) { slug = QStringLiteral("item"); } return slug.toUtf8().toStdString(); } std::string LlavaImageAnalyzer::normalize_filename(const std::string& base, const std::filesystem::path& original_path) { const std::string ext = original_path.extension().string(); if (base.empty()) { return original_path.filename().string(); } return ext.empty() ? base : base + ext; } ================================================ FILE: app/lib/LlmCatalog.cpp ================================================ #include "LlmCatalog.hpp" #include #include #include namespace { QString resolved_llm_name(const DefaultLlmEntry& entry) { const char* env_value = std::getenv(entry.name_env); if (env_value && *env_value) { return QString::fromUtf8(env_value); } return QString::fromUtf8(entry.fallback_name); } } // namespace const std::vector& default_llm_entries() { static const std::vector entries = { {LLMChoice::Local_3b, "LOCAL_LLM_3B_DOWNLOAD_URL", "LOCAL_LLM_3B_DISPLAY_NAME", "LLaMa 3b v3.2 Instruct Q4"}, {LLMChoice::Local_3b_legacy, "LOCAL_LLM_3B_LEGACY_DOWNLOAD_URL", "LOCAL_LLM_3B_LEGACY_DISPLAY_NAME", "LLaMa 3b v3.2 Instruct Q8, legacy"}, {LLMChoice::Local_7b, "LOCAL_LLM_7B_DOWNLOAD_URL", "LOCAL_LLM_7B_DISPLAY_NAME", "Mistral 7b Instruct v0.2 Q5"}}; return entries; } QString default_llm_label(const DefaultLlmEntry& entry) { return QObject::tr("Local LLM (%1)").arg(resolved_llm_name(entry)); } QString default_llm_label_for_choice(LLMChoice choice) { const auto& entries = default_llm_entries(); const auto it = std::find_if(entries.begin(), entries.end(), [choice](const DefaultLlmEntry& entry) { return entry.choice == choice; }); if (it == entries.end()) { return QObject::tr("Local LLM"); } return default_llm_label(*it); } ================================================ FILE: app/lib/LocalLLMClient.cpp ================================================ #include "LocalLLMClient.hpp" #include "Logger.hpp" #include "Utils.hpp" #include "TestHooks.hpp" #include "LocalLLMTestAccess.hpp" #include "llama.h" #include "gguf.h" #include "ggml-backend.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(__APPLE__) #include #include #endif #if defined(_WIN32) [[maybe_unused]] static void set_env_var(const char *key, const char *value) { _putenv_s(key, value); } #else [[maybe_unused]] static void set_env_var(const char *key, const char *value) { setenv(key, value, 1); } #endif namespace { struct GgufCtxDeleter { void operator()(gguf_context* ctx) const { gguf_free(ctx); } }; bool try_parse_env_int(const char *key, int &out) { const char *value = std::getenv(key); if (!value || *value == '\0') { return false; } char *end_ptr = nullptr; errno = 0; long parsed = std::strtol(value, &end_ptr, 10); if (end_ptr == value || *end_ptr != '\0' || errno == ERANGE) { return false; } if (parsed > INT_MAX || parsed < INT_MIN) { return false; } out = static_cast(parsed); return true; } int resolve_gpu_layer_override() { int parsed = 0; if (try_parse_env_int("AI_FILE_SORTER_N_GPU_LAYERS", parsed)) { return parsed; } if (try_parse_env_int("LLAMA_CPP_N_GPU_LAYERS", parsed)) { return parsed; } return INT_MIN; } std::string gpu_layers_to_string(int value) { if (value == -1) { return "auto (-1)"; } return std::to_string(value); } int resolve_context_length() { int parsed = 0; if (try_parse_env_int("AI_FILE_SORTER_CTX_TOKENS", parsed) && parsed > 0) { return parsed; } if (try_parse_env_int("LLAMA_CPP_MAX_CONTEXT", parsed) && parsed > 0) { return parsed; } return 2048; // increased default to better accommodate larger prompts (whitelists, hints) } bool is_cpu_backend_requested() { auto is_cpu_env = [](const char* value) { if (!value || *value == '\0') { return false; } std::string lowered(value); std::transform(lowered.begin(), lowered.end(), lowered.begin(), [](unsigned char c) { return static_cast(std::tolower(c)); }); return lowered == "cpu"; }; if (is_cpu_env(std::getenv("AI_FILE_SORTER_GPU_BACKEND")) || is_cpu_env(std::getenv("LLAMA_ARG_DEVICE"))) { return true; } const int override_layers = resolve_gpu_layer_override(); return override_layers != INT_MIN && override_layers <= 0; } bool allow_gpu_fallback(const LocalLLMClient::FallbackDecisionCallback& callback, const std::shared_ptr& logger, std::string_view reason) { if (is_cpu_backend_requested()) { return false; } if (!callback) { return true; } bool allowed = callback(std::string(reason)); if (!allowed && logger) { logger->warn("GPU fallback declined: {}", reason); } return allowed; } struct MetalDeviceInfo { size_t total_bytes = 0; size_t free_bytes = 0; std::string name; bool valid() const { return total_bytes > 0; } }; #if defined(GGML_USE_METAL) MetalDeviceInfo query_primary_gpu_device() { MetalDeviceInfo info; #if defined(__APPLE__) uint64_t memsize = 0; size_t len = sizeof(memsize); if (sysctlbyname("hw.memsize", &memsize, &len, nullptr, 0) == 0) { info.total_bytes = static_cast(memsize); } mach_port_t host_port = mach_host_self(); vm_size_t page_size = 0; if (host_port != MACH_PORT_NULL && host_page_size(host_port, &page_size) == KERN_SUCCESS) { vm_statistics64_data_t vm_stat {}; mach_msg_type_number_t count = HOST_VM_INFO64_COUNT; if (host_statistics64(host_port, HOST_VM_INFO64, reinterpret_cast(&vm_stat), &count) == KERN_SUCCESS) { const uint64_t free_pages = static_cast(vm_stat.free_count) + static_cast(vm_stat.inactive_count); info.free_bytes = static_cast(free_pages * static_cast(page_size)); } } info.name = "Metal (system memory)"; #endif return info; } bool metal_backend_available(const std::shared_ptr& logger) { ggml_backend_reg_t metal = ggml_backend_reg_by_name("Metal"); if (!metal) { metal = ggml_backend_reg_by_name("MTL"); } if (!metal) { if (logger) { logger->warn("Metal backend not registered under aliases Metal/MTL; falling back to CPU"); } return false; } const size_t dev_count = ggml_backend_reg_dev_count(metal); if (dev_count == 0) { if (logger) { logger->warn("No Metal devices detected; falling back to CPU"); } return false; } return true; } #endif // defined(GGML_USE_METAL) bool case_insensitive_contains(std::string_view text, std::string_view needle) { if (needle.empty()) { return true; } std::string text_lower(text); std::string needle_lower(needle); std::transform(text_lower.begin(), text_lower.end(), text_lower.begin(), [](unsigned char c) { return static_cast(std::tolower(c)); }); std::transform(needle_lower.begin(), needle_lower.end(), needle_lower.begin(), [](unsigned char c) { return static_cast(std::tolower(c)); }); return text_lower.find(needle_lower) != std::string::npos; } std::string to_lower_copy(std::string value); std::string trim_copy(std::string value) { auto not_space = [](unsigned char ch) { return !std::isspace(ch); }; value.erase(value.begin(), std::find_if(value.begin(), value.end(), not_space)); value.erase(std::find_if(value.rbegin(), value.rend(), not_space).base(), value.end()); return value; } std::string collapse_spaces_copy(std::string value) { std::string collapsed; collapsed.reserve(value.size()); bool previous_space = false; for (unsigned char ch : value) { if (std::isspace(ch)) { if (!previous_space) { collapsed.push_back(' '); } previous_space = true; continue; } collapsed.push_back(static_cast(ch)); previous_space = false; } return trim_copy(std::move(collapsed)); } std::string strip_wrapping_punctuation(std::string value) { auto is_wrapping = [](unsigned char ch) { switch (ch) { case '"': case '\'': case '`': case '(': case ')': case '[': case ']': case '{': case '}': case '<': case '>': return true; default: return false; } }; while (!value.empty() && (std::isspace(static_cast(value.front())) || is_wrapping(static_cast(value.front())))) { value.erase(value.begin()); } while (!value.empty() && (std::isspace(static_cast(value.back())) || is_wrapping(static_cast(value.back())) || value.back() == '.' || value.back() == ',' || value.back() == ':' || value.back() == ';')) { value.pop_back(); } return value; } std::string strip_trailing_parenthetical_gloss(std::string value) { value = trim_copy(std::move(value)); while (true) { const auto open = value.rfind(" ("); if (open == std::string::npos) { break; } std::string gloss = trim_copy(value.substr(open + 2)); if (!gloss.empty() && gloss.back() == ')') { gloss.pop_back(); gloss = trim_copy(std::move(gloss)); } const bool has_alpha_chars = std::any_of(gloss.begin(), gloss.end(), [](unsigned char ch) { return std::isalpha(ch); }); if (!has_alpha_chars) { break; } value = trim_copy(value.substr(0, open)); } return value; } std::size_t find_case_insensitive(const std::string& value, std::string_view needle) { const std::string lower_value = to_lower_copy(value); std::string lower_needle(needle); std::transform(lower_needle.begin(), lower_needle.end(), lower_needle.begin(), [](unsigned char ch) { return static_cast(std::tolower(ch)); }); return lower_value.find(lower_needle); } std::string strip_explanatory_suffix(std::string value) { static const std::vector markers = { " (based on", " (note", " (since", " - this ", " - based on", " because ", " based on ", " which ", " since ", " however ", " specifically ", " indicating ", " indicates ", " commonly ", " related to " }; std::size_t cut = std::string::npos; for (const std::string_view marker : markers) { const auto pos = find_case_insensitive(value, marker); if (pos != std::string::npos && (cut == std::string::npos || pos < cut)) { cut = pos; } } if (cut != std::string::npos) { value.resize(cut); } return strip_wrapping_punctuation(collapse_spaces_copy(std::move(value))); } std::string extract_category_phrase(std::string value) { struct PhrasePattern { std::string_view prefix; std::string_view suffix; }; static const std::vector patterns = { {"falls under the ", " category"}, {"falls under ", " category"}, {"belongs to the ", " category"}, {"belongs to ", " category"}, {"categorized as ", ""}, {"classified as ", ""}, {"category is ", ""}, {"category would be ", ""} }; const std::string lower = to_lower_copy(value); for (const auto& pattern : patterns) { const auto start = lower.find(pattern.prefix); if (start == std::string::npos) { continue; } const std::size_t content_start = start + pattern.prefix.size(); std::size_t content_end = value.size(); if (!pattern.suffix.empty()) { content_end = lower.find(pattern.suffix, content_start); if (content_end == std::string::npos || content_end <= content_start) { continue; } } return value.substr(content_start, content_end - content_start); } return value; } std::string strip_inline_label_artifacts(std::string value, bool category_label) { const auto markers = category_label ? std::array{ ", subcategory", ", sub category", " - subcategory", " - sub category", "; subcategory", "; sub category", " subcategory:", " sub category:" } : std::array{ ", category", ", main category", " - category", " - main category", "; category", "; main category", " category:", " main category:" }; std::size_t cut = std::string::npos; for (const std::string_view marker : markers) { const auto pos = find_case_insensitive(value, marker); if (pos != std::string::npos && (cut == std::string::npos || pos < cut)) { cut = pos; } } if (cut != std::string::npos) { value.resize(cut); } return trim_copy(std::move(value)); } std::string normalize_candidate_label(std::string value, bool category_label) { value = strip_wrapping_punctuation(collapse_spaces_copy(trim_copy(std::move(value)))); if (value.empty()) { return value; } if (category_label) { value = extract_category_phrase(std::move(value)); } value = strip_explanatory_suffix(std::move(value)); value = strip_trailing_parenthetical_gloss(std::move(value)); value = strip_inline_label_artifacts(std::move(value), category_label); return strip_wrapping_punctuation(collapse_spaces_copy(std::move(value))); } std::string to_lower_copy(std::string value) { std::transform(value.begin(), value.end(), value.begin(), [](unsigned char ch) { return static_cast(std::tolower(ch)); }); return value; } bool has_alpha(std::string_view value) { return std::any_of(value.begin(), value.end(), [](unsigned char ch) { return std::isalpha(ch); }); } bool is_heading_like_label(const std::string& value) { const std::string lower = to_lower_copy(strip_wrapping_punctuation(collapse_spaces_copy(trim_copy(value)))); static const std::array exact_matches = { "category", "main category", "subcategory", "sub category", "categorization", "classification", "result", "answer", "note", "warning", "disclaimer", "reason", "explanation", "full path", "file name", "directory name" }; for (const std::string_view candidate : exact_matches) { if (lower == candidate) { return true; } } return case_insensitive_contains(lower, "categorization") || case_insensitive_contains(lower, "classification"); } std::vector split_segments(const std::string& line, std::string_view delimiter) { std::vector segments; std::size_t start = 0; while (start <= line.size()) { const auto pos = line.find(delimiter, start); const std::string segment = trim_copy(line.substr(start, pos == std::string::npos ? pos : pos - start)); if (!segment.empty()) { segments.push_back(segment); } if (pos == std::string::npos) { break; } start = pos + delimiter.size(); } return segments; } std::optional> extract_inline_pair_from_line(const std::string& line) { for (std::string_view delimiter : {std::string_view(" : "), std::string_view(":")}) { const auto segments = split_segments(line, delimiter); if (segments.size() < 2) { continue; } for (std::size_t idx = segments.size() - 1; idx > 0; --idx) { const std::string left = normalize_candidate_label(segments[idx - 1], true); const std::string right = normalize_candidate_label(segments[idx], false); if (left.size() < 2 || right.empty()) { continue; } if (!has_alpha(left) || !has_alpha(right)) { continue; } if (is_heading_like_label(left)) { continue; } return std::make_pair(left, right); } } return std::nullopt; } std::optional extract_labeled_value(const std::string& line, std::initializer_list labels, bool category_label) { const auto colon = line.find(':'); if (colon == std::string::npos) { return std::nullopt; } const std::string key = to_lower_copy(trim_copy(line.substr(0, colon))); for (const std::string_view label : labels) { if (key == label) { const std::string value = normalize_candidate_label(line.substr(colon + 1), category_label); if (!value.empty()) { return value; } break; } } return std::nullopt; } std::string strip_code_fence(std::string output) { output = trim_copy(std::move(output)); if (output.rfind("```", 0) != 0) { return output; } const auto first_newline = output.find('\n'); if (first_newline == std::string::npos) { return output; } const auto last_fence = output.rfind("\n```"); if (last_fence == std::string::npos || last_fence <= first_newline) { return output; } return trim_copy(output.substr(first_newline + 1, last_fence - first_newline - 1)); } std::string sanitize_categorization_output(std::string output) { output = strip_code_fence(std::move(output)); if (output.empty()) { return output; } std::vector lines; std::istringstream input(output); for (std::string line; std::getline(input, line); ) { line = trim_copy(std::move(line)); if (!line.empty()) { lines.push_back(std::move(line)); } } if (lines.empty()) { return output; } std::string category; std::string subcategory; for (auto it = lines.rbegin(); it != lines.rend(); ++it) { if (subcategory.empty()) { if (auto value = extract_labeled_value(*it, {"subcategory", "sub category"}, false)) { subcategory = std::move(*value); } } if (category.empty()) { if (auto value = extract_labeled_value(*it, {"category", "main category"}, true)) { category = std::move(*value); } } if (!category.empty() && !subcategory.empty()) { return category + " : " + subcategory; } } for (auto it = lines.rbegin(); it != lines.rend(); ++it) { if (auto pair = extract_inline_pair_from_line(*it)) { return pair->first + " : " + pair->second; } } if (!category.empty()) { return category; } return output; } std::string categorization_system_prompt() { return "You are a file categorization assistant. If the file is an installer, " "determine the type of software it installs. Base your answer on the " "filename, extension, and any directory context provided. Reply with " "exactly one line in the format
: . Main " "category must be broad (one or two words, plural). Subcategory must be " "specific, relevant, and must not repeat the main category. Do not " "explain your answer, add extra lines, or use label words like " "'Category' or 'Subcategory'. If uncertain, make your best guess from " "the name only."; } int prompt_token_budget(int context_tokens, int max_tokens) { if (context_tokens <= 0) { return 0; } const int generation_reserve = std::max(32, max_tokens); return std::max(1, context_tokens - generation_reserve); } std::string truncate_with_ellipsis(std::string value, std::size_t limit) { if (value.size() <= limit) { return value; } if (limit <= 3) { value.resize(limit); return value; } value.resize(limit - 3); value += "..."; return value; } std::string shrink_user_prompt_for_context(const std::string& prompt, int attempt) { static const std::array kSummaryBudgets = {1200, 800, 500, 300}; static const std::array kPromptBudgets = {1800, 1400, 1000, 700}; std::string trimmed = prompt; const auto summary_marker = trimmed.find("\nDocument summary: "); if (summary_marker != std::string::npos) { const auto file_name_marker = trimmed.find("\nFile name:", summary_marker + 1); const auto directory_name_marker = trimmed.find("\nDirectory name:", summary_marker + 1); std::size_t suffix_start = std::string::npos; if (file_name_marker != std::string::npos) { suffix_start = file_name_marker; } if (directory_name_marker != std::string::npos) { suffix_start = suffix_start == std::string::npos ? directory_name_marker : std::min(suffix_start, directory_name_marker); } if (suffix_start == std::string::npos) { suffix_start = trimmed.size(); } const std::size_t summary_start = summary_marker + std::string("\nDocument summary: ").size(); const std::size_t summary_length = suffix_start > summary_start ? suffix_start - summary_start : 0; const std::size_t budget = kSummaryBudgets[std::min( static_cast(attempt), kSummaryBudgets.size() - 1)]; if (summary_length > budget) { const std::string prefix = trimmed.substr(0, summary_start); const std::string summary = truncate_with_ellipsis(trimmed.substr(summary_start, summary_length), budget); const std::string suffix = trimmed.substr(suffix_start); return prefix + summary + suffix; } } const std::size_t budget = kPromptBudgets[std::min( static_cast(attempt), kPromptBudgets.size() - 1)]; if (trimmed.size() > budget) { return truncate_with_ellipsis(trimmed, budget); } return trimmed; } bool is_probably_integrated_gpu(ggml_backend_dev_t device, enum ggml_backend_dev_type type) { #if defined(AI_FILE_SORTER_GGML_HAS_IGPU_ENUM) (void) device; return type == GGML_BACKEND_DEVICE_TYPE_IGPU; #else (void) type; const auto matches_hint = [](const char * value) { if (!value || value[0] == '\0') { return false; } constexpr std::array hints = {"integrated", "apu", "shared", "uma"}; const std::string_view view(value); for (const std::string_view hint : hints) { if (case_insensitive_contains(view, hint)) { return true; } } return false; }; return matches_hint(ggml_backend_dev_name(device)) || matches_hint(ggml_backend_dev_description(device)); #endif } void load_ggml_backends_once(const std::shared_ptr& logger) { static bool loaded = false; if (loaded) { return; } const char* ggml_dir = std::getenv("AI_FILE_SORTER_GGML_DIR"); if (ggml_dir && ggml_dir[0] != '\0') { if (logger) { logger->info("Loading ggml backends from '{}'", ggml_dir); } ggml_backend_load_all_from_path(ggml_dir); } else { ggml_backend_load_all(); } loaded = true; } using BackendMemoryInfo = TestHooks::BackendMemoryInfo; using BackendMemoryProbe = TestHooks::BackendMemoryProbe; using BackendAvailabilityProbe = TestHooks::BackendAvailabilityProbe; BackendMemoryProbe& backend_memory_probe_slot() { static BackendMemoryProbe probe; return probe; } BackendAvailabilityProbe& backend_availability_probe_slot() { static BackendAvailabilityProbe probe; return probe; } bool query_backend_available_impl(std::string_view backend_name) { if (backend_name.empty()) { return false; } const std::string backend_name_str(backend_name); ggml_backend_reg_t backend_reg = ggml_backend_reg_by_name(backend_name_str.c_str()); if (!backend_reg) { return false; } return ggml_backend_reg_dev_count(backend_reg) > 0; } bool resolve_backend_available(std::string_view backend_name) { if (auto& probe = backend_availability_probe_slot()) { return probe(backend_name); } return query_backend_available_impl(backend_name); } bool backend_name_matches(const char *name, std::string_view backend_name) { if (backend_name.empty()) { return true; } return name && case_insensitive_contains(name, backend_name); } std::optional build_backend_memory_info(ggml_backend_dev_t device, std::string_view backend_name) { if (!device) { return std::nullopt; } const auto type = ggml_backend_dev_type(device); if (type != GGML_BACKEND_DEVICE_TYPE_GPU) { return std::nullopt; } auto * reg = ggml_backend_dev_backend_reg(device); const char * name = reg ? ggml_backend_reg_name(reg) : nullptr; if (!backend_name_matches(name, backend_name)) { return std::nullopt; } size_t free_bytes = 0; size_t total_bytes = 0; ggml_backend_dev_memory(device, &free_bytes, &total_bytes); if (free_bytes == 0 && total_bytes == 0) { return std::nullopt; } BackendMemoryInfo info; info.memory.free_bytes = free_bytes; info.memory.total_bytes = (total_bytes != 0) ? total_bytes : free_bytes; info.is_integrated = is_probably_integrated_gpu(device, type); info.name = name ? name : ""; return info; } std::optional query_backend_memory_metrics_impl(std::string_view backend_name) { const size_t device_count = ggml_backend_dev_count(); BackendMemoryInfo best{}; bool found = false; for (size_t i = 0; i < device_count; ++i) { auto * device = ggml_backend_dev_get(i); const auto info = build_backend_memory_info(device, backend_name); if (!info.has_value()) { continue; } if (!found || info->memory.total_bytes > best.memory.total_bytes) { best = *info; found = true; } } if (found) { return best; } return std::nullopt; } [[maybe_unused]] std::optional resolve_backend_memory(std::string_view backend_name) { if (auto& probe = backend_memory_probe_slot()) { return probe(backend_name); } return query_backend_memory_metrics_impl(backend_name); } } // namespace namespace TestHooks { void set_backend_memory_probe(BackendMemoryProbe probe) { backend_memory_probe_slot() = std::move(probe); } void reset_backend_memory_probe() { backend_memory_probe_slot() = BackendMemoryProbe{}; } void set_backend_availability_probe(BackendAvailabilityProbe probe) { backend_availability_probe_slot() = std::move(probe); } void reset_backend_availability_probe() { backend_availability_probe_slot() = BackendAvailabilityProbe{}; } } // namespace TestHooks namespace { bool read_file_prefix(std::ifstream& file, std::vector& buffer, std::size_t requested_bytes, std::size_t& bytes_read) { const auto compute_safe_request = [&](std::size_t& safe_request) -> bool { if (requested_bytes == 0 || requested_bytes > buffer.size()) { return false; } const auto max_streamsize = static_cast(std::numeric_limits::max()); const std::size_t clamped_request = std::min(requested_bytes, buffer.size()); safe_request = std::min(clamped_request, max_streamsize); return safe_request > 0; }; const auto validate_read_count = [&](std::streamsize read_count, std::size_t to_request) -> bool { if (read_count <= 0) { return false; } if (read_count > static_cast(to_request) || static_cast(read_count) > buffer.size()) { return false; } return true; }; std::size_t safe_request = 0; if (!compute_safe_request(safe_request)) { return false; } const std::streamsize to_request = static_cast(safe_request); file.read(buffer.data(), to_request); if (!file && !file.eof()) { return false; } const std::streamsize read_count = file.gcount(); if (!validate_read_count(read_count, safe_request)) { return false; } bytes_read = static_cast(read_count); return true; } uint32_t read_le32(const char* ptr) { uint32_t value = 0; std::memcpy(&value, ptr, sizeof(uint32_t)); return value; } uint64_t read_le64(const char* ptr) { uint64_t value = 0; std::memcpy(&value, ptr, sizeof(uint64_t)); return value; } std::optional read_uint_value(uint32_t type, const char* ptr, std::size_t available_bytes) { switch (type) { case 4: // GGUF_TYPE_UINT32 case 5: // GGUF_TYPE_INT32: if (available_bytes >= sizeof(uint32_t)) { return static_cast(read_le32(ptr)); } break; case 10: // GGUF_TYPE_UINT64 case 11: // GGUF_TYPE_INT64 if (available_bytes >= sizeof(uint64_t)) { return static_cast(read_le64(ptr)); } break; default: break; } return std::nullopt; } std::optional read_gguf_numeric(gguf_context* ctx, int64_t id) { const enum gguf_type type = gguf_get_kv_type(ctx, id); switch (type) { case GGUF_TYPE_INT16: return static_cast(gguf_get_val_i16(ctx, id)); case GGUF_TYPE_INT32: return gguf_get_val_i32(ctx, id); case GGUF_TYPE_INT64: return static_cast(gguf_get_val_i64(ctx, id)); case GGUF_TYPE_UINT16: return static_cast(gguf_get_val_u16(ctx, id)); case GGUF_TYPE_UINT32: return static_cast(gguf_get_val_u32(ctx, id)); case GGUF_TYPE_UINT64: return static_cast(gguf_get_val_u64(ctx, id)); default: return std::nullopt; } } std::optional try_block_count_keys(gguf_context* ctx, const std::array& keys) { for (const char* key : keys) { const int64_t id = gguf_find_key(ctx, key); if (id < 0) { continue; } if (auto value = read_gguf_numeric(ctx, id)) { return value; } } return std::nullopt; } std::optional infer_block_count_from_tensors(gguf_context* ctx) { const int64_t tensor_count = gguf_get_n_tensors(ctx); int32_t max_layer = -1; for (int64_t i = 0; i < tensor_count; ++i) { const char* tname = gguf_get_tensor_name(ctx, i); if (!tname) { continue; } int32_t current = -1; for (const char* p = tname; *p; ++p) { if (std::isdigit(static_cast(*p))) { int value = 0; while (*p && std::isdigit(static_cast(*p))) { value = value * 10 + (*p - '0'); ++p; } current = std::max(current, value); } } if (current > max_layer) { max_layer = current; } } if (max_layer >= 0) { return max_layer + 1; // zero-indexed } return std::nullopt; } bool format_prompt(llama_model* model, std::string_view system_prompt, std::string_view user_prompt, std::string& final_prompt) { if (!model) { return false; } const char* tmpl = llama_model_chat_template(model, nullptr); if (!tmpl || tmpl[0] == '\0') { final_prompt.clear(); if (!system_prompt.empty()) { final_prompt.append(system_prompt); final_prompt.append("\n\n"); } final_prompt.append(user_prompt); return true; } std::vector owned_messages; owned_messages.reserve(system_prompt.empty() ? 1 : 2); std::vector messages; messages.reserve(system_prompt.empty() ? 1 : 2); if (!system_prompt.empty()) { owned_messages.emplace_back(system_prompt); messages.push_back({"system", owned_messages.back().c_str()}); } owned_messages.emplace_back(user_prompt); messages.push_back({"user", owned_messages.back().c_str()}); std::size_t estimated_size = 4096; for (const auto& message : owned_messages) { estimated_size += message.size() * 2; } std::vector formatted_prompt(estimated_size); int actual_len = llama_chat_apply_template(tmpl, messages.data(), messages.size(), true, formatted_prompt.data(), static_cast(formatted_prompt.size())); if (actual_len < 0) { return false; } if (actual_len >= static_cast(formatted_prompt.size())) { formatted_prompt.resize(static_cast(actual_len) + 1); actual_len = llama_chat_apply_template(tmpl, messages.data(), messages.size(), true, formatted_prompt.data(), static_cast(formatted_prompt.size())); if (actual_len < 0 || actual_len >= static_cast(formatted_prompt.size())) { return false; } } final_prompt.assign(formatted_prompt.data(), static_cast(actual_len)); return true; } bool tokenize_prompt(const llama_vocab* vocab, const std::string& final_prompt, std::vector& prompt_tokens, int& n_prompt, const std::shared_ptr& logger) { n_prompt = -llama_tokenize(vocab, final_prompt.c_str(), final_prompt.size(), nullptr, 0, true, true); if (n_prompt <= 0) { if (logger) { logger->error("Failed to determine token count for prompt"); } return false; } prompt_tokens.resize(static_cast(n_prompt)); if (llama_tokenize(vocab, final_prompt.c_str(), final_prompt.size(), prompt_tokens.data(), prompt_tokens.size(), true, true) < 0) { if (logger) { logger->error("Tokenization failed for prompt"); } return false; } return true; } std::string run_generation_loop(llama_context* ctx, llama_sampler* smpl, std::vector& prompt_tokens, int n_prompt, int max_tokens, const std::shared_ptr& logger, const llama_vocab* vocab) { const int ctx_n_ctx = static_cast(llama_n_ctx(ctx)); int ctx_n_batch = static_cast(llama_n_batch(ctx)); if (ctx_n_batch <= 0) { ctx_n_batch = ctx_n_ctx; } const int prompt_budget = prompt_token_budget(ctx_n_ctx, max_tokens); if (prompt_budget > 0 && n_prompt > prompt_budget) { const int overflow = n_prompt - prompt_budget; if (overflow > 0 && overflow < n_prompt) { if (logger) { logger->warn("Prompt tokens ({}) exceed prompt budget ({}) by {}; truncating oldest tokens", n_prompt, prompt_budget, overflow); } prompt_tokens.erase(prompt_tokens.begin(), prompt_tokens.begin() + overflow); n_prompt = prompt_budget; } } int n_pos = 0; while (n_pos < n_prompt) { const int chunk = std::min(ctx_n_batch, n_prompt - n_pos); llama_batch batch = llama_batch_get_one(prompt_tokens.data() + n_pos, chunk); if (llama_decode(ctx, batch)) { if (logger) { logger->warn("llama_decode returned non-zero status during prompt eval; aborting generation"); } return std::string(); } n_pos += chunk; } std::string output; int generated_tokens = 0; while (generated_tokens < max_tokens) { llama_token new_token_id = llama_sampler_sample(smpl, ctx, -1); if (llama_vocab_is_eog(vocab, new_token_id)) { break; } char buf[128]; int n = llama_token_to_piece(vocab, new_token_id, buf, sizeof(buf), 0, true); if (n < 0) { break; } output.append(buf, n); generated_tokens++; llama_batch batch = llama_batch_get_one(&new_token_id, 1); if (llama_decode(ctx, batch)) { if (logger) { logger->warn("llama_decode returned non-zero status; aborting generation"); } break; } } while (!output.empty() && std::isspace(static_cast(output.front()))) { output.erase(output.begin()); } return output; } std::optional parse_block_count_entry(const std::vector& buffer, std::size_t bytes_read, std::size_t key_pos, std::string_view key) { if (key_pos < sizeof(uint64_t)) { return std::nullopt; } const uint64_t declared_len = read_le64(buffer.data() + key_pos - sizeof(uint64_t)); if (declared_len != key.size()) { return std::nullopt; } const std::size_t type_offset = key_pos + key.size(); if (type_offset + sizeof(uint32_t) > bytes_read) { return std::nullopt; } const uint32_t type = read_le32(buffer.data() + type_offset); const std::size_t value_offset = type_offset + sizeof(uint32_t); if (value_offset >= bytes_read) { return std::nullopt; } const std::size_t available = bytes_read - value_offset; return read_uint_value(type, buffer.data() + value_offset, available); } std::optional extract_block_count_gguf(const std::string& model_path) { gguf_init_params params{}; params.no_alloc = true; gguf_context* ctx = gguf_init_from_file(model_path.c_str(), params); if (!ctx) { return std::nullopt; } auto cleanup = std::unique_ptr(ctx); static const std::array block_keys = { "llama.block_count", "llama.layer_count", "llama.n_layer", "qwen.block_count", "qwen2.block_count", "block_count" }; if (auto meta_val = try_block_count_keys(ctx, block_keys)) { return meta_val; } if (auto inferred = infer_block_count_from_tensors(ctx)) { return inferred; } return std::nullopt; } std::optional extract_block_count(const std::string & model_path) { if (const auto via_ctx = extract_block_count_gguf(model_path)) { return via_ctx; } std::ifstream file(model_path, std::ios::binary); if (!file) { return std::nullopt; } constexpr std::size_t kScanBytes = 8 * 1024 * 1024; // first 8 MiB should contain metadata std::vector buffer(kScanBytes); std::streamsize to_read = static_cast(buffer.size()); std::error_code size_ec; const auto file_size = std::filesystem::file_size(model_path, size_ec); if (!size_ec) { to_read = static_cast(std::min(file_size, buffer.size())); } if (to_read <= 0 || static_cast(to_read) > buffer.size()) { return std::nullopt; } std::size_t bytes_read = 0; if (!read_file_prefix(file, buffer, static_cast(to_read), bytes_read)) { return std::nullopt; } const std::string_view data(buffer.data(), bytes_read); [[maybe_unused]] static const std::string_view candidate_keys[] = { "llama.block_count", "llama.layer_count", "llama.n_layer", "qwen.block_count", "qwen2.block_count", "block_count", }; for (const auto & key : candidate_keys) { std::size_t pos = data.find(key); while (pos != std::string_view::npos) { if (const auto parsed_value = parse_block_count_entry(buffer, bytes_read, pos, key)) { return parsed_value; } pos = data.find(key, pos + 1); } } return std::nullopt; } struct AutoGpuLayerEstimation { int32_t layers = -1; std::string reason; }; #if defined(GGML_USE_METAL) AutoGpuLayerEstimation estimate_gpu_layers_for_metal(const std::string & model_path, const MetalDeviceInfo & device_info) { AutoGpuLayerEstimation result; if (!device_info.valid()) { result.layers = -1; result.reason = "no GPU memory metrics available"; return result; } std::error_code ec; const auto file_size = std::filesystem::file_size(model_path, ec); if (ec) { result.layers = -1; result.reason = "model file size unavailable"; return result; } const auto block_count_opt = extract_block_count(model_path); if (!block_count_opt.has_value() || block_count_opt.value() <= 0) { result.layers = -1; result.reason = "model block count not found"; return result; } const int32_t total_layers = block_count_opt.value(); const double bytes_per_layer = static_cast(file_size) / static_cast(total_layers); // Prefer reported free memory, but fall back to a fraction of total RAM on unified-memory systems. double approx_free = static_cast(device_info.free_bytes); double total_bytes = static_cast(device_info.total_bytes); if (approx_free <= 0.0) { approx_free = total_bytes * 0.6; // assume we can use ~60% of total RAM when free info is missing } const double safety_reserve = std::max(total_bytes * 0.10, 512.0 * 1024.0 * 1024.0); // keep at least 10% or 512 MiB free double budget_bytes = std::max(approx_free - safety_reserve, total_bytes * 0.35); // use at least 35% of total as budget budget_bytes = std::min(budget_bytes, total_bytes * 0.80); // never try to use more than 80% of RAM if (budget_bytes <= 0.0 || bytes_per_layer <= 0.0) { result.layers = 0; result.reason = "insufficient GPU memory budget"; return result; } // Account for temporary buffers / fragmentation. const double overhead_factor = 1.20; int32_t estimated_layers = static_cast(std::floor(budget_bytes / (bytes_per_layer * overhead_factor))); estimated_layers = std::clamp(estimated_layers, 1, total_layers); result.layers = estimated_layers; if (estimated_layers == 0) { result.reason = "model layers larger than available GPU headroom"; } else { result.reason = "estimated from GPU memory headroom"; } return result; } #endif // defined(GGML_USE_METAL) namespace { struct LayerMetrics { int32_t total_layers{0}; double bytes_per_layer{0.0}; }; bool populate_layer_metrics(const std::string& model_path, AutoGpuLayerEstimation& result, LayerMetrics& metrics) { std::error_code ec; const auto file_size = std::filesystem::file_size(model_path, ec); if (ec) { result.layers = -1; result.reason = "model file size unavailable"; return false; } const auto block_count_opt = extract_block_count(model_path); if (!block_count_opt.has_value() || block_count_opt.value() <= 0) { result.layers = -1; result.reason = "model block count not found"; return false; } metrics.total_layers = block_count_opt.value(); metrics.bytes_per_layer = static_cast(file_size) / static_cast(metrics.total_layers); return true; } struct CudaBudget { double approx_free{0.0}; double usable_total{0.0}; double budget_bytes{0.0}; }; bool compute_cuda_budget(const Utils::CudaMemoryInfo& memory_info, double bytes_per_layer, AutoGpuLayerEstimation& result, CudaBudget& budget) { if (!memory_info.valid()) { result.layers = -1; result.reason = "CUDA memory metrics unavailable"; return false; } budget.approx_free = static_cast(memory_info.free_bytes); double total_bytes = static_cast(memory_info.total_bytes); if (total_bytes <= 0.0) { total_bytes = budget.approx_free; } budget.usable_total = std::max(total_bytes, budget.approx_free); if (budget.usable_total <= 0.0) { result.layers = 0; result.reason = "CUDA memory metrics invalid"; return false; } if (budget.approx_free <= 0.0) { budget.approx_free = budget.usable_total * 0.80; } else if (budget.approx_free > budget.usable_total) { budget.approx_free = budget.usable_total; } if (budget.approx_free <= 0.0 || bytes_per_layer <= 0.0) { result.layers = 0; result.reason = "insufficient CUDA memory metrics"; return false; } const double safety_reserve = std::max(budget.usable_total * 0.05, 192.0 * 1024.0 * 1024.0); budget.budget_bytes = budget.approx_free - safety_reserve; if (budget.budget_bytes <= 0.0) { budget.budget_bytes = budget.approx_free * 0.75; } const double max_budget = std::min(budget.approx_free * 0.98, budget.usable_total * 0.90); const double min_budget = budget.usable_total * 0.45; budget.budget_bytes = std::clamp(budget.budget_bytes, min_budget, max_budget); return true; } bool finalize_cuda_estimate(const LayerMetrics& metrics, const CudaBudget& budget, AutoGpuLayerEstimation& result) { constexpr double overhead_factor = 1.08; const double denominator = metrics.bytes_per_layer * overhead_factor; if (denominator <= 0.0) { result.layers = 0; result.reason = "invalid CUDA layer parameters"; return false; } int32_t estimated_layers = static_cast(std::floor(budget.budget_bytes / denominator)); if (estimated_layers <= 0) { result.layers = 0; result.reason = "insufficient CUDA memory budget"; return false; } result.layers = std::clamp(estimated_layers, 1, metrics.total_layers); result.reason = "estimated from CUDA memory headroom"; return true; } } // namespace [[maybe_unused]] AutoGpuLayerEstimation estimate_gpu_layers_for_cuda(const std::string & model_path, const Utils::CudaMemoryInfo & memory_info) { AutoGpuLayerEstimation result; LayerMetrics metrics; if (!populate_layer_metrics(model_path, result, metrics)) { return result; } CudaBudget budget; if (!compute_cuda_budget(memory_info, metrics.bytes_per_layer, result, budget)) { return result; } if (!finalize_cuda_estimate(metrics, budget, result)) { return result; } return result; } enum class PreferredBackend { Auto, Cpu, Cuda, Vulkan }; [[maybe_unused]] PreferredBackend detect_preferred_backend() { const char* env = std::getenv("AI_FILE_SORTER_GPU_BACKEND"); if (!env || *env == '\0') { return PreferredBackend::Auto; } std::string value(env); std::transform(value.begin(), value.end(), value.begin(), [](unsigned char c) { return static_cast(std::tolower(c)); }); if (value == "cuda") { return PreferredBackend::Cuda; } if (value == "vulkan") { return PreferredBackend::Vulkan; } if (value == "cpu") { return PreferredBackend::Cpu; } return PreferredBackend::Auto; } #ifdef GGML_USE_METAL int determine_metal_layers(const std::string& model_path, const std::shared_ptr& logger) { int gpu_layers = resolve_gpu_layer_override(); if (gpu_layers == INT_MIN) { const MetalDeviceInfo device_info = query_primary_gpu_device(); const auto estimation = estimate_gpu_layers_for_metal(model_path, device_info); gpu_layers = (estimation.layers >= 0) ? estimation.layers : -1; if (logger) { const double to_mib = 1024.0 * 1024.0; logger->info( "Metal device '{}' total {:.1f} MiB, free {:.1f} MiB -> n_gpu_layers={} ({})", device_info.name.empty() ? "GPU" : device_info.name, device_info.total_bytes / to_mib, device_info.free_bytes / to_mib, gpu_layers_to_string(gpu_layers), estimation.reason ); } } else if (logger) { logger->info("Using Metal backend with explicit n_gpu_layers override={}", gpu_layers_to_string(gpu_layers)); } return gpu_layers; } #else bool apply_cpu_backend(llama_model_params& params, PreferredBackend backend_pref, const std::shared_ptr& logger) { if (backend_pref != PreferredBackend::Cpu) { return false; } params.n_gpu_layers = 0; set_env_var("GGML_DISABLE_CUDA", "1"); if (logger) { logger->info("GPU backend disabled via AI_FILE_SORTER_GPU_BACKEND=cpu"); } return true; } bool apply_vulkan_override(llama_model_params& params, int override_layers, const std::shared_ptr& logger) { if (override_layers == INT_MIN) { return false; } if (override_layers <= 0) { params.n_gpu_layers = 0; if (logger) { logger->info("Vulkan backend requested but AI_FILE_SORTER_N_GPU_LAYERS <= 0; using CPU instead."); } return true; } params.n_gpu_layers = override_layers; if (logger) { logger->info("Using Vulkan backend with explicit n_gpu_layers override={}", gpu_layers_to_string(override_layers)); } return true; } Utils::CudaMemoryInfo cap_integrated_gpu_memory(const BackendMemoryInfo& backend_memory, const std::shared_ptr& logger) { Utils::CudaMemoryInfo adjusted = backend_memory.memory; if (!backend_memory.is_integrated) { return adjusted; } constexpr size_t igpu_cap_bytes = static_cast(4ULL) * 1024ULL * 1024ULL * 1024ULL; // 4 GiB adjusted.free_bytes = std::min(adjusted.free_bytes, igpu_cap_bytes); adjusted.total_bytes = std::min(adjusted.total_bytes, igpu_cap_bytes); if (logger) { const double to_mib = 1024.0 * 1024.0; logger->info("Vulkan device reported as integrated GPU; capping usable memory to {:.1f} MiB", igpu_cap_bytes / to_mib); } return adjusted; } void log_vulkan_estimation(const Utils::CudaMemoryInfo& memory, const BackendMemoryInfo& original, const AutoGpuLayerEstimation& estimation, int resolved_layers, const std::shared_ptr& logger) { if (!logger) { return; } const double to_mib = 1024.0 * 1024.0; const char* device_label = original.name.empty() ? "Vulkan device" : original.name.c_str(); logger->info( "{} total {:.1f} MiB, free {:.1f} MiB -> n_gpu_layers={} ({})", device_label, memory.total_bytes / to_mib, memory.free_bytes / to_mib, gpu_layers_to_string(resolved_layers), estimation.reason.empty() ? "auto-estimated" : estimation.reason); } bool finalize_vulkan_layers(const AutoGpuLayerEstimation& estimation, const Utils::CudaMemoryInfo& memory, llama_model_params& params, const BackendMemoryInfo& original, const std::shared_ptr& logger) { if (estimation.layers > 0) { params.n_gpu_layers = estimation.layers; log_vulkan_estimation(memory, original, estimation, params.n_gpu_layers, logger); return true; } params.n_gpu_layers = -1; if (logger) { logger->warn( "Vulkan estimator could not determine n_gpu_layers ({}); leaving llama.cpp auto (-1).", estimation.reason.empty() ? "no detail" : estimation.reason); } return true; } bool apply_vulkan_backend(const std::string& model_path, llama_model_params& params, const std::shared_ptr& logger) { load_ggml_backends_once(logger); set_env_var("GGML_DISABLE_CUDA", "1"); if (!resolve_backend_available("Vulkan")) { params.n_gpu_layers = 0; set_env_var("AI_FILE_SORTER_GPU_BACKEND", "cpu"); set_env_var("LLAMA_ARG_DEVICE", "cpu"); if (logger) { logger->warn("Vulkan backend unavailable; using CPU backend."); } return false; } const auto vk_memory = resolve_backend_memory("vulkan"); if (apply_vulkan_override(params, resolve_gpu_layer_override(), logger)) { return true; } if (!vk_memory.has_value()) { params.n_gpu_layers = 0; set_env_var("AI_FILE_SORTER_GPU_BACKEND", "cpu"); set_env_var("LLAMA_ARG_DEVICE", "cpu"); if (logger) { logger->warn("Vulkan backend memory metrics unavailable; using CPU backend."); } return false; } Utils::CudaMemoryInfo adjusted = cap_integrated_gpu_memory(*vk_memory, logger); const auto estimation = estimate_gpu_layers_for_cuda(model_path, adjusted); finalize_vulkan_layers(estimation, adjusted, params, *vk_memory, logger); return true; } bool handle_cuda_forced_off(bool cuda_forced_off, PreferredBackend backend_pref, llama_model_params& params, const std::shared_ptr& logger) { if (!cuda_forced_off) { return false; } params.n_gpu_layers = 0; set_env_var("GGML_DISABLE_CUDA", "1"); if (logger) { logger->info("CUDA disabled via GGML_DISABLE_CUDA environment override."); if (backend_pref == PreferredBackend::Cuda) { logger->warn("AI_FILE_SORTER_GPU_BACKEND=cuda but GGML_DISABLE_CUDA forces CPU fallback."); } } return true; } void disable_cuda_backend(llama_model_params& params, const std::shared_ptr& logger, const std::string& reason) { params.n_gpu_layers = 0; set_env_var("GGML_DISABLE_CUDA", "1"); if (logger) { logger->info("CUDA backend disabled: {}", reason); } } bool ensure_cuda_available(llama_model_params& params, const std::shared_ptr& logger) { if (Utils::is_cuda_available()) { return true; } disable_cuda_backend(params, logger, "CUDA backend unavailable; using CPU backend"); std::cout << "No supported GPU backend detected. Running on CPU.\n"; return false; } bool apply_ngl_override(int override_layers, llama_model_params& params, const std::shared_ptr& logger) { if (override_layers == INT_MIN) { return false; } if (override_layers <= 0) { disable_cuda_backend( params, logger, fmt::format("AI_FILE_SORTER_N_GPU_LAYERS={} forcing CPU fallback", override_layers)); return true; } params.n_gpu_layers = override_layers; if (logger) { logger->info("Using explicit CUDA n_gpu_layers override {}", gpu_layers_to_string(override_layers)); } std::cout << "ngl override: " << params.n_gpu_layers << std::endl; return true; } struct NglEstimationResult { int candidate_layers{0}; int heuristic_layers{0}; }; NglEstimationResult estimate_ngl_from_cuda_info(const std::string& model_path, const std::shared_ptr& logger) { NglEstimationResult result; AutoGpuLayerEstimation estimation{}; std::optional cuda_info = Utils::query_cuda_memory(); if (!cuda_info.has_value()) { if (logger) { logger->warn("Unable to query CUDA memory information, falling back to heuristic"); } return result; } estimation = estimate_gpu_layers_for_cuda(model_path, *cuda_info); result.heuristic_layers = Utils::compute_ngl_from_cuda_memory(*cuda_info); int candidate_layers = estimation.layers > 0 ? estimation.layers : 0; if (result.heuristic_layers > 0) { candidate_layers = std::max(candidate_layers, result.heuristic_layers); } result.candidate_layers = candidate_layers; if (logger) { if (estimation.layers > 0 && estimation.layers != candidate_layers) { logger->info("CUDA estimator suggested {} layers, but heuristic floor kept {}", estimation.layers, candidate_layers); } const double to_mib = 1024.0 * 1024.0; logger->info( "CUDA device total {:.1f} MiB, free {:.1f} MiB -> estimator={}, heuristic={}, chosen={} ({})", cuda_info->total_bytes / to_mib, cuda_info->free_bytes / to_mib, gpu_layers_to_string(estimation.layers), gpu_layers_to_string(result.heuristic_layers), gpu_layers_to_string(candidate_layers), estimation.reason.empty() ? "no estimation detail" : estimation.reason); } return result; } int fallback_ngl(int heuristic_layers, const std::shared_ptr& logger) { if (heuristic_layers > 0) { return heuristic_layers; } const int fallback = Utils::determine_ngl_cuda(); if (fallback > 0 && logger) { logger->info("Using heuristic CUDA fallback -> n_gpu_layers={}", gpu_layers_to_string(fallback)); } return fallback; } bool configure_cuda_backend(const std::string& model_path, llama_model_params& params, const std::shared_ptr& logger) { if (!ensure_cuda_available(params, logger)) { return false; } const int override_layers = resolve_gpu_layer_override(); if (apply_ngl_override(override_layers, params, logger)) { return true; } const NglEstimationResult estimation = estimate_ngl_from_cuda_info(model_path, logger); int ngl = estimation.candidate_layers; if (ngl <= 0) { ngl = fallback_ngl(estimation.heuristic_layers, logger); } if (ngl > 0) { params.n_gpu_layers = ngl; std::cout << "ngl: " << params.n_gpu_layers << std::endl; } else { disable_cuda_backend(params, logger, "CUDA not usable after estimation; falling back to CPU."); std::cout << "CUDA not usable, falling back to CPU.\n"; } return true; } #endif } // namespace void silent_logger(enum ggml_log_level, const char *, void *) {} void llama_debug_logger(enum ggml_log_level level, const char *text, void *user_data) { if (auto logger = Logger::get_logger("core_logger")) { logger->log(level >= GGML_LOG_LEVEL_ERROR ? spdlog::level::err : spdlog::level::debug, "[llama.cpp] {}", text); } else { std::fprintf(stderr, "[llama.cpp] %s", text); } } bool llama_logs_enabled_from_env() { const char* env = std::getenv("AI_FILE_SORTER_LLAMA_LOGS"); if (!env || env[0] == '\0') { env = std::getenv("LLAMA_CPP_DEBUG_LOGS"); } if (!env || env[0] == '\0') { return false; } std::string value{env}; std::transform(value.begin(), value.end(), value.begin(), [](unsigned char c) { return static_cast(std::tolower(c)); }); return value != "0" && value != "false" && value != "off" && value != "no"; } LocalLLMClient::LocalLLMClient(const std::string& model_path, FallbackDecisionCallback fallback_decision_callback) : model_path(model_path), fallback_decision_callback_(std::move(fallback_decision_callback)) { auto logger = Logger::get_logger("core_logger"); if (logger) { logger->info("Initializing local LLM client with model '{}'", model_path); } configure_llama_logging(logger); load_ggml_backends_once(logger); const int context_length = std::clamp(resolve_context_length(), 512, 8192); llama_model_params model_params = prepare_model_params(logger); if (logger) { logger->info("Configured context length {} token(s) for local LLM", context_length); } model_params = load_model_or_throw(model_params, logger); configure_context(context_length, model_params); } void LocalLLMClient::configure_llama_logging(const std::shared_ptr& logger) const { if (llama_logs_enabled_from_env()) { llama_log_set(llama_debug_logger, nullptr); if (logger) { logger->info("Enabled detailed llama.cpp logging via environment configuration"); } } else { llama_log_set(silent_logger, nullptr); } } llama_model_params build_model_params_for_path(const std::string& model_path, const std::shared_ptr& logger) { load_ggml_backends_once(logger); llama_model_params model_params = llama_model_default_params(); #ifdef GGML_USE_METAL const char* backend_env = std::getenv("AI_FILE_SORTER_GPU_BACKEND"); if (backend_env) { std::string value(backend_env); std::transform(value.begin(), value.end(), value.begin(), [](unsigned char c) { return static_cast(std::tolower(c)); }); if (value == "cpu") { if (logger) { logger->info("AI_FILE_SORTER_GPU_BACKEND=cpu set; disabling Metal and using CPU backend."); } model_params.n_gpu_layers = 0; return model_params; } } if (!metal_backend_available(logger)) { model_params.n_gpu_layers = 0; return model_params; } model_params.n_gpu_layers = determine_metal_layers(model_path, logger); #else const PreferredBackend backend_pref = detect_preferred_backend(); const char* disable_env = std::getenv("GGML_DISABLE_CUDA"); const bool cuda_forced_off = disable_env && disable_env[0] != '\0' && disable_env[0] != '0'; if (apply_cpu_backend(model_params, backend_pref, logger)) { return model_params; } if (backend_pref == PreferredBackend::Vulkan) { apply_vulkan_backend(model_path, model_params, logger); return model_params; } if (handle_cuda_forced_off(cuda_forced_off, backend_pref, model_params, logger)) { return model_params; } const bool prefer_vulkan = (backend_pref == PreferredBackend::Vulkan) || (backend_pref == PreferredBackend::Auto); if (prefer_vulkan) { // Vulkan is the primary backend; keep CUDA disabled and steer llama.cpp to Vulkan. set_env_var("AI_FILE_SORTER_GPU_BACKEND", "vulkan"); set_env_var("LLAMA_ARG_DEVICE", "vulkan"); apply_vulkan_backend(model_path, model_params, logger); return model_params; } // CUDA requested explicitly. if (handle_cuda_forced_off(cuda_forced_off, backend_pref, model_params, logger)) { return model_params; } const bool cudaConfigured = configure_cuda_backend(model_path, model_params, logger); if (!cudaConfigured) { if (logger) { logger->warn("CUDA backend explicitly requested but unavailable; attempting Vulkan fallback."); } set_env_var("AI_FILE_SORTER_GPU_BACKEND", "vulkan"); set_env_var("LLAMA_ARG_DEVICE", "vulkan"); apply_vulkan_backend(model_path, model_params, logger); return model_params; } #endif return model_params; } llama_model_params LocalLLMClient::prepare_model_params(const std::shared_ptr& logger) { return build_model_params_for_path(model_path, logger); } #if defined(AI_FILE_SORTER_TEST_BUILD) && !defined(GGML_USE_METAL) namespace { PreferredBackend to_internal_backend(LocalLLMTestAccess::BackendPreference preference) { switch (preference) { case LocalLLMTestAccess::BackendPreference::Cpu: return PreferredBackend::Cpu; case LocalLLMTestAccess::BackendPreference::Cuda: return PreferredBackend::Cuda; case LocalLLMTestAccess::BackendPreference::Vulkan: return PreferredBackend::Vulkan; case LocalLLMTestAccess::BackendPreference::Auto: default: return PreferredBackend::Auto; } } LocalLLMTestAccess::BackendPreference to_external_backend(PreferredBackend preference) { switch (preference) { case PreferredBackend::Cpu: return LocalLLMTestAccess::BackendPreference::Cpu; case PreferredBackend::Cuda: return LocalLLMTestAccess::BackendPreference::Cuda; case PreferredBackend::Vulkan: return LocalLLMTestAccess::BackendPreference::Vulkan; case PreferredBackend::Auto: default: return LocalLLMTestAccess::BackendPreference::Auto; } } } // namespace namespace LocalLLMTestAccess { BackendPreference detect_preferred_backend() { return to_external_backend(::detect_preferred_backend()); } bool apply_cpu_backend(llama_model_params& params, BackendPreference preference) { return ::apply_cpu_backend(params, to_internal_backend(preference), nullptr); } bool apply_vulkan_backend(const std::string& model_path, llama_model_params& params) { return ::apply_vulkan_backend(model_path, params, nullptr); } bool handle_cuda_forced_off(bool cuda_forced_off, BackendPreference preference, llama_model_params& params) { return ::handle_cuda_forced_off(cuda_forced_off, to_internal_backend(preference), params, nullptr); } bool configure_cuda_backend(const std::string& model_path, llama_model_params& params) { return ::configure_cuda_backend(model_path, params, nullptr); } llama_model_params prepare_model_params_for_testing(const std::string& model_path) { return ::build_model_params_for_path(model_path, nullptr); } } // namespace LocalLLMTestAccess #endif // AI_FILE_SORTER_TEST_BUILD && !GGML_USE_METAL #ifdef AI_FILE_SORTER_TEST_BUILD namespace LocalLLMTestAccess { std::string sanitize_output_for_testing(const std::string& output) { return sanitize_categorization_output(output); } } // namespace LocalLLMTestAccess #endif llama_model_params LocalLLMClient::load_model_or_throw(llama_model_params model_params, const std::shared_ptr& logger) { auto try_load = [&](const llama_model_params& params) { model = llama_model_load_from_file(model_path.c_str(), params); if (!model) { return false; } if (logger) { logger->info("Loaded local model '{}'", model_path); } vocab = llama_model_get_vocab(model); return true; }; if (try_load(model_params)) { return model_params; } if (model_params.n_gpu_layers != 0) { if (logger) { logger->warn("Failed to load model with GPU backend; retrying on CPU."); } if (!allow_gpu_fallback(fallback_decision_callback_, logger, "model load failure")) { if (logger) { logger->warn("GPU fallback declined during model load; aborting."); } throw std::runtime_error("GPU backend failed to initialize and CPU fallback was declined."); } notify_status(Status::GpuFallbackToCpu); set_env_var("AI_FILE_SORTER_GPU_BACKEND", "cpu"); set_env_var("LLAMA_ARG_DEVICE", "cpu"); model_params.n_gpu_layers = 0; if (try_load(model_params)) { return model_params; } } if (logger) { logger->error("Failed to load model from '{}'", model_path); } throw std::runtime_error("Failed to load model"); } void LocalLLMClient::configure_context(int context_length, const llama_model_params& model_params) { ctx_params = llama_context_default_params(); ctx_params.n_ctx = context_length; ctx_params.n_batch = context_length; #ifdef GGML_USE_METAL if (model_params.n_gpu_layers != 0) { ctx_params.offload_kqv = true; } #else (void)model_params; #endif } std::string LocalLLMClient::make_prompt(const std::string& file_name, const std::string& file_path, FileType file_type, const std::string& consistency_context) { std::ostringstream prompt; prompt << (file_type == FileType::File ? "Categorize this file.\n" : "Categorize this directory.\n"); if (!file_path.empty()) { prompt << "Full path: " << file_path << "\n"; } prompt << (file_type == FileType::File ? "File name: " : "Directory name: ") << file_name << "\n"; if (!consistency_context.empty()) { prompt << "\n" << consistency_context << "\n"; } return prompt.str(); } std::string LocalLLMClient::generate_response(const std::string& prompt, int n_predict, bool apply_sanitizer, const std::string& system_prompt) { auto logger = Logger::get_logger("core_logger"); if (logger) { logger->debug("Generating response with prompt length {} chars target {} tokens", prompt.size(), n_predict); } struct ContextAttempt { int n_ctx; int n_batch; }; auto build_context_attempts = [](int n_ctx, int n_batch) { std::vector attempts; auto add_attempt = [&](int ctx, int batch) { ctx = std::max(ctx, 512); batch = std::clamp(batch, 1, ctx); if (ctx > n_ctx || batch > n_batch) { return; } if (ctx == n_ctx && batch == n_batch) { return; } for (const auto& existing : attempts) { if (existing.n_ctx == ctx && existing.n_batch == batch) { return; } } attempts.push_back({ctx, batch}); }; add_attempt(std::min(n_ctx, 2048), std::min(n_batch, 1024)); add_attempt(std::min(n_ctx, 1024), std::min(n_batch, 512)); add_attempt(std::min(n_ctx, 512), std::min(n_batch, 256)); return attempts; }; auto try_init_context = [&](const llama_context_params& base_params, int n_ctx, int n_batch, llama_context_params& resolved_params) -> llama_context* { llama_context_params attempt = base_params; attempt.n_ctx = n_ctx; attempt.n_batch = std::min(n_batch, n_ctx); auto* ctx = llama_init_from_model(model, attempt); if (ctx) { resolved_params = attempt; } return ctx; }; auto init_context_with_retries = [&](const llama_context_params& base_params, bool cpu_attempt, llama_context_params& resolved_params) -> llama_context* { auto* ctx = try_init_context(base_params, base_params.n_ctx, base_params.n_batch, resolved_params); if (ctx) { return ctx; } if (logger) { logger->warn("Failed to initialize llama context (n_ctx={}, n_batch={}); retrying with smaller buffers{}", base_params.n_ctx, base_params.n_batch, cpu_attempt ? " on CPU" : ""); } for (const auto& attempt : build_context_attempts(base_params.n_ctx, base_params.n_batch)) { if (logger) { logger->warn("Retrying llama context init with n_ctx={}, n_batch={}{}", attempt.n_ctx, attempt.n_batch, cpu_attempt ? " on CPU" : ""); } ctx = try_init_context(base_params, attempt.n_ctx, attempt.n_batch, resolved_params); if (ctx) { return ctx; } } return nullptr; }; bool allow_fallback = true; for (;;) { llama_context* ctx = nullptr; llama_sampler* smpl = nullptr; try { llama_context_params resolved_params = ctx_params; llama_context_params base_params = ctx_params; ctx = init_context_with_retries(base_params, false, resolved_params); if (!ctx && !is_cpu_backend_requested()) { if (!allow_gpu_fallback(fallback_decision_callback_, logger, "context initialization failure")) { allow_fallback = false; throw std::runtime_error("GPU backend failed during context initialization and CPU fallback was declined."); } if (logger) { logger->warn("Context init failed on GPU; reloading model on CPU and retrying."); } notify_status(Status::GpuFallbackToCpu); llama_model_params cpu_params = llama_model_default_params(); cpu_params.n_gpu_layers = 0; set_env_var("AI_FILE_SORTER_GPU_BACKEND", "cpu"); set_env_var("LLAMA_ARG_DEVICE", "cpu"); set_env_var("GGML_DISABLE_CUDA", "1"); llama_model* old_model = model; llama_model* cpu_model = llama_model_load_from_file(model_path.c_str(), cpu_params); if (!cpu_model) { if (logger) { logger->error("Failed to reload model on CPU after context init failure"); } } else { if (old_model) { llama_model_free(old_model); } model = cpu_model; vocab = llama_model_get_vocab(model); #ifdef GGML_USE_METAL base_params = ctx_params; base_params.offload_kqv = false; #else base_params = ctx_params; #endif resolved_params = base_params; ctx = init_context_with_retries(base_params, true, resolved_params); } } if (!ctx) { if (logger) { logger->error("Failed to initialize llama context"); } return ""; } ctx_params = resolved_params; smpl = llama_sampler_chain_init(llama_sampler_chain_default_params()); llama_sampler_chain_add(smpl, llama_sampler_init_min_p(0.05f, 1)); llama_sampler_chain_add(smpl, llama_sampler_init_temp(0.8f)); llama_sampler_chain_add(smpl, llama_sampler_init_dist(LLAMA_DEFAULT_SEED)); std::vector prompt_tokens; int n_prompt = 0; std::string working_prompt = prompt; std::string final_prompt; const int context_budget = prompt_token_budget(static_cast(resolved_params.n_ctx), n_predict); for (int shrink_attempt = 0;; ++shrink_attempt) { if (!format_prompt(model, system_prompt, working_prompt, final_prompt)) { if (logger) { logger->error("Failed to apply chat template to prompt"); } llama_free(ctx); llama_sampler_free(smpl); return ""; } if (!tokenize_prompt(vocab, final_prompt, prompt_tokens, n_prompt, logger)) { llama_free(ctx); llama_sampler_free(smpl); return ""; } if (context_budget <= 0 || n_prompt <= context_budget) { break; } const std::string trimmed_prompt = shrink_user_prompt_for_context(working_prompt, shrink_attempt); if (trimmed_prompt == working_prompt) { if (logger) { logger->warn("Prompt tokens ({}) still exceed prompt budget ({}); proceeding with token truncation", n_prompt, context_budget); } break; } if (logger) { logger->warn("Prompt tokens ({}) exceed prompt budget ({}); shrinking user prompt and retrying", n_prompt, context_budget); } working_prompt = trimmed_prompt; } std::string output = run_generation_loop(ctx, smpl, prompt_tokens, n_prompt, n_predict, logger, vocab); llama_sampler_reset(smpl); llama_free(ctx); llama_sampler_free(smpl); if (logger) { logger->debug("Generation complete, produced {} character(s)", output.size()); } if (apply_sanitizer) { return sanitize_output(output); } return output; } catch (const std::exception& ex) { if (ctx) { llama_free(ctx); } if (smpl) { llama_sampler_free(smpl); } if (allow_fallback && !is_cpu_backend_requested()) { if (!allow_gpu_fallback(fallback_decision_callback_, logger, "generation failure")) { allow_fallback = false; throw std::runtime_error("GPU backend failed during generation and CPU fallback was declined."); } allow_fallback = false; if (logger) { logger->warn("LLM generation failed on GPU ({}); retrying on CPU.", ex.what()); } notify_status(Status::GpuFallbackToCpu); llama_model_params cpu_params = llama_model_default_params(); cpu_params.n_gpu_layers = 0; set_env_var("AI_FILE_SORTER_GPU_BACKEND", "cpu"); set_env_var("LLAMA_ARG_DEVICE", "cpu"); set_env_var("GGML_DISABLE_CUDA", "1"); llama_model* old_model = model; llama_model* cpu_model = llama_model_load_from_file(model_path.c_str(), cpu_params); if (!cpu_model) { if (logger) { logger->error("Failed to reload model on CPU after GPU error"); } } else { if (old_model) { llama_model_free(old_model); } model = cpu_model; vocab = llama_model_get_vocab(model); #ifdef GGML_USE_METAL ctx_params.offload_kqv = false; #endif continue; } } if (logger) { logger->error("LLM generation failed: {}", ex.what()); } throw; } } } std::string LocalLLMClient::categorize_file(const std::string& file_name, const std::string& file_path, FileType file_type, const std::string& consistency_context) { if (auto logger = Logger::get_logger("core_logger")) { if (!file_path.empty()) { logger->debug("Requesting local categorization for '{}' ({}) at '{}'", file_name, to_string(file_type), file_path); } else { logger->debug("Requesting local categorization for '{}' ({})", file_name, to_string(file_type)); } } std::string prompt = make_prompt(file_name, file_path, file_type, consistency_context); const std::string system_prompt = categorization_system_prompt(); if (prompt_logging_enabled) { std::cout << "\n[DEV][PROMPT] Categorization request\n" << "[system]\n" << system_prompt << "\n" << "[user]\n" << prompt << "\n"; } std::string response = generate_response(prompt, 64, true, system_prompt); if (prompt_logging_enabled) { std::cout << "[DEV][RESPONSE] Categorization reply\n" << response << "\n"; } return response; } std::string LocalLLMClient::complete_prompt(const std::string& prompt, int max_tokens) { const int capped = max_tokens > 0 ? max_tokens : 256; return generate_response(prompt, capped, false); } std::string LocalLLMClient::sanitize_output(const std::string& output) { return sanitize_categorization_output(output); } LocalLLMClient::~LocalLLMClient() { if (auto logger = Logger::get_logger("core_logger")) { logger->debug("Destroying LocalLLMClient for model '{}'", model_path); } if (model) llama_model_free(model); } void LocalLLMClient::set_prompt_logging_enabled(bool enabled) { prompt_logging_enabled = enabled; } void LocalLLMClient::set_status_callback(StatusCallback callback) { status_callback_ = std::move(callback); } void LocalLLMClient::set_fallback_decision_callback(FallbackDecisionCallback callback) { fallback_decision_callback_ = std::move(callback); } void LocalLLMClient::notify_status(Status status) const { if (status_callback_) { status_callback_(status); } } ================================================ FILE: app/lib/Logger.cpp ================================================ #include "constants.hpp" #include "Logger.hpp" #include "Utils.hpp" #include #include #include #include std::string Logger::get_log_directory() { #ifdef _WIN32 return get_windows_log_directory(); #else return get_xdg_cache_home(); #endif } std::string Logger::get_xdg_cache_home() { const char* xdg_cache_home = std::getenv("XDG_CACHE_HOME"); if (xdg_cache_home && *xdg_cache_home) { return std::string(xdg_cache_home) + "/" + APP_NAME_DIR + "/my_app/logs"; } const char* home = std::getenv("HOME"); if (home && *home) { return std::string(home) + "/.cache/" + APP_NAME_DIR + "/logs"; } throw std::runtime_error("Failed to determine XDG_CACHE_HOME or HOME environment variable."); } std::string Logger::get_windows_log_directory() { const char* appdata = std::getenv("APPDATA"); if (appdata && *appdata) { return std::string(appdata) + "\\" + APP_NAME_DIR + "\\logs"; } throw std::runtime_error("Failed to determine APPDATA environment variable."); } void Logger::setup_loggers() { std::string log_dir = get_log_directory(); Utils::ensure_directory_exists(log_dir); auto core_log_path = log_dir + "/core.log"; auto db_log_path = log_dir + "/db.log"; auto ui_log_path = log_dir + "/ui.log"; auto core_console_sink = std::make_shared(); auto core_file_sink = std::make_shared(core_log_path, 1048576 * 5, 3); auto db_console_sink = std::make_shared(); auto db_file_sink = std::make_shared(db_log_path, 1048576 * 5, 3); auto ui_console_sink = std::make_shared(); auto ui_file_sink = std::make_shared(ui_log_path, 1048576 * 5, 3); auto core_logger = std::make_shared("core_logger", spdlog::sinks_init_list{core_console_sink, core_file_sink}); auto db_logger = std::make_shared("db_logger", spdlog::sinks_init_list{db_console_sink, db_file_sink}); auto ui_logger = std::make_shared("ui_logger", spdlog::sinks_init_list{ui_console_sink, ui_file_sink}); spdlog::register_logger(core_logger); spdlog::register_logger(db_logger); spdlog::register_logger(ui_logger); core_logger->set_level(spdlog::level::debug); db_logger->set_level(spdlog::level::debug); ui_logger->set_level(spdlog::level::debug); core_logger->flush_on(spdlog::level::info); db_logger->flush_on(spdlog::level::info); ui_logger->flush_on(spdlog::level::info); spdlog::flush_every(std::chrono::seconds(2)); spdlog::set_level(spdlog::level::debug); spdlog::info("Loggers initialized."); } std::shared_ptr Logger::get_logger(const std::string &name) { return spdlog::get(name); } ================================================ FILE: app/lib/MainApp.cpp ================================================ #include "MainApp.hpp" #include "AppInfo.hpp" #include "CategorizationSession.hpp" #include "DialogUtils.hpp" #include "ErrorMessages.hpp" #include "LLMClient.hpp" #include "GeminiClient.hpp" #include "LLMSelectionDialog.hpp" #include "Logger.hpp" #include "MainAppEditActions.hpp" #include "MainAppHelpActions.hpp" #include "Updater.hpp" #include "TranslationManager.hpp" #include "Utils.hpp" #include "Types.hpp" #include "CategoryLanguage.hpp" #include "MainAppUiBuilder.hpp" #include "SuitabilityBenchmarkDialog.hpp" #include "UiTranslator.hpp" #include "UpdaterBuildConfig.hpp" #include "LlavaImageAnalyzer.hpp" #include "DocumentTextAnalyzer.hpp" #include "ImageRenameMetadataService.hpp" #include "MediaRenameMetadataService.hpp" #include "SupportCodeManager.hpp" #include "WhitelistManagerDialog.hpp" #include "UndoManager.hpp" #ifdef AI_FILE_SORTER_TEST_BUILD #include "MainAppTestAccess.hpp" #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std::chrono_literals; namespace { std::string trim_ws_copy(const std::string& value) { const char* whitespace = " \t\n\r\f\v"; const auto start = value.find_first_not_of(whitespace); if (start == std::string::npos) { return std::string(); } const auto end = value.find_last_not_of(whitespace); return value.substr(start, end - start + 1); } std::string expand_user_path(const std::string& value) { if (value.empty() || value.front() != '~') { return value; } QString home = QDir::homePath(); if (home.isEmpty()) { return value; } if (value.size() == 1) { return home.toUtf8().toStdString(); } const char next = value[1]; if (next == '/' || next == '\\') { QString expanded = home + QString::fromUtf8(value.c_str() + 1); return expanded.toUtf8().toStdString(); } return value; } std::string normalize_directory_path(const std::string& value) { const std::string trimmed = trim_ws_copy(value); if (trimmed.empty()) { return trimmed; } const std::string expanded = expand_user_path(trimmed); const std::filesystem::path fs_path = Utils::utf8_to_path(expanded).lexically_normal(); std::string normalized = Utils::path_to_utf8(fs_path); if (fs_path.has_relative_path()) { while (normalized.size() > 1 && (normalized.back() == '/' || normalized.back() == '\\')) { normalized.pop_back(); } } return normalized; } std::string resolve_document_prompt_name(const std::string& original_name, const std::string& suggested_name) { return suggested_name.empty() ? original_name : suggested_name; } std::string build_document_prompt_path(const std::string& full_path, const std::string& prompt_name, const std::string& summary) { const auto entry_path = Utils::utf8_to_path(full_path); const std::string effective_name = prompt_name.empty() ? Utils::path_to_utf8(entry_path.filename()) : prompt_name; std::string prompt_path = Utils::path_to_utf8( entry_path.parent_path() / Utils::utf8_to_path(effective_name)); if (!summary.empty()) { prompt_path += "\nDocument summary: " + summary; } return prompt_path; } void schedule_next_support_prompt(Settings& settings, int total_files) { settings.set_next_support_prompt_threshold(total_files + 50); settings.save(); } void maybe_show_support_prompt(Settings& settings, bool& prompt_active, std::function show_prompt) { if (prompt_active) { return; } if (SupportCodeManager(Utils::utf8_to_path(settings.get_config_dir())).is_prompt_permanently_disabled()) { return; } const int total = settings.get_total_categorized_files(); int threshold = settings.get_next_support_prompt_threshold(); if (threshold <= 0) { const int base = std::max(total, 0); threshold = ((base / 50) + 1) * 50; settings.set_next_support_prompt_threshold(threshold); settings.save(); } if (total < threshold || total == 0) { return; } prompt_active = true; MainApp::SupportPromptResult result = MainApp::SupportPromptResult::NotSure; if (show_prompt) { result = show_prompt(total); } prompt_active = false; if (result == MainApp::SupportPromptResult::Support) { return; } schedule_next_support_prompt(settings, total); } void record_categorized_metrics_impl(Settings& settings, bool& prompt_active, int count, std::function show_prompt) { if (count <= 0) { return; } settings.add_categorized_files(count); settings.save(); maybe_show_support_prompt(settings, prompt_active, std::move(show_prompt)); } std::string to_utf8(const QString& value) { const QByteArray bytes = value.toUtf8(); return std::string(bytes.constData(), static_cast(bytes.size())); } std::string to_lower_copy(std::string value) { std::transform(value.begin(), value.end(), value.begin(), [](unsigned char ch) { return static_cast(std::tolower(ch)); }); return value; } bool should_offer_visual_cpu_fallback(const std::string& reason) { const std::string lowered = to_lower_copy(reason); static const char* kRetryableMarkers[] = { "failed to create llama_context", "mtmd_helper_eval_chunks failed", "out of memory", "not enough memory", "gpu memory", "vk_error_out_of_device_memory", "vk_error_out_of_host_memory", "cuda error out of memory", "cuda_error_out_of_memory" }; for (const char* marker : kRetryableMarkers) { if (lowered.find(marker) != std::string::npos) { return true; } } return false; } struct VisualLlmPaths { std::filesystem::path model_path; std::filesystem::path mmproj_path; }; bool default_text_llm_files_available() { static const char* kEnvVars[] = { "LOCAL_LLM_3B_DOWNLOAD_URL", "LOCAL_LLM_3B_LEGACY_DOWNLOAD_URL", "LOCAL_LLM_7B_DOWNLOAD_URL" }; for (const char* env_key : kEnvVars) { const char* env_url = std::getenv(env_key); if (!env_url || *env_url == '\0') { continue; } try { const std::filesystem::path path = Utils::make_default_path_to_file_from_download_url(env_url); std::error_code ec; if (!path.empty() && std::filesystem::exists(path, ec)) { return true; } } catch (...) { continue; } } return false; } std::optional resolve_mmproj_path(const std::filesystem::path& primary) { if (std::filesystem::exists(primary)) { return primary; } const auto llm_dir = std::filesystem::path(Utils::get_default_llm_destination()); static const char* kAltMmprojNames[] = { "mmproj-model-f16.gguf", "llava-v1.6-mistral-7b-mmproj-f16.gguf" }; for (const char* alt_name : kAltMmprojNames) { const auto candidate = llm_dir / alt_name; if (std::filesystem::exists(candidate)) { return candidate; } } return std::nullopt; } std::optional resolve_visual_llm_paths(std::string* error) { const char* model_url = std::getenv("LLAVA_MODEL_URL"); const char* mmproj_url = std::getenv("LLAVA_MMPROJ_URL"); if (!model_url || !*model_url || !mmproj_url || !*mmproj_url) { if (error) { *error = "Missing visual LLM download URLs. Check LLAVA_MODEL_URL and LLAVA_MMPROJ_URL."; } return std::nullopt; } const auto model_path = std::filesystem::path( Utils::make_default_path_to_file_from_download_url(model_url)); if (!std::filesystem::exists(model_path)) { if (error) { *error = "Visual LLM model file is missing: " + model_path.string(); } return std::nullopt; } const auto mmproj_primary = std::filesystem::path( Utils::make_default_path_to_file_from_download_url(mmproj_url)); const auto mmproj_path = resolve_mmproj_path(mmproj_primary); if (!mmproj_path) { if (error) { *error = "Visual LLM mmproj file is missing: " + mmproj_primary.string(); } return std::nullopt; } return VisualLlmPaths{model_path, *mmproj_path}; } bool should_use_visual_gpu() { const char* backend = std::getenv("AI_FILE_SORTER_GPU_BACKEND"); if (!backend || !*backend) { return true; } std::string value = backend; std::transform(value.begin(), value.end(), value.begin(), [](unsigned char c) { return static_cast(std::tolower(c)); }); return value != "cpu"; } std::optional read_env_bool(const char* key) { const char* value = std::getenv(key); if (!value || value[0] == '\0') { return std::nullopt; } std::string lowered = value; std::transform(lowered.begin(), lowered.end(), lowered.begin(), [](unsigned char c) { return static_cast(std::tolower(c)); }); if (lowered == "1" || lowered == "true" || lowered == "yes" || lowered == "on") { return true; } if (lowered == "0" || lowered == "false" || lowered == "no" || lowered == "off") { return false; } return std::nullopt; } std::optional read_env_int(const char* key) { const char* value = std::getenv(key); if (!value || value[0] == '\0') { return std::nullopt; } char* end_ptr = nullptr; long parsed = std::strtol(value, &end_ptr, 10); if (end_ptr == value || (end_ptr && *end_ptr != '\0')) { return std::nullopt; } if (parsed <= 0 || parsed > 100000) { return std::nullopt; } return static_cast(parsed); } int resolve_local_context_tokens() { if (auto parsed = read_env_int("AI_FILE_SORTER_CTX_TOKENS")) { return *parsed; } if (auto parsed = read_env_int("LLAMA_CPP_MAX_CONTEXT")) { return *parsed; } return 2048; } size_t resolve_document_char_budget(bool using_local_llm, int max_output_tokens) { int context_tokens = using_local_llm ? resolve_local_context_tokens() : 4096; context_tokens = std::clamp(context_tokens, 512, 8192); const int reserve_tokens = std::max(192, context_tokens / 6); const int output_tokens = std::clamp(max_output_tokens, 0, context_tokens / 2); const int prompt_tokens = std::max(256, context_tokens - reserve_tokens - output_tokens); const size_t chars_per_token = using_local_llm ? 2 : 4; return static_cast(prompt_tokens) * chars_per_token; } void split_entries_for_analysis(const std::vector& files, bool analyze_images, bool analyze_documents, bool process_images_only, bool process_documents_only, bool rename_images_only, bool rename_documents_only, bool categorize_files, bool use_full_path_keys, const std::unordered_set& renamed_files, std::vector& image_entries, std::vector& document_entries, std::vector& other_entries) { image_entries.clear(); document_entries.clear(); other_entries.clear(); image_entries.reserve(files.size()); document_entries.reserve(files.size()); other_entries.reserve(files.size()); const bool restrict_types = process_images_only || process_documents_only; const bool allow_images = !restrict_types || process_images_only; const bool allow_documents = !restrict_types || process_documents_only; const bool allow_other_files = categorize_files && !restrict_types; for (const auto& entry : files) { const std::string entry_key = use_full_path_keys ? entry.full_path : entry.file_name; if (entry.type == FileType::Directory) { if (!restrict_types) { other_entries.push_back(entry); } continue; } const bool is_image_entry = entry.type == FileType::File && LlavaImageAnalyzer::is_supported_image(entry.full_path); const bool is_document_entry = entry.type == FileType::File && DocumentTextAnalyzer::is_supported_document(entry.full_path); if (is_image_entry) { if (!allow_images) { continue; } if (analyze_images) { const bool already_renamed = renamed_files.contains(entry_key); if (already_renamed) { if (rename_images_only) { continue; } // Already-renamed images skip vision analysis and use filename/path categorization. other_entries.push_back(entry); } else { image_entries.push_back(entry); } } else if (allow_other_files) { other_entries.push_back(entry); } continue; } if (is_document_entry) { if (!allow_documents) { continue; } if (analyze_documents) { const bool already_renamed = renamed_files.contains(entry_key); if (already_renamed) { if (rename_documents_only) { continue; } // Already-renamed documents skip content analysis and use filename/path categorization. other_entries.push_back(entry); } else { document_entries.push_back(entry); } } else if (allow_other_files) { other_entries.push_back(entry); } continue; } if (allow_other_files) { other_entries.push_back(entry); } } } void sync_disclosure_button(QToolButton* button, bool expanded) { if (!button) { return; } Q_UNUSED(expanded); button->update(); } } // namespace MainApp::MainApp(Settings& settings, bool development_mode, QWidget* parent) : QMainWindow(parent), settings(settings), db_manager(settings.get_config_dir()), core_logger(Logger::get_logger("core_logger")), ui_logger(Logger::get_logger("ui_logger")), whitelist_store(settings.get_config_dir()), categorization_service(settings, db_manager, core_logger), consistency_pass_service(db_manager, core_logger), results_coordinator(dirscanner), undo_manager_(settings.get_config_dir() + "/undo"), development_mode_(development_mode), development_prompt_logging_enabled_(development_mode ? settings.get_development_prompt_logging() : false) { TranslationManager::instance().initialize_for_app(qApp, settings.get_language()); initialize_whitelists(); using_local_llm = !is_remote_choice(settings.get_llm_choice()); MainAppUiBuilder ui_builder; ui_builder.build(*this); ui_translator_ = std::make_unique(ui_builder.build_translator_dependencies(*this)); retranslate_ui(); setup_file_explorer(); connect_signals(); connect_edit_actions(); #if !defined(AI_FILE_SORTER_TEST_BUILD) start_updater(); #endif load_settings(); set_app_icon(); } MainApp::~MainApp() = default; void MainApp::run() { show(); #if !defined(AI_FILE_SORTER_TEST_BUILD) maybe_show_suitability_benchmark(); #endif } void MainApp::shutdown() { stop_running_analysis(); save_settings(); } void MainApp::setup_file_explorer() { create_file_explorer_dock(); setup_file_system_model(); setup_file_explorer_view(); connect_file_explorer_signals(); apply_file_explorer_preferences(); } void MainApp::create_file_explorer_dock() { file_explorer_dock = new QDockWidget(tr("File Explorer"), this); file_explorer_dock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea); addDockWidget(Qt::LeftDockWidgetArea, file_explorer_dock); } void MainApp::setup_file_system_model() { if (!file_explorer_dock) { return; } file_system_model = new QFileSystemModel(file_explorer_dock); file_system_model->setRootPath(QDir::rootPath()); file_system_model->setFilter(QDir::AllEntries | QDir::NoDotAndDotDot | QDir::Drives | QDir::AllDirs); } void MainApp::setup_file_explorer_view() { if (!file_explorer_dock || !file_system_model) { return; } file_explorer_view = new QTreeView(file_explorer_dock); file_explorer_view->setModel(file_system_model); const QString root_path = file_system_model->rootPath(); file_explorer_view->setRootIndex(file_system_model->index(root_path)); const QModelIndex home_index = file_system_model->index(QDir::homePath()); if (home_index.isValid()) { file_explorer_view->setCurrentIndex(home_index); file_explorer_view->scrollTo(home_index); } file_explorer_view->setHeaderHidden(false); file_explorer_view->setEditTriggers(QAbstractItemView::NoEditTriggers); file_explorer_view->header()->setSectionResizeMode(QHeaderView::ResizeToContents); file_explorer_view->setColumnHidden(1, true); file_explorer_view->setColumnHidden(2, true); file_explorer_view->setColumnHidden(3, true); file_explorer_view->setExpandsOnDoubleClick(true); file_explorer_dock->setWidget(file_explorer_view); } void MainApp::connect_file_explorer_signals() { if (!file_explorer_view || !file_explorer_view->selectionModel()) { return; } connect(file_explorer_view->selectionModel(), &QItemSelectionModel::currentChanged, this, [this](const QModelIndex& current, const QModelIndex&) { if (!file_system_model || suppress_explorer_sync_) { return; } if (!current.isValid() || !file_system_model->isDir(current)) { return; } const QString path = file_system_model->filePath(current); if (path_entry && path_entry->text() == path) { update_folder_contents(path); } else { on_directory_selected(path, true); } }); if (file_explorer_dock) { connect(file_explorer_dock, &QDockWidget::visibilityChanged, this, [this](bool) { update_results_view_mode(); }); } } void MainApp::apply_file_explorer_preferences() { if (!file_explorer_dock) { return; } const bool show_explorer = settings.get_show_file_explorer(); if (file_explorer_menu_action) { file_explorer_menu_action->setChecked(show_explorer); } if (consistency_pass_action) { consistency_pass_action->setChecked(settings.get_consistency_pass_enabled()); } file_explorer_dock->setVisible(show_explorer); update_results_view_mode(); } void MainApp::connect_signals() { connect(analyze_button, &QPushButton::clicked, this, &MainApp::on_analyze_clicked); connect(browse_button, &QPushButton::clicked, this, [this]() { const QString directory = QFileDialog::getExistingDirectory(this, tr("Select Directory"), path_entry->text()); if (!directory.isEmpty()) { on_directory_selected(directory); } }); connect(path_entry, &QLineEdit::returnPressed, this, [this]() { const QString folder = path_entry->text(); if (QDir(folder).exists()) { on_directory_selected(folder); } else { show_error_dialog(ERR_INVALID_PATH); } }); connect_folder_contents_signals(); connect_checkbox_signals(); connect_whitelist_signals(); } void MainApp::connect_folder_contents_signals() { if (!folder_contents_view || !folder_contents_model || !folder_contents_view->selectionModel()) { return; } folder_contents_view->setExpandsOnDoubleClick(true); connect(folder_contents_view->selectionModel(), &QItemSelectionModel::currentChanged, this, [this](const QModelIndex& current, const QModelIndex&) { if (suppress_folder_view_sync_) { return; } if (!folder_contents_model || !current.isValid()) { return; } if (!folder_contents_model->isDir(current)) { return; } on_directory_selected(folder_contents_model->filePath(current), true); }); connect(folder_contents_model, &QFileSystemModel::directoryLoaded, this, [this](const QString& path) { if (!folder_contents_view || !folder_contents_model) { return; } if (folder_contents_model->rootPath() == path) { folder_contents_view->resizeColumnToContents(0); } }); } void MainApp::connect_checkbox_signals() { connect(use_subcategories_checkbox, &QCheckBox::toggled, this, [this](bool checked) { settings.set_use_subcategories(checked); if (categorization_dialog) { categorization_dialog->set_show_subcategory_column(checked); } }); if (categorization_style_refined_radio) { connect(categorization_style_refined_radio, &QRadioButton::toggled, this, [this](bool checked) { if (checked) { set_categorization_style(false); settings.set_use_consistency_hints(false); } else if (categorization_style_consistent_radio && !categorization_style_consistent_radio->isChecked()) { set_categorization_style(true); settings.set_use_consistency_hints(true); } }); } if (categorization_style_consistent_radio) { connect(categorization_style_consistent_radio, &QRadioButton::toggled, this, [this](bool checked) { if (checked) { set_categorization_style(true); settings.set_use_consistency_hints(true); } else if (categorization_style_refined_radio && !categorization_style_refined_radio->isChecked()) { set_categorization_style(false); settings.set_use_consistency_hints(false); } }); } connect(categorize_files_checkbox, &QCheckBox::toggled, this, [this](bool checked) { ensure_one_checkbox_active(categorize_files_checkbox); update_file_scan_option(FileScanOptions::Files, checked); settings.set_categorize_files(checked); }); connect(categorize_directories_checkbox, &QCheckBox::toggled, this, [this](bool checked) { ensure_one_checkbox_active(categorize_directories_checkbox); update_file_scan_option(FileScanOptions::Directories, checked); settings.set_categorize_directories(checked); }); if (include_subdirectories_checkbox) { connect(include_subdirectories_checkbox, &QCheckBox::toggled, this, [this](bool checked) { settings.set_include_subdirectories(checked); if (checked && categorize_directories_checkbox && categorize_directories_checkbox->isChecked()) { QSignalBlocker blocker(categorize_directories_checkbox); categorize_directories_checkbox->setChecked(false); update_file_scan_option(FileScanOptions::Directories, false); settings.set_categorize_directories(false); } update_image_only_controls(); }); } if (analyze_images_checkbox) { connect(analyze_images_checkbox, &QCheckBox::toggled, this, [this](bool checked) { handle_image_analysis_toggle(checked); }); } if (process_images_only_checkbox) { connect(process_images_only_checkbox, &QCheckBox::toggled, this, [this](bool checked) { settings.set_process_images_only(checked); update_image_only_controls(); }); } if (add_image_date_to_category_checkbox) { connect(add_image_date_to_category_checkbox, &QCheckBox::toggled, this, [this](bool checked) { settings.set_add_image_date_to_category(checked); }); } if (add_image_date_place_to_filename_checkbox) { connect(add_image_date_place_to_filename_checkbox, &QCheckBox::toggled, this, [this](bool checked) { settings.set_add_image_date_place_to_filename(checked); }); } if (add_audio_video_metadata_to_filename_checkbox) { connect(add_audio_video_metadata_to_filename_checkbox, &QCheckBox::toggled, this, [this](bool checked) { settings.set_add_audio_video_metadata_to_filename(checked); }); } if (offer_rename_images_checkbox) { connect(offer_rename_images_checkbox, &QCheckBox::toggled, this, [this](bool checked) { if (!checked && rename_images_only_checkbox && rename_images_only_checkbox->isChecked()) { QSignalBlocker blocker(rename_images_only_checkbox); rename_images_only_checkbox->setChecked(false); } settings.set_offer_rename_images(checked); if (add_image_date_place_to_filename_checkbox) { settings.set_add_image_date_place_to_filename( add_image_date_place_to_filename_checkbox->isChecked()); } if (rename_images_only_checkbox) { settings.set_rename_images_only(rename_images_only_checkbox->isChecked()); } update_image_analysis_controls(); }); } if (rename_images_only_checkbox) { connect(rename_images_only_checkbox, &QCheckBox::toggled, this, [this](bool checked) { if (checked && offer_rename_images_checkbox && !offer_rename_images_checkbox->isChecked()) { QSignalBlocker blocker(offer_rename_images_checkbox); offer_rename_images_checkbox->setChecked(true); } settings.set_rename_images_only(checked); if (offer_rename_images_checkbox) { settings.set_offer_rename_images(offer_rename_images_checkbox->isChecked()); } update_image_analysis_controls(); }); } if (image_options_toggle_button) { connect(image_options_toggle_button, &QToolButton::toggled, this, [this](bool) { settings.set_image_options_expanded(image_options_toggle_button->isChecked()); update_image_analysis_controls(); }); } if (analyze_documents_checkbox) { connect(analyze_documents_checkbox, &QCheckBox::toggled, this, [this](bool checked) { settings.set_analyze_documents_by_content(checked); update_document_analysis_controls(); }); } if (process_documents_only_checkbox) { connect(process_documents_only_checkbox, &QCheckBox::toggled, this, [this](bool checked) { settings.set_process_documents_only(checked); update_document_analysis_controls(); }); } if (offer_rename_documents_checkbox) { connect(offer_rename_documents_checkbox, &QCheckBox::toggled, this, [this](bool checked) { if (!checked && rename_documents_only_checkbox && rename_documents_only_checkbox->isChecked()) { QSignalBlocker blocker(rename_documents_only_checkbox); rename_documents_only_checkbox->setChecked(false); } settings.set_offer_rename_documents(checked); if (rename_documents_only_checkbox) { settings.set_rename_documents_only(rename_documents_only_checkbox->isChecked()); } update_document_analysis_controls(); }); } if (rename_documents_only_checkbox) { connect(rename_documents_only_checkbox, &QCheckBox::toggled, this, [this](bool checked) { if (checked && offer_rename_documents_checkbox && !offer_rename_documents_checkbox->isChecked()) { QSignalBlocker blocker(offer_rename_documents_checkbox); offer_rename_documents_checkbox->setChecked(true); } settings.set_rename_documents_only(checked); if (offer_rename_documents_checkbox) { settings.set_offer_rename_documents(offer_rename_documents_checkbox->isChecked()); } update_document_analysis_controls(); }); } if (add_document_date_to_category_checkbox) { connect(add_document_date_to_category_checkbox, &QCheckBox::toggled, this, [this](bool checked) { settings.set_add_document_date_to_category(checked); }); } if (document_options_toggle_button) { connect(document_options_toggle_button, &QToolButton::toggled, this, [this](bool) { settings.set_document_options_expanded(document_options_toggle_button->isChecked()); update_document_analysis_controls(); }); } } void MainApp::connect_whitelist_signals() { connect(use_whitelist_checkbox, &QCheckBox::toggled, this, [this](bool checked) { if (whitelist_selector) { whitelist_selector->setEnabled(checked); } settings.set_use_whitelist(checked); apply_whitelist_to_selector(); }); connect(whitelist_selector, &QComboBox::currentTextChanged, this, [this](const QString& name) { settings.set_active_whitelist(name.toStdString()); if (auto entry = whitelist_store.get(name.toStdString())) { settings.set_allowed_categories(entry->categories); settings.set_allowed_subcategories(entry->subcategories); } }); } void MainApp::connect_edit_actions() { path_entry->setContextMenuPolicy(Qt::DefaultContextMenu); } void MainApp::start_updater() { if (!UpdaterBuildConfig::update_checks_enabled()) { return; } auto* updater = new Updater(settings); updater->begin(); } void MainApp::set_app_icon() { const QString icon_path = QStringLiteral(":/net/quicknode/AIFileSorter/images/app_icon_128.png"); QIcon icon(icon_path); if (icon.isNull()) { icon = QIcon(QStringLiteral(":/net/quicknode/AIFileSorter/images/logo.png")); } if (!icon.isNull()) { QApplication::setWindowIcon(icon); setWindowIcon(icon); } } void MainApp::load_settings() { if (!settings.load()) { core_logger->info("Failed to load settings, using defaults."); } if (development_mode_) { development_prompt_logging_enabled_ = settings.get_development_prompt_logging(); } else { development_prompt_logging_enabled_ = false; } apply_development_logging(); TranslationManager::instance().set_language(settings.get_language()); sync_settings_to_ui(); retranslate_ui(); } void MainApp::save_settings() { sync_ui_to_settings(); settings.save(); } void MainApp::sync_settings_to_ui() { restore_tree_settings(); restore_sort_folder_state(); restore_file_scan_options(); restore_file_explorer_visibility(); restore_development_preferences(); if (ui_translator_) { ui_translator_->update_language_checks(); } } void MainApp::restore_tree_settings() { use_subcategories_checkbox->setChecked(settings.get_use_subcategories()); set_categorization_style(settings.get_use_consistency_hints()); if (use_whitelist_checkbox) { use_whitelist_checkbox->setChecked(settings.get_use_whitelist()); } if (whitelist_selector) { apply_whitelist_to_selector(); } categorize_files_checkbox->setChecked(settings.get_categorize_files()); categorize_directories_checkbox->setChecked(settings.get_categorize_directories()); if (include_subdirectories_checkbox) { include_subdirectories_checkbox->setChecked(settings.get_include_subdirectories()); } if (analyze_images_checkbox) { QSignalBlocker blocker(analyze_images_checkbox); analyze_images_checkbox->setChecked(settings.get_analyze_images_by_content()); } if (process_images_only_checkbox) { QSignalBlocker blocker(process_images_only_checkbox); process_images_only_checkbox->setChecked(settings.get_process_images_only()); } if (add_image_date_place_to_filename_checkbox) { QSignalBlocker blocker(add_image_date_place_to_filename_checkbox); add_image_date_place_to_filename_checkbox->setChecked( settings.get_add_image_date_place_to_filename()); } if (add_audio_video_metadata_to_filename_checkbox) { QSignalBlocker blocker(add_audio_video_metadata_to_filename_checkbox); add_audio_video_metadata_to_filename_checkbox->setChecked( settings.get_add_audio_video_metadata_to_filename()); } if (add_image_date_to_category_checkbox) { QSignalBlocker blocker(add_image_date_to_category_checkbox); add_image_date_to_category_checkbox->setChecked( settings.get_add_image_date_to_category()); } if (offer_rename_images_checkbox) { QSignalBlocker blocker(offer_rename_images_checkbox); offer_rename_images_checkbox->setChecked(settings.get_offer_rename_images()); } if (rename_images_only_checkbox) { QSignalBlocker blocker(rename_images_only_checkbox); rename_images_only_checkbox->setChecked(settings.get_rename_images_only()); } if (image_options_toggle_button) { const bool expand_images = settings.get_image_options_expanded(); QSignalBlocker blocker(image_options_toggle_button); image_options_toggle_button->setChecked(expand_images); } if (analyze_documents_checkbox) { QSignalBlocker blocker(analyze_documents_checkbox); analyze_documents_checkbox->setChecked(settings.get_analyze_documents_by_content()); } if (process_documents_only_checkbox) { QSignalBlocker blocker(process_documents_only_checkbox); process_documents_only_checkbox->setChecked(settings.get_process_documents_only()); } if (offer_rename_documents_checkbox) { QSignalBlocker blocker(offer_rename_documents_checkbox); offer_rename_documents_checkbox->setChecked(settings.get_offer_rename_documents()); } if (rename_documents_only_checkbox) { QSignalBlocker blocker(rename_documents_only_checkbox); rename_documents_only_checkbox->setChecked(settings.get_rename_documents_only()); } if (add_document_date_to_category_checkbox) { QSignalBlocker blocker(add_document_date_to_category_checkbox); add_document_date_to_category_checkbox->setChecked(settings.get_add_document_date_to_category()); } if (document_options_toggle_button) { const bool expand_documents = settings.get_document_options_expanded(); QSignalBlocker blocker(document_options_toggle_button); document_options_toggle_button->setChecked(expand_documents); } update_image_analysis_controls(); update_document_analysis_controls(); } void MainApp::restore_sort_folder_state() { const QString stored_folder = QString::fromStdString(settings.get_sort_folder()); QString effective_folder = stored_folder; if (effective_folder.isEmpty() || !QDir(effective_folder).exists()) { effective_folder = QDir::homePath(); } path_entry->setText(effective_folder); if (!effective_folder.isEmpty() && QDir(effective_folder).exists()) { statusBar()->showMessage(tr("Loaded folder %1").arg(effective_folder), 3000); status_is_ready_ = false; update_folder_contents(effective_folder); focus_file_explorer_on_path(effective_folder); } else if (!stored_folder.isEmpty()) { core_logger->warn("Sort folder path is invalid: {}", stored_folder.toStdString()); } } void MainApp::restore_file_scan_options() { file_scan_options = FileScanOptions::None; if (settings.get_categorize_files()) { file_scan_options = file_scan_options | FileScanOptions::Files; } if (settings.get_categorize_directories()) { file_scan_options = file_scan_options | FileScanOptions::Directories; } } void MainApp::restore_file_explorer_visibility() { const bool show_explorer = settings.get_show_file_explorer(); if (file_explorer_dock) { file_explorer_dock->setVisible(show_explorer); } if (file_explorer_menu_action) { file_explorer_menu_action->setChecked(show_explorer); } update_results_view_mode(); } void MainApp::restore_development_preferences() { if (!development_mode_ || !development_prompt_logging_action) { return; } QSignalBlocker blocker(development_prompt_logging_action); development_prompt_logging_action->setChecked(development_prompt_logging_enabled_); } void MainApp::sync_ui_to_settings() { settings.set_use_subcategories(use_subcategories_checkbox->isChecked()); if (categorization_style_consistent_radio) { settings.set_use_consistency_hints(categorization_style_consistent_radio->isChecked()); } if (use_whitelist_checkbox) { settings.set_use_whitelist(use_whitelist_checkbox->isChecked()); } if (whitelist_selector) { settings.set_active_whitelist(whitelist_selector->currentText().toStdString()); } settings.set_categorize_files(categorize_files_checkbox->isChecked()); settings.set_categorize_directories(categorize_directories_checkbox->isChecked()); if (include_subdirectories_checkbox) { settings.set_include_subdirectories(include_subdirectories_checkbox->isChecked()); } if (analyze_images_checkbox) { settings.set_analyze_images_by_content(analyze_images_checkbox->isChecked()); } if (process_images_only_checkbox) { settings.set_process_images_only(process_images_only_checkbox->isChecked()); } if (add_image_date_place_to_filename_checkbox) { settings.set_add_image_date_place_to_filename( add_image_date_place_to_filename_checkbox->isChecked()); } if (add_audio_video_metadata_to_filename_checkbox) { settings.set_add_audio_video_metadata_to_filename( add_audio_video_metadata_to_filename_checkbox->isChecked()); } if (add_image_date_to_category_checkbox) { settings.set_add_image_date_to_category( add_image_date_to_category_checkbox->isChecked()); } if (offer_rename_images_checkbox) { settings.set_offer_rename_images(offer_rename_images_checkbox->isChecked()); } if (rename_images_only_checkbox) { settings.set_rename_images_only(rename_images_only_checkbox->isChecked()); } if (analyze_documents_checkbox) { settings.set_analyze_documents_by_content(analyze_documents_checkbox->isChecked()); } if (process_documents_only_checkbox) { settings.set_process_documents_only(process_documents_only_checkbox->isChecked()); } if (offer_rename_documents_checkbox) { settings.set_offer_rename_documents(offer_rename_documents_checkbox->isChecked()); } if (rename_documents_only_checkbox) { settings.set_rename_documents_only(rename_documents_only_checkbox->isChecked()); } if (add_document_date_to_category_checkbox) { settings.set_add_document_date_to_category(add_document_date_to_category_checkbox->isChecked()); } const QByteArray folder_bytes = path_entry->text().toUtf8(); settings.set_sort_folder(std::string(folder_bytes.constData(), static_cast(folder_bytes.size()))); if (file_explorer_menu_action) { settings.set_show_file_explorer(file_explorer_menu_action->isChecked()); } if (consistency_pass_action) { settings.set_consistency_pass_enabled(consistency_pass_action->isChecked()); } if (development_mode_ && development_prompt_logging_action) { const bool checked = development_prompt_logging_action->isChecked(); development_prompt_logging_enabled_ = checked; settings.set_development_prompt_logging(checked); apply_development_logging(); } if (language_group) { if (QAction* checked = language_group->checkedAction()) { settings.set_language(static_cast(checked->data().toInt())); } } } void MainApp::retranslate_ui() { if (!ui_translator_) { return; } UiTranslator::State state{ .analysis_in_progress = analysis_in_progress_, .stop_analysis_requested = stop_analysis.load(), .status_is_ready = status_is_ready_ }; ui_translator_->retranslate_all(state); } #if defined(AI_FILE_SORTER_TEST_BUILD) QString MainAppTestAccess::analyze_button_text(const MainApp& app) { return app.analyze_button ? app.analyze_button->text() : QString(); } QString MainAppTestAccess::path_label_text(const MainApp& app) { return app.path_label ? app.path_label->text() : QString(); } QCheckBox* MainAppTestAccess::categorize_files_checkbox(MainApp& app) { return app.categorize_files_checkbox; } QCheckBox* MainAppTestAccess::analyze_images_checkbox(MainApp& app) { return app.analyze_images_checkbox; } QCheckBox* MainAppTestAccess::process_images_only_checkbox(MainApp& app) { return app.process_images_only_checkbox; } QCheckBox* MainAppTestAccess::add_image_date_to_category_checkbox(MainApp& app) { return app.add_image_date_to_category_checkbox; } QCheckBox* MainAppTestAccess::add_image_date_place_to_filename_checkbox(MainApp& app) { return app.add_image_date_place_to_filename_checkbox; } QCheckBox* MainAppTestAccess::add_audio_video_metadata_to_filename_checkbox(MainApp& app) { return app.add_audio_video_metadata_to_filename_checkbox; } QCheckBox* MainAppTestAccess::offer_rename_images_checkbox(MainApp& app) { return app.offer_rename_images_checkbox; } QCheckBox* MainAppTestAccess::rename_images_only_checkbox(MainApp& app) { return app.rename_images_only_checkbox; } QCheckBox* MainAppTestAccess::analyze_documents_checkbox(MainApp& app) { return app.analyze_documents_checkbox; } QCheckBox* MainAppTestAccess::process_documents_only_checkbox(MainApp& app) { return app.process_documents_only_checkbox; } QCheckBox* MainAppTestAccess::rename_documents_only_checkbox(MainApp& app) { return app.rename_documents_only_checkbox; } QToolButton* MainAppTestAccess::image_options_toggle_button(MainApp& app) { return app.image_options_toggle_button; } QToolButton* MainAppTestAccess::document_options_toggle_button(MainApp& app) { return app.document_options_toggle_button; } void MainAppTestAccess::split_entries_for_analysis(const std::vector& files, bool analyze_images, bool analyze_documents, bool process_images_only, bool process_documents_only, bool rename_images_only, bool rename_documents_only, bool categorize_files, bool use_full_path_keys, const std::unordered_set& renamed_files, std::vector& image_entries, std::vector& document_entries, std::vector& other_entries) { ::split_entries_for_analysis(files, analyze_images, analyze_documents, process_images_only, process_documents_only, rename_images_only, rename_documents_only, categorize_files, use_full_path_keys, renamed_files, image_entries, document_entries, other_entries); } void MainAppTestAccess::set_visual_llm_available_probe(MainApp& app, std::function probe) { app.visual_llm_available_probe_ = std::move(probe); } void MainAppTestAccess::set_llm_selection_runner(MainApp& app, std::function runner) { app.llm_selection_runner_override_ = std::move(runner); } void MainAppTestAccess::set_image_analysis_prompt_override(MainApp& app, std::function prompt) { app.image_analysis_prompt_override_ = std::move(prompt); } bool MainAppTestAccess::should_offer_visual_cpu_fallback(const std::string& reason) { return ::should_offer_visual_cpu_fallback(reason); } std::string MainAppTestAccess::resolve_document_prompt_name(const std::string& original_name, const std::string& suggested_name) { return ::resolve_document_prompt_name(original_name, suggested_name); } std::string MainAppTestAccess::build_document_prompt_path(const std::string& full_path, const std::string& prompt_name, const std::string& summary) { return ::build_document_prompt_path(full_path, prompt_name, summary); } void MainAppTestAccess::trigger_retranslate(MainApp& app) { app.retranslate_ui(); } void MainAppTestAccess::add_categorized_files(MainApp& app, int count) { app.record_categorized_metrics(count); } void MainAppTestAccess::simulate_support_prompt(Settings& settings, bool& prompt_state, int count, std::function callback) { const auto config_dir = Utils::utf8_to_path(settings.get_config_dir()); auto convert = [config_dir, cb = std::move(callback)](int total) -> MainApp::SupportPromptResult { if (!cb) { return MainApp::SupportPromptResult::NotSure; } switch (cb(total)) { case SimulatedSupportResult::Support: if (SupportCodeManager(config_dir).force_disable_prompt_for_testing()) { return MainApp::SupportPromptResult::Support; } return MainApp::SupportPromptResult::NotSure; case SimulatedSupportResult::NotSure: default: return MainApp::SupportPromptResult::NotSure; } }; record_categorized_metrics_impl(settings, prompt_state, count, convert); } #endif // AI_FILE_SORTER_TEST_BUILD void MainApp::on_language_selected(Language language) { settings.set_language(language); TranslationManager::instance().set_language(language); if (ui_translator_) { ui_translator_->update_language_checks(); } retranslate_ui(); if (categorization_dialog) { QCoreApplication::postEvent( categorization_dialog.get(), new QEvent(QEvent::LanguageChange)); } if (progress_dialog) { QCoreApplication::postEvent( progress_dialog.get(), new QEvent(QEvent::LanguageChange)); } } void MainApp::on_category_language_selected(CategoryLanguage language) { settings.set_category_language(language); if (ui_translator_) { ui_translator_->update_language_checks(); } } void MainApp::on_analyze_clicked() { if (analyze_thread.joinable()) { stop_running_analysis(); update_analyze_button_state(false); statusBar()->showMessage(tr("Analysis cancelled"), 4000); status_is_ready_ = false; return; } const std::string folder_path = get_folder_path(); if (!Utils::is_valid_directory(folder_path.c_str())) { show_error_dialog(ERR_INVALID_PATH); core_logger->warn("User supplied invalid directory '{}'", folder_path); return; } if (!using_local_llm) { if (!Utils::is_network_available()) { show_error_dialog(ERR_NO_INTERNET_CONNECTION); core_logger->warn("Network unavailable when attempting to analyze '{}'", folder_path); return; } std::string credential_error; if (!categorization_service.ensure_remote_credentials(&credential_error)) { show_error_dialog(credential_error.empty() ? "Remote model credentials are missing or invalid. Please configure your API key and try again." : credential_error); return; } } if (!ensure_folder_categorization_style(folder_path)) { return; } stop_analysis = false; text_cpu_fallback_choice_.reset(); update_analyze_button_state(true); const bool show_subcategory = use_subcategories_checkbox->isChecked(); progress_dialog = std::make_unique(this, this, show_subcategory); progress_dialog->show(); analyze_thread = std::thread([this]() { try { perform_analysis(); } catch (const std::exception& ex) { core_logger->error("Exception during analysis: {}", ex.what()); run_on_ui([this, message = std::string("Analysis error: ") + ex.what()]() { handle_analysis_failure(message); }); } }); } void MainApp::on_directory_selected(const QString& path, bool user_initiated) { path_entry->setText(path); statusBar()->showMessage(tr("Folder selected: %1").arg(path), 3000); status_is_ready_ = false; if (!user_initiated) { focus_file_explorer_on_path(path); } update_folder_contents(path); } void MainApp::set_categorization_style(bool use_consistency) { if (!categorization_style_refined_radio || !categorization_style_consistent_radio) { return; } QSignalBlocker blocker_refined(categorization_style_refined_radio); QSignalBlocker blocker_consistent(categorization_style_consistent_radio); categorization_style_refined_radio->setChecked(!use_consistency); categorization_style_consistent_radio->setChecked(use_consistency); } void MainApp::apply_whitelist_to_selector() { if (!whitelist_selector) { return; } auto names = whitelist_store.list_names(); if (names.empty()) { whitelist_store.ensure_default_from_legacy(settings.get_allowed_categories(), settings.get_allowed_subcategories()); whitelist_store.save(); names = whitelist_store.list_names(); } const QString current_active = QString::fromStdString(settings.get_active_whitelist()); whitelist_selector->blockSignals(true); whitelist_selector->clear(); for (const auto& name : names) { whitelist_selector->addItem(QString::fromStdString(name)); } whitelist_selector->setEnabled(use_whitelist_checkbox && use_whitelist_checkbox->isChecked()); int idx = whitelist_selector->findText(current_active); if (idx < 0 && !names.empty()) { const QString def = QString::fromStdString(whitelist_store.default_name()); idx = whitelist_selector->findText(def); if (idx < 0) { idx = 0; } } if (idx >= 0) { whitelist_selector->setCurrentIndex(idx); const QString chosen = whitelist_selector->itemText(idx); settings.set_active_whitelist(chosen.toStdString()); if (auto entry = whitelist_store.get(chosen.toStdString())) { settings.set_allowed_categories(entry->categories); settings.set_allowed_subcategories(entry->subcategories); } } whitelist_selector->blockSignals(false); } void MainApp::show_whitelist_manager() { if (!whitelist_dialog) { whitelist_dialog = std::make_unique(whitelist_store, this); whitelist_dialog->set_on_lists_changed([this]() { whitelist_store.load(); whitelist_store.save(); apply_whitelist_to_selector(); }); } whitelist_dialog->show(); whitelist_dialog->raise(); whitelist_dialog->activateWindow(); } void MainApp::initialize_whitelists() { whitelist_store.initialize_from_settings(settings); } bool MainApp::ensure_folder_categorization_style(const std::string& folder_path) { const bool desired = settings.get_use_consistency_hints(); const bool recursive = settings.get_include_subdirectories(); if (!db_manager.has_categorization_style_conflict(folder_path, desired, recursive)) { return true; } const auto style_label = [](bool value) -> QString { return value ? tr("More consistent") : tr("More refined"); }; QMessageBox box(this); box.setIcon(QMessageBox::Question); box.setWindowTitle(tr("Recategorize folder?")); box.setText(tr("This folder was categorized using the %1 mode. Do you want to recategorize it now using the %2 mode?") .arg(style_label(!desired), style_label(desired))); QPushButton* recategorize_button = box.addButton(tr("Recategorize"), QMessageBox::AcceptRole); box.addButton(tr("Keep existing"), QMessageBox::RejectRole); QPushButton* cancel_button = box.addButton(QMessageBox::Cancel); box.exec(); if (box.clickedButton() == cancel_button) { return false; } if (box.clickedButton() == recategorize_button) { if (!db_manager.clear_directory_categorizations(folder_path, recursive)) { show_error_dialog(tr("Failed to reset cached categorization for this folder.").toStdString()); return false; } } return true; } void MainApp::ensure_one_checkbox_active(QCheckBox* changed_checkbox) { if (!categorize_files_checkbox || !categorize_directories_checkbox) { return; } const bool include_subdirs_active = include_subdirectories_checkbox && include_subdirectories_checkbox->isChecked(); if (include_subdirs_active && !categorize_files_checkbox->isChecked() && !categorize_directories_checkbox->isChecked()) { return; } if (!categorize_files_checkbox->isChecked() && !categorize_directories_checkbox->isChecked()) { QCheckBox* other = (changed_checkbox == categorize_files_checkbox) ? categorize_directories_checkbox : categorize_files_checkbox; other->setChecked(true); } } void MainApp::update_file_scan_option(FileScanOptions option, bool enabled) { if (enabled) { file_scan_options = file_scan_options | option; } else { file_scan_options = file_scan_options & ~option; } } FileScanOptions MainApp::effective_scan_options() const { const bool analyze_images = settings.get_analyze_images_by_content(); const bool analyze_documents = settings.get_analyze_documents_by_content(); const bool images_only = analyze_images && settings.get_process_images_only(); const bool documents_only = analyze_documents && settings.get_process_documents_only(); if (images_only || documents_only) { return FileScanOptions::Files; } FileScanOptions options = file_scan_options; if (analyze_images || analyze_documents) { options = options | FileScanOptions::Files; } if (settings.get_include_subdirectories() && has_flag(options, FileScanOptions::Files)) { options = options | FileScanOptions::Recursive; } return options; } bool MainApp::visual_llm_files_available() const { #ifdef AI_FILE_SORTER_TEST_BUILD if (visual_llm_available_probe_) { return visual_llm_available_probe_(); } #endif const char* model_url = std::getenv("LLAVA_MODEL_URL"); const char* mmproj_url = std::getenv("LLAVA_MMPROJ_URL"); if (!model_url || *model_url == '\0' || !mmproj_url || *mmproj_url == '\0') { return false; } const auto model_path = std::filesystem::path( Utils::make_default_path_to_file_from_download_url(model_url)); const auto mmproj_path = std::filesystem::path( Utils::make_default_path_to_file_from_download_url(mmproj_url)); if (!std::filesystem::exists(model_path)) { return false; } if (std::filesystem::exists(mmproj_path)) { return true; } const auto llm_dir = std::filesystem::path(Utils::get_default_llm_destination()); static const char* kAltMmprojNames[] = { "mmproj-model-f16.gguf", "llava-v1.6-mistral-7b-mmproj-f16.gguf" }; for (const char* alt_name : kAltMmprojNames) { if (std::filesystem::exists(llm_dir / alt_name)) { return true; } } return false; } void MainApp::update_image_analysis_controls() { if (!analyze_images_checkbox || !process_images_only_checkbox || !add_image_date_to_category_checkbox || !add_image_date_place_to_filename_checkbox || !offer_rename_images_checkbox || !rename_images_only_checkbox) { return; } const bool analysis_enabled = analyze_images_checkbox->isChecked(); const bool rename_only = analysis_enabled && rename_images_only_checkbox->isChecked(); process_images_only_checkbox->setEnabled(analysis_enabled); offer_rename_images_checkbox->setEnabled(analysis_enabled); rename_images_only_checkbox->setEnabled(analysis_enabled); add_image_date_to_category_checkbox->setEnabled(analysis_enabled && !rename_only); add_image_date_place_to_filename_checkbox->setEnabled( analysis_enabled && offer_rename_images_checkbox->isChecked()); if (image_options_toggle_button) { image_options_toggle_button->setEnabled(analysis_enabled); const bool expanded = image_options_toggle_button->isChecked(); sync_disclosure_button(image_options_toggle_button, expanded); if (image_options_container) { image_options_container->setVisible(analysis_enabled && expanded); } } else if (image_options_container) { image_options_container->setVisible(analysis_enabled); } if (analysis_enabled && rename_images_only_checkbox->isChecked() && !offer_rename_images_checkbox->isChecked()) { QSignalBlocker blocker(offer_rename_images_checkbox); offer_rename_images_checkbox->setChecked(true); } update_image_only_controls(); } void MainApp::update_image_only_controls() { if (!process_images_only_checkbox && !process_documents_only_checkbox) { return; } const bool analyze_images = analyze_images_checkbox && analyze_images_checkbox->isChecked(); const bool analyze_documents = analyze_documents_checkbox && analyze_documents_checkbox->isChecked(); const bool images_only_active = process_images_only_checkbox && analyze_images && process_images_only_checkbox->isChecked(); const bool documents_only_active = process_documents_only_checkbox && analyze_documents && process_documents_only_checkbox->isChecked(); const bool rename_images_active = rename_images_only_checkbox && analyze_images && rename_images_only_checkbox->isChecked(); const bool rename_documents_active = rename_documents_only_checkbox && analyze_documents && rename_documents_only_checkbox->isChecked(); const bool restrict_types = images_only_active || documents_only_active; const bool allow_images = !restrict_types || images_only_active; const bool allow_documents = !restrict_types || documents_only_active; const bool allow_other_files = !restrict_types; const bool images_rename_only = allow_images ? rename_images_active : true; const bool documents_rename_only = allow_documents ? rename_documents_active : true; const bool disable_files_categorization = !allow_other_files && images_rename_only && documents_rename_only; const bool include_subdirs_active = include_subdirectories_checkbox && include_subdirectories_checkbox->isChecked(); const bool disable_directories_categorization = restrict_types || include_subdirs_active; if (use_subcategories_checkbox) { use_subcategories_checkbox->setEnabled(!disable_files_categorization); } if (categorize_files_checkbox) { categorize_files_checkbox->setEnabled(!disable_files_categorization); } if (categorize_directories_checkbox) { categorize_directories_checkbox->setEnabled(!disable_directories_categorization); } if (categorization_style_heading) { categorization_style_heading->setEnabled(!disable_files_categorization); } if (categorization_style_refined_radio) { categorization_style_refined_radio->setEnabled(!disable_files_categorization); } if (categorization_style_consistent_radio) { categorization_style_consistent_radio->setEnabled(!disable_files_categorization); } if (use_whitelist_checkbox) { use_whitelist_checkbox->setEnabled(!disable_files_categorization); } if (whitelist_selector) { const bool whitelist_enabled = !disable_files_categorization && use_whitelist_checkbox && use_whitelist_checkbox->isChecked(); whitelist_selector->setEnabled(whitelist_enabled); } } void MainApp::update_document_analysis_controls() { if (!analyze_documents_checkbox || !process_documents_only_checkbox || !offer_rename_documents_checkbox || !rename_documents_only_checkbox || !add_document_date_to_category_checkbox) { return; } const bool analysis_enabled = analyze_documents_checkbox->isChecked(); process_documents_only_checkbox->setEnabled(analysis_enabled); offer_rename_documents_checkbox->setEnabled(analysis_enabled); rename_documents_only_checkbox->setEnabled(analysis_enabled); const bool rename_only = analysis_enabled && rename_documents_only_checkbox->isChecked(); add_document_date_to_category_checkbox->setEnabled(analysis_enabled && !rename_only); if (analysis_enabled && rename_documents_only_checkbox->isChecked() && !offer_rename_documents_checkbox->isChecked()) { QSignalBlocker blocker(offer_rename_documents_checkbox); offer_rename_documents_checkbox->setChecked(true); } if (document_options_toggle_button) { document_options_toggle_button->setEnabled(analysis_enabled); const bool expanded = document_options_toggle_button->isChecked(); sync_disclosure_button(document_options_toggle_button, expanded); if (document_options_container) { document_options_container->setVisible(analysis_enabled && expanded); } } else if (document_options_container) { document_options_container->setVisible(analysis_enabled); } update_image_only_controls(); } void MainApp::run_llm_selection_dialog_for_visual() { #ifdef AI_FILE_SORTER_TEST_BUILD if (llm_selection_runner_override_) { llm_selection_runner_override_(); return; } #endif show_llm_selection_dialog(); } void MainApp::handle_image_analysis_toggle(bool checked) { if (!analyze_images_checkbox) { return; } if (checked && !visual_llm_files_available()) { bool should_open_dialog = false; #ifdef AI_FILE_SORTER_TEST_BUILD if (image_analysis_prompt_override_) { should_open_dialog = image_analysis_prompt_override_(); } else #endif { QMessageBox box(this); box.setIcon(QMessageBox::Information); box.setWindowTitle(tr("Download required")); box.setText(tr("Image analysis requires visual LLM files. Download them now?")); QPushButton* ok_button = box.addButton(tr("OK"), QMessageBox::AcceptRole); box.addButton(QMessageBox::Cancel); box.setDefaultButton(ok_button); box.exec(); should_open_dialog = (box.clickedButton() == ok_button); } if (!should_open_dialog) { QSignalBlocker blocker(analyze_images_checkbox); analyze_images_checkbox->setChecked(false); settings.set_analyze_images_by_content(false); update_image_analysis_controls(); return; } run_llm_selection_dialog_for_visual(); if (!visual_llm_files_available()) { QSignalBlocker blocker(analyze_images_checkbox); analyze_images_checkbox->setChecked(false); settings.set_analyze_images_by_content(false); update_image_analysis_controls(); return; } } settings.set_analyze_images_by_content(analyze_images_checkbox->isChecked()); update_image_analysis_controls(); } void MainApp::update_analyze_button_state(bool analyzing) { analysis_in_progress_ = analyzing; if (analyzing) { analyze_button->setText(tr("Stop analyzing")); statusBar()->showMessage(tr("Analyzing…")); status_is_ready_ = false; } else { analyze_button->setText(tr("Analyze folder")); statusBar()->showMessage(tr("Ready")); status_is_ready_ = true; } } void MainApp::update_results_view_mode() { if (!results_stack) { return; } const bool explorer_visible = file_explorer_dock && file_explorer_dock->isVisible(); const int target_index = explorer_visible ? folder_view_page_index_ : tree_view_page_index_; if (target_index >= 0 && target_index < results_stack->count()) { results_stack->setCurrentIndex(target_index); } if (explorer_visible && path_entry) { update_folder_contents(path_entry->text()); } } void MainApp::update_folder_contents(const QString& directory) { if (!folder_contents_model || !folder_contents_view || directory.isEmpty()) { return; } QDir dir(directory); if (!dir.exists()) { return; } const bool previous_flag = suppress_folder_view_sync_; suppress_folder_view_sync_ = true; const QModelIndex new_root = folder_contents_model->setRootPath(directory); folder_contents_view->setRootIndex(new_root); folder_contents_view->scrollTo(new_root, QAbstractItemView::PositionAtTop); folder_contents_view->resizeColumnToContents(0); suppress_folder_view_sync_ = previous_flag; } void MainApp::focus_file_explorer_on_path(const QString& path) { if (!file_system_model || !file_explorer_view || path.isEmpty()) { return; } const QModelIndex index = file_system_model->index(path); if (!index.isValid()) { return; } const bool previous_suppress = suppress_explorer_sync_; suppress_explorer_sync_ = true; file_explorer_view->setCurrentIndex(index); file_explorer_view->expand(index); file_explorer_view->scrollTo(index, QAbstractItemView::PositionAtCenter); suppress_explorer_sync_ = previous_suppress; } void MainApp::record_categorized_metrics(int count) { record_categorized_metrics_impl( settings, donation_prompt_active_, count, [this](int total) { return show_support_prompt_dialog(total); }); } void MainApp::undo_last_run() { const auto latest = undo_manager_.latest_plan_path(); if (!latest) { show_error_dialog("No undo plans available."); return; } QMessageBox box(this); box.setWindowTitle(tr("Undo last run")); box.setText(tr("This will attempt to move files back to their original locations based on the last run.\n\nPlan file: %1") .arg(*latest)); box.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); box.setDefaultButton(QMessageBox::Cancel); if (box.exec() != QMessageBox::Ok) { return; } const auto res = undo_manager_.undo_plan(*latest); QString summary = tr("Restored %1 file(s). Skipped %2.").arg(res.restored).arg(res.skipped); if (!res.details.isEmpty()) { summary.append("\n"); summary.append(res.details.join("\n")); } QMessageBox::information(this, tr("Undo complete"), summary); if (ui_logger) { ui_logger->info(summary.toStdString()); } if (res.restored > 0) { QFile::remove(*latest); } } bool MainApp::perform_undo_from_plan(const QString& plan_path) { const auto res = undo_manager_.undo_plan(plan_path); QString summary = tr("Restored %1 file(s). Skipped %2.").arg(res.restored).arg(res.skipped); if (!res.details.isEmpty()) { summary.append("\n"); summary.append(res.details.join("\n")); } QMessageBox::information(this, tr("Undo complete"), summary); return res.restored > 0; } MainApp::SupportPromptResult MainApp::show_support_prompt_dialog(int total_files) { QMessageBox box(this); box.setIcon(QMessageBox::Information); box.setWindowTitle(QObject::tr("Support %1").arg(app_display_name())); const QString headline = tr("Thank you for using AI File Sorter! You have categorized %1 files thus far. I, the author, really hope this app was useful for you.") .arg(total_files); const QString details = tr("AI File Sorter takes hundreds of hours of development, feature work, support replies, and ongoing costs such as servers and remote-model infrastructure. " "If the app saves you time or brings value, please consider supporting it so it can keep improving."); const QString code_note = tr("Already donated? Click \"I have already donated\" to enter your donation code and permanently disable this reminder."); box.setText(headline); box.setInformativeText(details + QStringLiteral("\n\n") + code_note); auto* support_btn = box.addButton(tr("Donate to permanently hide the donation dialog"), QMessageBox::ActionRole); auto* later_btn = box.addButton(tr("I'm not yet sure"), QMessageBox::ActionRole); auto* donated_btn = box.addButton(tr("I have already donated"), QMessageBox::ActionRole); const auto apply_button_style = [](QAbstractButton* button, const QString& background, const QString& hover, const QString& text_color, int font_weight, const QString& border) { if (!button) { return; } button->setStyleSheet(QStringLiteral( "QPushButton {" " background-color: %1;" " color: %2;" " padding: 6px 18px;" " border: %5;" " border-radius: 14px;" " font-weight: %3;" "}" "QPushButton:hover {" " background-color: %4;" "}" "QPushButton:pressed {" " background-color: %4;" " opacity: 0.9;" "}" ).arg(background, text_color, QString::number(font_weight), hover, border)); }; apply_button_style(support_btn, QStringLiteral("#007aff"), QStringLiteral("#005ec7"), QStringLiteral("white"), 800, QStringLiteral("2px solid #005ec7")); const QString neutral_bg = QStringLiteral("#bdc3c7"); const QString neutral_hover = QStringLiteral("#95a5a6"); apply_button_style(later_btn, neutral_bg, neutral_hover, QStringLiteral("#1f1f1f"), 500, QStringLiteral("none")); apply_button_style(donated_btn, neutral_bg, neutral_hover, QStringLiteral("#1f1f1f"), 500, QStringLiteral("none")); if (auto* button_box = box.findChild()) { button_box->setCenterButtons(true); button_box->setLayoutDirection(Qt::LeftToRight); if (auto* layout = qobject_cast(button_box->layout())) { int insert_index = layout->count(); for (int i = 0; i < layout->count(); ++i) { if (auto* item = layout->itemAt(i); item && item->widget() && qobject_cast(item->widget())) { insert_index = i; break; } } layout->removeWidget(support_btn); layout->removeWidget(later_btn); layout->removeWidget(donated_btn); layout->insertWidget(insert_index++, support_btn); layout->insertWidget(insert_index++, donated_btn); layout->insertWidget(insert_index, later_btn); } } support_btn->setAutoDefault(true); support_btn->setDefault(true); later_btn->setAutoDefault(false); donated_btn->setAutoDefault(false); support_btn->setFocus(); box.setDefaultButton(support_btn); box.exec(); const QAbstractButton* clicked = box.clickedButton(); auto prompt_for_donation_code = [this]() -> SupportPromptResult { SupportCodeManager support_codes(Utils::utf8_to_path(settings.get_config_dir())); while (true) { bool accepted = false; const QString code = QInputDialog::getText( this, tr("Donation code"), tr("Enter the donation code generated after your donation.\n" "A valid code will permanently hide the donation dialog."), QLineEdit::Normal, QString(), &accepted); if (!accepted) { return SupportPromptResult::NotSure; } if (support_codes.redeem_code(to_utf8(code))) { return SupportPromptResult::Support; } QMessageBox::warning( this, tr("Invalid donation code"), tr("The donation code is invalid. Please try again or press Cancel.")); } }; if (clicked == support_btn) { if (!MainAppHelpActions::open_support_page()) { QMessageBox::information( this, tr("Open donation page"), tr("Could not open your browser automatically.\nPlease open this link manually:\n%1") .arg(MainAppHelpActions::support_page_url())); } return prompt_for_donation_code(); } if (clicked == donated_btn) { return prompt_for_donation_code(); } return SupportPromptResult::NotSure; } void MainApp::handle_analysis_finished() { update_analyze_button_state(false); if (analyze_thread.joinable()) { analyze_thread.join(); } if (progress_dialog) { progress_dialog->hide(); progress_dialog.reset(); } stop_analysis = false; if (new_files_to_sort.empty()) { handle_no_files_to_sort(); return; } populate_tree_view(new_files_to_sort); show_results_dialog(new_files_to_sort); } void MainApp::handle_analysis_cancelled() { update_analyze_button_state(false); if (analyze_thread.joinable()) { analyze_thread.join(); } if (progress_dialog) { progress_dialog->hide(); progress_dialog.reset(); } stop_analysis = false; statusBar()->showMessage(tr("Analysis cancelled"), 4000); } void MainApp::handle_analysis_failure(const std::string& message) { update_analyze_button_state(false); if (analyze_thread.joinable()) { analyze_thread.join(); } if (progress_dialog) { progress_dialog->hide(); progress_dialog.reset(); } stop_analysis = false; show_error_dialog(message); } void MainApp::handle_no_files_to_sort() { show_error_dialog(ERR_NO_FILES_TO_CATEGORIZE); } void MainApp::populate_tree_view(const std::vector& files) { tree_model->removeRows(0, tree_model->rowCount()); for (const auto& file : files) { QList row; auto* file_item = new QStandardItem(QString::fromStdString(file.file_name)); auto* type_item = new QStandardItem(file.type == FileType::Directory ? tr("Directory") : tr("File")); type_item->setData(file.type == FileType::Directory ? QStringLiteral("D") : QStringLiteral("F"), Qt::UserRole); auto* category_item = new QStandardItem(QString::fromStdString(file.category)); auto* subcategory_item = new QStandardItem(QString::fromStdString(file.subcategory)); auto* status_item = new QStandardItem(tr("Ready")); status_item->setData(QStringLiteral("ready"), Qt::UserRole); row << file_item << type_item << category_item << subcategory_item << status_item; tree_model->appendRow(row); } } void MainApp::append_progress(const std::string& message) { run_on_ui([this, message]() { if (progress_dialog) { progress_dialog->append_text(message); } }); } void MainApp::configure_progress_stages(const std::vector& stages) { run_on_ui_blocking([this, stages]() { if (progress_dialog) { progress_dialog->configure_stages(stages); } }); } void MainApp::set_progress_stage_items(CategorizationProgressDialog::StageId stage_id, const std::vector& items) { run_on_ui_blocking([this, stage_id, items]() { if (progress_dialog) { progress_dialog->set_stage_items(stage_id, items); } }); } void MainApp::set_progress_active_stage(CategorizationProgressDialog::StageId stage_id) { run_on_ui_blocking([this, stage_id]() { if (progress_dialog) { progress_dialog->set_active_stage(stage_id); } }); } void MainApp::mark_progress_stage_item_in_progress(CategorizationProgressDialog::StageId stage_id, const FileEntry& entry) { run_on_ui_blocking([this, stage_id, entry]() { if (progress_dialog) { progress_dialog->mark_stage_item_in_progress(stage_id, entry); } }); } void MainApp::mark_progress_stage_item_completed(CategorizationProgressDialog::StageId stage_id, const FileEntry& entry) { run_on_ui_blocking([this, stage_id, entry]() { if (progress_dialog) { progress_dialog->mark_stage_item_completed(stage_id, entry); } }); } bool MainApp::should_abort_analysis() const { return stop_analysis.load(); } void MainApp::prune_empty_cached_entries_for(const std::string& directory_path) { const std::vector cleared = categorization_service.prune_empty_cached_entries(directory_path); if (cleared.empty()) { return; } if (core_logger) { core_logger->warn("Cleared {} cached categorization entr{} with empty values for '{}'", cleared.size(), cleared.size() == 1 ? "y" : "ies", directory_path); for (const auto& entry : cleared) { core_logger->warn(" - {}", entry.file_name); } } std::string reason = "Cached category was empty. The item will be analyzed again."; if (!using_local_llm) { reason += " Configure your remote API key before analyzing."; } notify_recategorization_reset(cleared, reason); } void MainApp::log_cached_highlights() { if (already_categorized_files.empty()) { return; } append_progress(to_utf8(tr("[ARCHIVE] Already categorized highlights:"))); for (const auto& file_entry : already_categorized_files) { const QString type_label = file_entry.type == FileType::Directory ? tr("Directory") : tr("File"); const QString sub = file_entry.subcategory.empty() ? QStringLiteral("-") : QString::fromStdString(file_entry.subcategory); append_progress(to_utf8(QStringLiteral(" - [%1] %2 -> %3 / %4") .arg(type_label, QString::fromStdString(file_entry.file_name), QString::fromStdString(file_entry.category), sub))); } } void MainApp::log_pending_queue() { if (!progress_dialog) { return; } if (files_to_categorize.empty()) { append_progress(to_utf8(tr("[DONE] No files to categorize."))); return; } append_progress(to_utf8(tr("[QUEUE] Items waiting for categorization:"))); for (const auto& file_entry : files_to_categorize) { const QString type_label = file_entry.type == FileType::Directory ? tr("Directory") : tr("File"); append_progress(to_utf8(QStringLiteral(" - [%1] %2") .arg(type_label, QString::fromStdString(file_entry.file_name)))); } } void MainApp::perform_analysis() { const std::string directory_path = get_folder_path(); core_logger->info("Starting analysis for directory '{}'", directory_path); bool stop_requested = false; auto update_stop = [this, &stop_requested]() { if (!stop_requested && should_abort_analysis()) { stop_requested = true; } return stop_requested; }; append_progress(to_utf8(tr("[SCAN] Exploring %1") .arg(QString::fromStdString(directory_path)))); update_stop(); try { prune_empty_cached_entries_for(directory_path); const bool analyze_images = settings.get_analyze_images_by_content(); const bool analyze_documents = settings.get_analyze_documents_by_content(); const bool process_images_only = analyze_images && settings.get_process_images_only(); const bool process_documents_only = analyze_documents && settings.get_process_documents_only(); const bool rename_images_only = analyze_images && settings.get_rename_images_only(); const bool rename_documents_only = analyze_documents && settings.get_rename_documents_only(); const bool allow_image_renames = settings.get_offer_rename_images(); const bool allow_document_renames = settings.get_offer_rename_documents(); const bool offer_image_renames = analyze_images && allow_image_renames; const bool offer_document_renames = analyze_documents && allow_document_renames; const bool wants_visual_rename = analyze_images && allow_image_renames && !rename_images_only; const bool wants_document_rename = analyze_documents && allow_document_renames && !rename_documents_only; const bool add_image_date_place_prefixes = analyze_images && allow_image_renames && settings.get_add_image_date_place_to_filename(); const bool add_image_date_to_category = analyze_images && settings.get_add_image_date_to_category(); const bool add_audio_video_metadata_to_filename = settings.get_add_audio_video_metadata_to_filename(); const bool add_document_date = analyze_documents && settings.get_add_document_date_to_category(); const bool use_full_path_keys = settings.get_include_subdirectories(); const auto cached_entries = categorization_service.load_cached_entries(directory_path); std::vector pending_renames; pending_renames.reserve(cached_entries.size()); std::unordered_set renamed_files; already_categorized_files.clear(); already_categorized_files.reserve(cached_entries.size()); std::vector cached_image_entries_for_visual; std::unordered_map cached_visual_indices; std::vector cached_document_entries_for_analysis; std::unordered_map cached_document_indices; std::unordered_map cached_image_suggestions; std::unordered_map cached_document_suggestions; if (wants_visual_rename) { cached_image_entries_for_visual.reserve(cached_entries.size()); cached_visual_indices.reserve(cached_entries.size()); } if (wants_document_rename) { cached_document_entries_for_analysis.reserve(cached_entries.size()); cached_document_indices.reserve(cached_entries.size()); } auto to_lower = [](std::string value) { std::transform(value.begin(), value.end(), value.begin(), [](unsigned char ch) { return static_cast(std::tolower(ch)); }); return value; }; auto has_category = [](const CategorizedFile& entry) { return !entry.category.empty() && !entry.subcategory.empty(); }; auto is_supported_image_entry = [](const CategorizedFile& entry) { if (entry.type != FileType::File) { return false; } const auto full_path = Utils::utf8_to_path(entry.file_path) / Utils::utf8_to_path(entry.file_name); return LlavaImageAnalyzer::is_supported_image(full_path); }; auto is_supported_document_entry = [](const CategorizedFile& entry) { if (entry.type != FileType::File) { return false; } const auto full_path = Utils::utf8_to_path(entry.file_path) / Utils::utf8_to_path(entry.file_name); return DocumentTextAnalyzer::is_supported_document(full_path); }; auto is_missing_category_label = [](const std::string& value) { std::string trimmed = value; const auto not_space = [](unsigned char ch) { return !std::isspace(ch); }; trimmed.erase(trimmed.begin(), std::find_if(trimmed.begin(), trimmed.end(), not_space)); trimmed.erase(std::find_if(trimmed.rbegin(), trimmed.rend(), not_space).base(), trimmed.end()); if (trimmed.empty()) { return true; } std::transform(trimmed.begin(), trimmed.end(), trimmed.begin(), [](unsigned char ch) { return static_cast(std::tolower(ch)); }); return trimmed == "uncategorized"; }; auto file_key = [use_full_path_keys](const CategorizedFile& entry) { if (!use_full_path_keys) { return entry.file_name; } const auto full_path = Utils::utf8_to_path(entry.file_path) / Utils::utf8_to_path(entry.file_name); return Utils::path_to_utf8(full_path); }; auto entry_key = [use_full_path_keys](const FileEntry& entry) { return use_full_path_keys ? entry.full_path : entry.file_name; }; auto resolve_entry_for_storage = [this](const CategorizedFile& entry) { const std::string canonical_category = entry.canonical_category.empty() ? entry.category : entry.canonical_category; const std::string canonical_subcategory = entry.canonical_subcategory.empty() ? entry.subcategory : entry.canonical_subcategory; if (!canonical_category.empty()) { return db_manager.resolve_category(canonical_category, canonical_subcategory); } return db_manager.resolve_category_for_language(entry.category, entry.subcategory, settings.get_category_language()); }; auto persist_rename_only_progress = [this, &is_missing_category_label](const FileEntry& entry, const std::string& suggested_name) { // Persist rename-only progress during analysis to avoid losing rename suggestions on crash. const auto entry_path = Utils::utf8_to_path(entry.full_path); const std::string dir_path = Utils::path_to_utf8(entry_path.parent_path()); const auto cached_entry = db_manager.get_categorized_file(dir_path, entry.file_name, entry.type); std::string category; std::string subcategory; bool used_consistency = false; DatabaseManager::ResolvedCategory resolved{0, "", ""}; if (cached_entry) { category = cached_entry->category; subcategory = cached_entry->subcategory; if (is_missing_category_label(category)) { category.clear(); } if (is_missing_category_label(subcategory)) { subcategory.clear(); } if (!category.empty()) { resolved.category = category; resolved.subcategory = subcategory; resolved.taxonomy_id = cached_entry->taxonomy_id; } used_consistency = cached_entry->used_consistency_hints; } const std::string file_type_label = (entry.type == FileType::Directory) ? "D" : "F"; db_manager.insert_or_update_file_with_categorization( entry.file_name, file_type_label, dir_path, resolved, used_consistency, suggested_name, true); }; auto persist_llm_suggestion_progress = [this, &is_missing_category_label](const FileEntry& entry, const std::string& suggested_name) { if (suggested_name.empty()) { return; } const auto entry_path = Utils::utf8_to_path(entry.full_path); const std::string dir_path = Utils::path_to_utf8(entry_path.parent_path()); const auto cached_entry = db_manager.get_categorized_file(dir_path, entry.file_name, entry.type); std::string category; std::string subcategory; bool used_consistency = false; bool rename_applied = false; DatabaseManager::ResolvedCategory resolved{0, "", ""}; if (cached_entry) { category = cached_entry->category; subcategory = cached_entry->subcategory; if (is_missing_category_label(category)) { category.clear(); } if (is_missing_category_label(subcategory)) { subcategory.clear(); } if (!category.empty()) { resolved.category = category; resolved.subcategory = subcategory; resolved.taxonomy_id = cached_entry->taxonomy_id; } used_consistency = cached_entry->used_consistency_hints; rename_applied = cached_entry->rename_applied; } const std::string file_type_label = (entry.type == FileType::Directory) ? "D" : "F"; db_manager.insert_or_update_file_with_categorization( entry.file_name, file_type_label, dir_path, resolved, used_consistency, suggested_name, false, rename_applied); }; auto persist_cached_suggestion = [this, &resolve_entry_for_storage](const CategorizedFile& entry, const std::string& suggested_name) { DatabaseManager::ResolvedCategory resolved = resolve_entry_for_storage(entry); const std::string file_type_label = (entry.type == FileType::Directory) ? "D" : "F"; db_manager.insert_or_update_file_with_categorization( entry.file_name, file_type_label, entry.file_path, resolved, entry.used_consistency_hints, suggested_name, entry.rename_only, entry.rename_applied); }; auto persist_analysis_results = [this, &is_missing_category_label, &resolve_entry_for_storage](const std::vector& entries) { for (const auto& entry : entries) { std::string category = entry.category; std::string subcategory = entry.subcategory; if (is_missing_category_label(category)) { category.clear(); } if (is_missing_category_label(subcategory)) { subcategory.clear(); } if (category.empty() && subcategory.empty() && entry.suggested_name.empty()) { continue; } DatabaseManager::ResolvedCategory resolved{0, "", ""}; if (!category.empty()) { resolved = resolve_entry_for_storage(entry); } const std::string file_type_label = (entry.type == FileType::Directory) ? "D" : "F"; db_manager.insert_or_update_file_with_categorization( entry.file_name, file_type_label, entry.file_path, resolved, entry.used_consistency_hints, entry.suggested_name, entry.rename_only, entry.rename_applied); } }; for (const auto& cached_entry : cached_entries) { auto entry = cached_entry; const bool is_image_entry = is_supported_image_entry(entry); const bool is_document_entry = is_supported_document_entry(entry); const bool allow_entry_renames = (is_image_entry && allow_image_renames) || (is_document_entry && allow_document_renames); const bool suggested_matches = !entry.suggested_name.empty() && to_lower(entry.suggested_name) == to_lower(entry.file_name); const bool already_renamed = entry.rename_applied || suggested_matches; if (already_renamed) { renamed_files.insert(file_key(entry)); } if (entry.rename_only && !has_category(entry)) { if (!allow_entry_renames) { continue; } if (!already_renamed) { pending_renames.push_back(entry); if (is_image_entry && !rename_images_only && !entry.suggested_name.empty()) { cached_image_suggestions.emplace(file_key(entry), entry.suggested_name); } if (is_document_entry && !rename_documents_only && !entry.suggested_name.empty()) { cached_document_suggestions.emplace(file_key(entry), entry.suggested_name); } } continue; } if (!has_category(entry)) { if (!entry.suggested_name.empty()) { if (is_image_entry) { cached_image_suggestions.emplace(file_key(entry), entry.suggested_name); } if (is_document_entry) { cached_document_suggestions.emplace(file_key(entry), entry.suggested_name); } if (!already_renamed && allow_entry_renames && ((rename_images_only && analyze_images && is_image_entry) || (rename_documents_only && analyze_documents && is_document_entry))) { CategorizedFile adjusted = entry; adjusted.rename_only = true; pending_renames.push_back(std::move(adjusted)); } } continue; } if (!allow_entry_renames) { entry.suggested_name.clear(); entry.rename_only = false; } if (rename_images_only && analyze_images && is_image_entry) { if (!already_renamed && entry.suggested_name.empty()) { continue; } CategorizedFile adjusted = entry; adjusted.rename_only = true; already_categorized_files.push_back(std::move(adjusted)); continue; } if (rename_documents_only && analyze_documents && is_document_entry) { if (!already_renamed && entry.suggested_name.empty()) { continue; } CategorizedFile adjusted = entry; adjusted.rename_only = true; already_categorized_files.push_back(std::move(adjusted)); continue; } if (wants_visual_rename && is_image_entry && entry.suggested_name.empty() && !already_renamed) { const auto entry_index = already_categorized_files.size(); already_categorized_files.push_back(entry); cached_visual_indices.emplace(file_key(entry), entry_index); const auto full_path = Utils::utf8_to_path(entry.file_path) / Utils::utf8_to_path(entry.file_name); cached_image_entries_for_visual.push_back( FileEntry{Utils::path_to_utf8(full_path), entry.file_name, entry.type}); continue; } if (wants_document_rename && is_document_entry && entry.suggested_name.empty() && !already_renamed) { const auto entry_index = already_categorized_files.size(); already_categorized_files.push_back(entry); cached_document_indices.emplace(file_key(entry), entry_index); const auto full_path = Utils::utf8_to_path(entry.file_path) / Utils::utf8_to_path(entry.file_name); cached_document_entries_for_analysis.push_back( FileEntry{Utils::path_to_utf8(full_path), entry.file_name, entry.type}); continue; } already_categorized_files.push_back(entry); } if (process_images_only || process_documents_only) { const bool allow_images = process_images_only; const bool allow_documents = process_documents_only; auto filter_entries = [&](std::vector& entries) { entries.erase( std::remove_if(entries.begin(), entries.end(), [&](const CategorizedFile& entry) { if (entry.type != FileType::File) { return true; } const auto full_path = Utils::utf8_to_path(entry.file_path) / Utils::utf8_to_path(entry.file_name); const bool is_image = LlavaImageAnalyzer::is_supported_image(full_path); const bool is_document = DocumentTextAnalyzer::is_supported_document(full_path); if (is_image && allow_images) { return false; } if (is_document && allow_documents) { return false; } return true; }), entries.end()); }; filter_entries(already_categorized_files); filter_entries(pending_renames); if (!cached_visual_indices.empty()) { for (size_t index = 0; index < already_categorized_files.size(); ++index) { auto it = cached_visual_indices.find(file_key(already_categorized_files[index])); if (it != cached_visual_indices.end()) { it->second = index; } } } if (!cached_document_indices.empty()) { for (size_t index = 0; index < already_categorized_files.size(); ++index) { auto it = cached_document_indices.find(file_key(already_categorized_files[index])); if (it != cached_document_indices.end()) { it->second = index; } } } } update_stop(); log_cached_highlights(); auto cached_file_names = results_coordinator.extract_file_names(already_categorized_files, use_full_path_keys); if ((rename_images_only || rename_documents_only) && !pending_renames.empty()) { for (const auto& entry : pending_renames) { cached_file_names.insert(file_key(entry)); } } const auto scan_options = effective_scan_options(); files_to_categorize = results_coordinator.find_files_to_categorize(directory_path, scan_options, cached_file_names, use_full_path_keys); if (process_images_only || process_documents_only) { const bool allow_images = process_images_only; const bool allow_documents = process_documents_only; files_to_categorize.erase( std::remove_if(files_to_categorize.begin(), files_to_categorize.end(), [&](const FileEntry& entry) { if (entry.type != FileType::File) { return true; } const bool is_image = LlavaImageAnalyzer::is_supported_image(entry.full_path); const bool is_document = DocumentTextAnalyzer::is_supported_document(entry.full_path); if (is_image && allow_images) { return false; } if (is_document && allow_documents) { return false; } return true; }), files_to_categorize.end()); } core_logger->debug("Found {} item(s) pending categorization in '{}'.", files_to_categorize.size(), directory_path); log_pending_queue(); update_stop(); append_progress(to_utf8(tr("[PROCESS] Letting the AI do its magic..."))); std::vector image_entries; std::vector document_entries; std::vector other_entries; split_entries_for_analysis(files_to_categorize, analyze_images, analyze_documents, process_images_only, process_documents_only, rename_images_only, rename_documents_only, settings.get_categorize_files(), use_full_path_keys, renamed_files, image_entries, document_entries, other_entries); if (!cached_image_entries_for_visual.empty()) { image_entries.insert(image_entries.end(), cached_image_entries_for_visual.begin(), cached_image_entries_for_visual.end()); } if (!cached_document_entries_for_analysis.empty()) { document_entries.insert(document_entries.end(), cached_document_entries_for_analysis.begin(), cached_document_entries_for_analysis.end()); } using ProgressStageId = CategorizationProgressDialog::StageId; std::vector image_stage_entries; image_stage_entries.reserve(image_entries.size()); for (const auto& entry : image_entries) { const bool already_renamed = renamed_files.contains(entry_key(entry)); if (already_renamed && rename_images_only) { continue; } image_stage_entries.push_back(entry); } std::vector document_stage_entries; document_stage_entries.reserve(document_entries.size()); for (const auto& entry : document_entries) { const bool already_renamed = renamed_files.contains(entry_key(entry)); if (already_renamed && rename_documents_only) { continue; } document_stage_entries.push_back(entry); } std::vector planned_categorization_entries; std::unordered_set planned_categorization_seen; planned_categorization_entries.reserve(other_entries.size() + image_entries.size() + document_entries.size()); auto append_planned_categorization_entry = [&](const FileEntry& entry) { const std::string key = entry_key(entry); if (planned_categorization_seen.contains(key)) { return; } planned_categorization_seen.insert(key); planned_categorization_entries.push_back(entry); }; for (const auto& entry : other_entries) { append_planned_categorization_entry(entry); } if (!rename_images_only) { for (const auto& entry : image_entries) { if (cached_visual_indices.contains(entry_key(entry))) { continue; } append_planned_categorization_entry(entry); } } if (!rename_documents_only) { for (const auto& entry : document_entries) { if (cached_document_indices.contains(entry_key(entry))) { continue; } append_planned_categorization_entry(entry); } } std::vector progress_stages; if (!image_stage_entries.empty()) { progress_stages.push_back({ProgressStageId::ImageAnalysis, image_stage_entries}); } if (!document_stage_entries.empty()) { progress_stages.push_back({ProgressStageId::DocumentAnalysis, document_stage_entries}); } if (!planned_categorization_entries.empty()) { progress_stages.push_back({ProgressStageId::Categorization, planned_categorization_entries}); } configure_progress_stages(progress_stages); if (!progress_stages.empty()) { set_progress_active_stage(progress_stages.front().id); } struct ImageAnalysisInfo { std::string suggested_name; std::string prompt_name; std::string prompt_path; }; struct DocumentAnalysisInfo { std::string suggested_name; std::string prompt_name; std::string prompt_path; }; std::unordered_map image_info; std::vector image_entries_for_llm; image_entries_for_llm.reserve(image_entries.size()); std::vector analyzed_image_entries; analyzed_image_entries.reserve(image_entries.size()); std::unordered_map document_info; std::unordered_map image_dates; std::unordered_map document_dates; std::vector document_entries_for_llm; document_entries_for_llm.reserve(document_entries.size()); std::vector analyzed_document_entries; analyzed_document_entries.reserve(document_entries.size()); std::unique_ptr image_metadata_service; std::unique_ptr media_metadata_service; std::unordered_map media_rename_suggestions; if (add_image_date_place_prefixes || add_image_date_to_category) { image_metadata_service = std::make_unique(settings.get_config_dir()); } if (add_audio_video_metadata_to_filename) { media_metadata_service = std::make_unique(); } if (analyze_images && !image_entries.empty()) { if (!image_stage_entries.empty()) { set_progress_active_stage(ProgressStageId::ImageAnalysis); } auto enrich_image_suggestion = [&](const FileEntry& entry, const std::string& raw_suggested_name) { if (raw_suggested_name.empty() || !image_metadata_service) { return raw_suggested_name; } return image_metadata_service->enrich_suggested_name( Utils::utf8_to_path(entry.full_path), raw_suggested_name); }; auto cache_image_date = [&](const FileEntry& entry) { if (!add_image_date_to_category || !image_metadata_service) { return; } const std::string key = entry_key(entry); if (image_dates.contains(key)) { return; } if (const auto date = image_metadata_service->extract_capture_date( Utils::utf8_to_path(entry.full_path))) { image_dates.emplace(key, *date); } }; std::string error; auto visual_paths = resolve_visual_llm_paths(&error); if (!visual_paths) { throw std::runtime_error(error); } LlavaImageAnalyzer::Settings vision_settings; vision_settings.use_gpu = should_use_visual_gpu(); const auto visual_gpu_override = read_env_bool("AI_FILE_SORTER_VISUAL_USE_GPU"); if (visual_gpu_override.has_value()) { vision_settings.use_gpu = *visual_gpu_override; } vision_settings.batch_progress = [this](int current_batch, int total_batches) { if (total_batches <= 0 || current_batch <= 0) { return; } const double percent = (static_cast(current_batch) / static_cast(total_batches)) * 100.0; append_progress(to_utf8(tr("[VISION] Decoding image batch %1/%2 (%3%)") .arg(current_batch) .arg(total_batches) .arg(percent, 0, 'f', 2))); }; vision_settings.log_visual_output = should_log_prompts(); const bool allow_visual_cpu_fallback = vision_settings.use_gpu && !visual_gpu_override.has_value(); std::optional visual_cpu_fallback_choice; bool visual_cpu_fallback_active = false; auto should_retry_on_cpu = [](const std::exception& ex) { return should_offer_visual_cpu_fallback(ex.what()); }; auto prompt_visual_cpu_fallback = [this]() -> bool { auto show_dialog = [this]() -> bool { QMessageBox box(this); box.setIcon(QMessageBox::Question); box.setWindowTitle(tr("Switch image analysis to CPU?")); box.setText(tr("Image analysis ran out of GPU memory.")); box.setInformativeText(tr("Retry on CPU instead? Cancel will skip visual analysis and fall back to " "filename-based categorization.")); box.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); box.setDefaultButton(QMessageBox::Ok); return box.exec() == QMessageBox::Ok; }; if (QThread::currentThread() == thread()) { return show_dialog(); } bool decision = false; QMetaObject::invokeMethod( this, [&decision, show_dialog]() mutable { decision = show_dialog(); }, Qt::BlockingQueuedConnection); return decision; }; auto update_cached_image_suggestion = [&](const FileEntry& entry, const std::string& suggested_name) { const auto it = cached_visual_indices.find(entry_key(entry)); if (it == cached_visual_indices.end()) { return; } auto& cached_entry = already_categorized_files[it->second]; if (cached_entry.suggested_name == suggested_name) { return; } cached_entry.suggested_name = suggested_name; persist_cached_suggestion(cached_entry, suggested_name); }; auto handle_visual_failure = [&](const FileEntry& entry, const std::string& reason, bool already_renamed, bool log_failure, bool visual_only) { if (log_failure) { append_progress(to_utf8(tr("[VISION-ERROR] %1 (%2)") .arg(QString::fromStdString(entry.file_name), QString::fromStdString(reason)))); } if (!rename_images_only && !visual_only) { other_entries.push_back(entry); } const std::string suggested_name = already_renamed ? std::string() : enrich_image_suggestion(entry, entry.file_name); const std::string ui_suggested_name = (allow_image_renames || rename_images_only) ? suggested_name : std::string(); image_info.emplace(entry_key(entry), ImageAnalysisInfo{ui_suggested_name, entry.file_name, entry.full_path}); if (rename_images_only) { persist_rename_only_progress(entry, suggested_name); } if (visual_only) { update_cached_image_suggestion(entry, suggested_name); } }; auto create_analyzer = [&]() -> std::unique_ptr { return std::make_unique( visual_paths->model_path, visual_paths->mmproj_path, vision_settings); }; std::unique_ptr analyzer; bool skip_visual_analysis = false; std::string skip_visual_reason; try { analyzer = create_analyzer(); } catch (const std::exception& ex) { const bool retry_on_cpu = should_retry_on_cpu(ex); if (core_logger) { core_logger->warn("Visual analyzer initialization failed (retryable_on_cpu={}): {}", retry_on_cpu, ex.what()); } if (!allow_visual_cpu_fallback) { throw; } if (!retry_on_cpu) { skip_visual_analysis = true; skip_visual_reason = ex.what(); if (core_logger) { core_logger->warn("Visual analysis disabled after non-retryable initialization failure."); } } else { if (!visual_cpu_fallback_choice.has_value()) { visual_cpu_fallback_choice = prompt_visual_cpu_fallback(); } if (!visual_cpu_fallback_choice.value()) { skip_visual_analysis = true; skip_visual_reason = ex.what(); if (core_logger) { core_logger->warn("Visual CPU fallback declined after initialization failure: {}", ex.what()); } } else { append_progress(to_utf8(tr("[VISION] Switching visual analysis to CPU."))); vision_settings.use_gpu = false; visual_cpu_fallback_active = true; if (core_logger) { core_logger->warn("Retrying visual analyzer initialization on CPU after GPU failure: {}", ex.what()); } try { analyzer = create_analyzer(); if (core_logger) { core_logger->info("Visual analyzer CPU fallback initialized successfully."); } } catch (const std::exception& init_ex) { skip_visual_analysis = true; skip_visual_reason = init_ex.what(); if (core_logger) { core_logger->error("Visual analyzer CPU fallback initialization failed: {}", init_ex.what()); } } } } } if (skip_visual_analysis) { if (!skip_visual_reason.empty()) { if (core_logger) { core_logger->warn("Visual analysis disabled; falling back to filenames: {}", skip_visual_reason); } append_progress(to_utf8(tr("[VISION-ERROR] %1") .arg(QString::fromStdString(skip_visual_reason)))); } append_progress(to_utf8(tr("[VISION] Visual analysis disabled; falling back to filenames."))); for (const auto& entry : image_entries) { if (update_stop()) { break; } const bool already_renamed = renamed_files.contains(entry_key(entry)); if (already_renamed && rename_images_only) { continue; } const bool visual_only = cached_visual_indices.contains(entry_key(entry)); analyzed_image_entries.push_back(entry); cache_image_date(entry); mark_progress_stage_item_in_progress(ProgressStageId::ImageAnalysis, entry); handle_visual_failure(entry, std::string(), already_renamed, false, visual_only); mark_progress_stage_item_completed(ProgressStageId::ImageAnalysis, entry); } } else { bool stop_visual_analysis = false; for (size_t index = 0; index < image_entries.size(); ++index) { const auto& entry = image_entries[index]; if (update_stop()) { break; } const bool already_renamed = renamed_files.contains(entry_key(entry)); if (already_renamed && rename_images_only) { continue; } const bool visual_only = cached_visual_indices.contains(entry_key(entry)); const auto cached_suggestion_it = cached_image_suggestions.find(entry_key(entry)); const bool has_cached_suggestion = cached_suggestion_it != cached_image_suggestions.end(); analyzed_image_entries.push_back(entry); cache_image_date(entry); mark_progress_stage_item_in_progress(ProgressStageId::ImageAnalysis, entry); while (true) { try { if (has_cached_suggestion) { append_progress(to_utf8(tr("[VISION] Using cached suggestion for %1") .arg(QString::fromStdString(entry.file_name)))); const std::string prompt_name = cached_suggestion_it->second; const std::string enriched_name = enrich_image_suggestion(entry, prompt_name); const std::string suggested_name = already_renamed ? std::string() : enriched_name; const std::string ui_suggested_name = (allow_image_renames || rename_images_only) ? suggested_name : std::string(); const auto entry_path = Utils::utf8_to_path(entry.full_path); const auto prompt_path = Utils::path_to_utf8( entry_path.parent_path() / Utils::utf8_to_path(prompt_name)); image_info.emplace(entry_key(entry), ImageAnalysisInfo{ui_suggested_name, prompt_name, prompt_path}); if (rename_images_only) { persist_rename_only_progress(entry, suggested_name); } if (visual_only) { update_cached_image_suggestion(entry, suggested_name); } if (!rename_images_only && !visual_only) { image_entries_for_llm.push_back(entry); } mark_progress_stage_item_completed(ProgressStageId::ImageAnalysis, entry); break; } append_progress(to_utf8(tr("[VISION] Analyzing %1") .arg(QString::fromStdString(entry.file_name)))); const auto analysis = analyzer->analyze(entry.full_path); const std::string prompt_name = analysis.suggested_name; const std::string enriched_name = enrich_image_suggestion(entry, prompt_name); const auto entry_path = Utils::utf8_to_path(entry.full_path); const auto prompt_path = Utils::path_to_utf8( entry_path.parent_path() / Utils::utf8_to_path(prompt_name)); const std::string suggested_name = already_renamed ? std::string() : enriched_name; const std::string ui_suggested_name = (allow_image_renames || rename_images_only) ? suggested_name : std::string(); if (!rename_images_only) { persist_llm_suggestion_progress(entry, suggested_name); } image_info.emplace(entry_key(entry), ImageAnalysisInfo{ui_suggested_name, prompt_name, prompt_path}); if (rename_images_only) { persist_rename_only_progress(entry, suggested_name); } if (visual_only) { update_cached_image_suggestion(entry, suggested_name); } if (!rename_images_only && !visual_only) { image_entries_for_llm.push_back(entry); } mark_progress_stage_item_completed(ProgressStageId::ImageAnalysis, entry); break; } catch (const std::exception& ex) { const bool retry_on_cpu = should_retry_on_cpu(ex); if (!visual_cpu_fallback_active && allow_visual_cpu_fallback && retry_on_cpu) { if (core_logger) { core_logger->warn("Visual analysis failed for '{}' with retryable GPU error: {}", entry.file_name, ex.what()); } if (!visual_cpu_fallback_choice.has_value()) { visual_cpu_fallback_choice = prompt_visual_cpu_fallback(); } if (visual_cpu_fallback_choice.value()) { append_progress(to_utf8(tr("[VISION] GPU memory issue detected. Switching to CPU."))); vision_settings.use_gpu = false; visual_cpu_fallback_active = true; if (core_logger) { core_logger->warn("Retrying visual analysis on CPU for '{}'.", entry.file_name); } try { analyzer = create_analyzer(); if (core_logger) { core_logger->info("Visual analyzer CPU fallback initialized successfully; retrying '{}'.", entry.file_name); } } catch (const std::exception& init_ex) { if (core_logger) { core_logger->error("Visual analyzer CPU fallback initialization failed for '{}': {}", entry.file_name, init_ex.what()); } handle_visual_failure(entry, init_ex.what(), already_renamed, true, visual_only); append_progress(to_utf8(tr("[VISION] Visual analysis disabled for remaining images."))); stop_visual_analysis = true; } if (!stop_visual_analysis) { continue; } } else { if (core_logger) { core_logger->warn("Visual CPU fallback declined for '{}': {}", entry.file_name, ex.what()); } append_progress(to_utf8(tr("[VISION] Visual analysis disabled; falling back to filenames."))); handle_visual_failure(entry, ex.what(), already_renamed, true, visual_only); stop_visual_analysis = true; } } else { if (core_logger) { core_logger->warn("Visual analysis failed for '{}': {}", entry.file_name, ex.what()); } handle_visual_failure(entry, ex.what(), already_renamed, true, visual_only); } mark_progress_stage_item_completed(ProgressStageId::ImageAnalysis, entry); break; } } if (stop_visual_analysis) { for (size_t remaining = index + 1; remaining < image_entries.size(); ++remaining) { if (update_stop()) { break; } const auto& pending = image_entries[remaining]; const bool pending_renamed = renamed_files.contains(entry_key(pending)); if (pending_renamed && rename_images_only) { continue; } const bool pending_visual_only = cached_visual_indices.contains(entry_key(pending)); analyzed_image_entries.push_back(pending); cache_image_date(pending); mark_progress_stage_item_in_progress(ProgressStageId::ImageAnalysis, pending); handle_visual_failure(pending, std::string(), pending_renamed, false, pending_visual_only); mark_progress_stage_item_completed(ProgressStageId::ImageAnalysis, pending); } break; } } } } if (analyze_documents && !document_entries.empty()) { if (!document_stage_entries.empty()) { set_progress_active_stage(ProgressStageId::DocumentAnalysis); } auto update_cached_document_suggestion = [&](const FileEntry& entry, const std::string& suggested_name) { const auto it = cached_document_indices.find(entry_key(entry)); if (it == cached_document_indices.end()) { return; } auto& cached_entry = already_categorized_files[it->second]; if (cached_entry.suggested_name == suggested_name) { return; } cached_entry.suggested_name = suggested_name; persist_cached_suggestion(cached_entry, suggested_name); }; auto handle_document_failure = [&](const FileEntry& entry, const std::string& reason, bool already_renamed, bool log_failure, bool document_only) { if (log_failure) { append_progress(to_utf8(tr("[DOC-ERROR] %1 (%2)") .arg(QString::fromStdString(entry.file_name), QString::fromStdString(reason)))); if (core_logger) { const char* fallback_action = "falling back to filename-based categorization"; if (rename_documents_only) { fallback_action = "keeping the original filename in rename-only mode"; } else if (document_only) { fallback_action = "restoring the original filename as the cached suggestion"; } core_logger->warn("Document analysis failed for '{}': {}; {}.", entry.file_name, reason, fallback_action); } } if (!rename_documents_only && !document_only) { other_entries.push_back(entry); } const std::string suggested_name = already_renamed ? std::string() : entry.file_name; const std::string ui_suggested_name = (allow_document_renames || rename_documents_only) ? suggested_name : std::string(); const std::string prompt_name = entry.file_name; document_info.emplace(entry_key(entry), DocumentAnalysisInfo{ui_suggested_name, prompt_name, build_document_prompt_path(entry.full_path, prompt_name, {})}); if (rename_documents_only) { persist_rename_only_progress(entry, suggested_name); } if (document_only) { update_cached_document_suggestion(entry, suggested_name); } }; DocumentTextAnalyzer::Settings doc_settings; doc_settings.max_tokens = 256; const size_t char_budget = resolve_document_char_budget(using_local_llm, doc_settings.max_tokens); doc_settings.max_characters = std::min(doc_settings.max_characters, char_budget); DocumentTextAnalyzer doc_analyzer(doc_settings); auto llm = make_llm_client(); if (!llm) { throw std::runtime_error("Failed to create LLM client."); } llm->set_prompt_logging_enabled(should_log_prompts()); for (const auto& entry : document_entries) { if (update_stop()) { break; } const bool already_renamed = renamed_files.contains(entry_key(entry)); if (already_renamed && rename_documents_only) { continue; } const bool document_only = cached_document_indices.contains(entry_key(entry)); const auto cached_suggestion_it = cached_document_suggestions.find(entry_key(entry)); const bool has_cached_suggestion = cached_suggestion_it != cached_document_suggestions.end(); if (add_document_date && !document_dates.contains(entry_key(entry))) { const auto date = DocumentTextAnalyzer::extract_creation_date( Utils::utf8_to_path(entry.full_path)); if (date) { document_dates.emplace(entry_key(entry), *date); } } analyzed_document_entries.push_back(entry); mark_progress_stage_item_in_progress(ProgressStageId::DocumentAnalysis, entry); try { if (has_cached_suggestion) { append_progress(to_utf8(tr("[DOC] Using cached suggestion for %1") .arg(QString::fromStdString(entry.file_name)))); const std::string suggested_name = already_renamed ? std::string() : cached_suggestion_it->second; const std::string ui_suggested_name = (allow_document_renames || rename_documents_only) ? suggested_name : std::string(); const std::string prompt_name = resolve_document_prompt_name(entry.file_name, cached_suggestion_it->second); document_info.emplace(entry_key(entry), DocumentAnalysisInfo{ui_suggested_name, prompt_name, build_document_prompt_path(entry.full_path, prompt_name, {})}); if (rename_documents_only) { persist_rename_only_progress(entry, suggested_name); } if (!rename_documents_only && !document_only) { document_entries_for_llm.push_back(entry); } mark_progress_stage_item_completed(ProgressStageId::DocumentAnalysis, entry); continue; } append_progress(to_utf8(tr("[DOC] Analyzing %1") .arg(QString::fromStdString(entry.file_name)))); const auto analysis = doc_analyzer.analyze(Utils::utf8_to_path(entry.full_path), *llm); const std::string suggested_name = already_renamed ? std::string() : analysis.suggested_name; const std::string ui_suggested_name = (allow_document_renames || rename_documents_only) ? suggested_name : std::string(); const std::string prompt_name = resolve_document_prompt_name(entry.file_name, analysis.suggested_name); const std::string prompt_path = build_document_prompt_path(entry.full_path, prompt_name, analysis.summary); if (!rename_documents_only) { persist_llm_suggestion_progress(entry, suggested_name); } document_info.emplace(entry_key(entry), DocumentAnalysisInfo{ui_suggested_name, prompt_name, prompt_path}); if (rename_documents_only) { persist_rename_only_progress(entry, suggested_name); } if (document_only) { update_cached_document_suggestion(entry, suggested_name); } if (!rename_documents_only && !document_only) { document_entries_for_llm.push_back(entry); } mark_progress_stage_item_completed(ProgressStageId::DocumentAnalysis, entry); } catch (const std::exception& ex) { handle_document_failure(entry, ex.what(), already_renamed, true, document_only); mark_progress_stage_item_completed(ProgressStageId::DocumentAnalysis, entry); } } } update_stop(); std::vector categorization_stage_entries; std::unordered_set categorization_stage_seen; categorization_stage_entries.reserve(other_entries.size() + image_entries_for_llm.size() + document_entries_for_llm.size()); auto append_categorization_stage_entry = [&](const FileEntry& entry) { const std::string key = entry_key(entry); if (categorization_stage_seen.contains(key)) { return; } categorization_stage_seen.insert(key); categorization_stage_entries.push_back(entry); }; if (!stop_requested) { for (const auto& entry : other_entries) { append_categorization_stage_entry(entry); } } for (const auto& entry : image_entries_for_llm) { append_categorization_stage_entry(entry); } for (const auto& entry : document_entries_for_llm) { append_categorization_stage_entry(entry); } set_progress_stage_items(ProgressStageId::Categorization, categorization_stage_entries); if (!categorization_stage_entries.empty()) { set_progress_active_stage(ProgressStageId::Categorization); } auto suggested_name_provider = [allow_image_renames, allow_document_renames, add_audio_video_metadata_to_filename, &image_info, &document_info, &media_metadata_service, &media_rename_suggestions, &entry_key](const FileEntry& entry) -> std::string { const std::string key = entry_key(entry); if (allow_image_renames) { if (const auto it = image_info.find(key); it != image_info.end()) { return it->second.suggested_name; } } if (allow_document_renames) { if (const auto it = document_info.find(key); it != document_info.end()) { return it->second.suggested_name; } } if (add_audio_video_metadata_to_filename && media_metadata_service && entry.type == FileType::File) { const auto cache_it = media_rename_suggestions.find(key); if (cache_it != media_rename_suggestions.end()) { return cache_it->second; } std::string suggestion; if (MediaRenameMetadataService::is_supported_media(Utils::utf8_to_path(entry.full_path))) { if (const auto suggested = media_metadata_service->suggest_name( Utils::utf8_to_path(entry.full_path))) { suggestion = *suggested; } } media_rename_suggestions.emplace(key, suggestion); return suggestion; } return std::string(); }; auto apply_image_dates = [this, add_image_date_to_category, &image_dates, &file_key, &resolve_entry_for_storage, &image_metadata_service](std::vector& results) { if (!add_image_date_to_category) { return; } for (auto& entry : results) { if (entry.type != FileType::File) { continue; } const auto full_path = Utils::utf8_to_path(entry.file_path) / Utils::utf8_to_path(entry.file_name); if (!LlavaImageAnalyzer::is_supported_image(full_path)) { continue; } const std::string key = file_key(entry); auto it = image_dates.find(key); if (it == image_dates.end() && image_metadata_service) { if (const auto date = image_metadata_service->extract_capture_date(full_path)) { it = image_dates.emplace(key, *date).first; } } if (it == image_dates.end() || it->second.empty()) { continue; } if (entry.category.empty()) { continue; } const std::string suffix = "_" + it->second; if (entry.category.size() >= suffix.size() && entry.category.compare(entry.category.size() - suffix.size(), suffix.size(), suffix) == 0) { continue; } entry.category += suffix; if (entry.canonical_category.empty()) { entry.canonical_category = entry.category.substr(0, entry.category.size() - suffix.size()); } entry.canonical_category += suffix; DatabaseManager::ResolvedCategory resolved = resolve_entry_for_storage(entry); const std::string file_type_label = (entry.type == FileType::Directory) ? "D" : "F"; db_manager.insert_or_update_file_with_categorization( entry.file_name, file_type_label, entry.file_path, resolved, entry.used_consistency_hints, entry.suggested_name, entry.rename_only, entry.rename_applied); } }; auto apply_document_dates = [this, add_document_date, &document_dates, &file_key, &resolve_entry_for_storage](std::vector& results) { if (!add_document_date || document_dates.empty()) { return; } for (auto& entry : results) { if (entry.type != FileType::File) { continue; } const auto full_path = Utils::utf8_to_path(entry.file_path) / Utils::utf8_to_path(entry.file_name); if (!DocumentTextAnalyzer::is_supported_document(full_path)) { continue; } const std::string key = file_key(entry); auto it = document_dates.find(key); if (it == document_dates.end()) { if (const auto date = DocumentTextAnalyzer::extract_creation_date(full_path)) { it = document_dates.emplace(key, *date).first; } } if (it == document_dates.end() || it->second.empty()) { continue; } if (entry.category.empty()) { continue; } const std::string suffix = "_" + it->second; if (entry.category.size() >= suffix.size() && entry.category.compare(entry.category.size() - suffix.size(), suffix.size(), suffix) == 0) { continue; } entry.category += suffix; if (entry.canonical_category.empty()) { entry.canonical_category = entry.category.substr(0, entry.category.size() - suffix.size()); } entry.canonical_category += suffix; DatabaseManager::ResolvedCategory resolved = resolve_entry_for_storage(entry); const std::string file_type_label = (entry.type == FileType::Directory) ? "D" : "F"; db_manager.insert_or_update_file_with_categorization( entry.file_name, file_type_label, entry.file_path, resolved, entry.used_consistency_hints, entry.suggested_name, entry.rename_only, entry.rename_applied); } }; std::vector other_results; if (!stop_requested && !other_entries.empty()) { other_results = categorization_service.categorize_entries( other_entries, using_local_llm, stop_analysis, [this](const std::string& message) { append_progress(message); }, [this](const FileEntry& entry) { mark_progress_stage_item_in_progress(ProgressStageId::Categorization, entry); const QString type_label = entry.type == FileType::Directory ? tr("Directory") : tr("File"); append_progress(to_utf8(tr("[SORT] %1 (%2)") .arg(QString::fromStdString(entry.file_name), type_label))); }, [this](const FileEntry& entry) { mark_progress_stage_item_completed(ProgressStageId::Categorization, entry); }, [this](const CategorizedFile& entry, const std::string& reason) { notify_recategorization_reset(entry, reason); }, [this]() { return make_llm_client(); }, {}, suggested_name_provider); } apply_image_dates(other_results); apply_document_dates(other_results); update_stop(); std::vector image_results; if (analyze_images && !analyzed_image_entries.empty()) { if (rename_images_only) { image_results.reserve(analyzed_image_entries.size()); for (const auto& entry : analyzed_image_entries) { const auto entry_path = Utils::utf8_to_path(entry.full_path); CategorizedFile result{Utils::path_to_utf8(entry_path.parent_path()), entry.file_name, entry.type, "", "", 0}; result.rename_only = true; if (offer_image_renames || rename_images_only) { const auto info_it = image_info.find(entry_key(entry)); if (info_it != image_info.end()) { result.suggested_name = info_it->second.suggested_name; } } image_results.push_back(std::move(result)); } } else if (!image_entries_for_llm.empty()) { const bool stop_before_image_categorization = stop_requested; const bool bypass_stop = stop_before_image_categorization && other_results.empty(); std::atomic image_stop{false}; std::atomic& stop_flag = bypass_stop ? image_stop : stop_analysis; auto override_provider = [&image_info, &entry_key](const FileEntry& entry) -> std::optional { const auto it = image_info.find(entry_key(entry)); if (it == image_info.end()) { return std::nullopt; } return CategorizationService::PromptOverride{it->second.prompt_name, it->second.prompt_path}; }; image_results = categorization_service.categorize_entries( image_entries_for_llm, using_local_llm, stop_flag, [this](const std::string& message) { append_progress(message); }, [this](const FileEntry& entry) { mark_progress_stage_item_in_progress(ProgressStageId::Categorization, entry); const QString type_label = entry.type == FileType::Directory ? tr("Directory") : tr("File"); append_progress(to_utf8(tr("[SORT] %1 (%2)") .arg(QString::fromStdString(entry.file_name), type_label))); }, [this](const FileEntry& entry) { mark_progress_stage_item_completed(ProgressStageId::Categorization, entry); }, [this](const CategorizedFile& entry, const std::string& reason) { notify_recategorization_reset(entry, reason); }, [this]() { return make_llm_client(); }, override_provider, suggested_name_provider); update_stop(); } } apply_image_dates(image_results); std::vector document_results; if (analyze_documents && !analyzed_document_entries.empty()) { if (rename_documents_only) { document_results.reserve(analyzed_document_entries.size()); for (const auto& entry : analyzed_document_entries) { const auto entry_path = Utils::utf8_to_path(entry.full_path); CategorizedFile result{Utils::path_to_utf8(entry_path.parent_path()), entry.file_name, entry.type, "", "", 0}; result.rename_only = true; if (offer_document_renames || rename_documents_only) { const auto info_it = document_info.find(entry_key(entry)); if (info_it != document_info.end()) { result.suggested_name = info_it->second.suggested_name; } } document_results.push_back(std::move(result)); } } else if (!document_entries_for_llm.empty()) { const bool stop_before_doc_categorization = stop_requested; const bool bypass_stop = stop_before_doc_categorization && other_results.empty() && image_results.empty(); std::atomic doc_stop{false}; std::atomic& stop_flag = bypass_stop ? doc_stop : stop_analysis; auto override_provider = [&document_info, &entry_key](const FileEntry& entry) -> std::optional { const auto it = document_info.find(entry_key(entry)); if (it == document_info.end()) { return std::nullopt; } return CategorizationService::PromptOverride{it->second.prompt_name, it->second.prompt_path}; }; document_results = categorization_service.categorize_entries( document_entries_for_llm, using_local_llm, stop_flag, [this](const std::string& message) { append_progress(message); }, [this](const FileEntry& entry) { mark_progress_stage_item_in_progress(ProgressStageId::Categorization, entry); const QString type_label = entry.type == FileType::Directory ? tr("Directory") : tr("File"); append_progress(to_utf8(tr("[SORT] %1 (%2)") .arg(QString::fromStdString(entry.file_name), type_label))); }, [this](const FileEntry& entry) { mark_progress_stage_item_completed(ProgressStageId::Categorization, entry); }, [this](const CategorizedFile& entry, const std::string& reason) { notify_recategorization_reset(entry, reason); }, [this]() { return make_llm_client(); }, override_provider, suggested_name_provider); } } apply_document_dates(document_results); update_stop(); new_files_with_categories.clear(); new_files_with_categories.reserve(other_results.size() + image_results.size() + document_results.size()); new_files_with_categories.insert(new_files_with_categories.end(), other_results.begin(), other_results.end()); new_files_with_categories.insert(new_files_with_categories.end(), image_results.begin(), image_results.end()); new_files_with_categories.insert(new_files_with_categories.end(), document_results.begin(), document_results.end()); core_logger->info("Categorization produced {} new record(s).", new_files_with_categories.size()); already_categorized_files.insert( already_categorized_files.end(), new_files_with_categories.begin(), new_files_with_categories.end()); persist_analysis_results(new_files_with_categories); std::vector review_entries = already_categorized_files; if ((rename_images_only || rename_documents_only) && !pending_renames.empty()) { review_entries.insert(review_entries.end(), pending_renames.begin(), pending_renames.end()); } const auto actual_files = results_coordinator.list_directory(get_folder_path(), scan_options); new_files_to_sort = results_coordinator.compute_files_to_sort(get_folder_path(), scan_options, actual_files, review_entries, settings.get_include_subdirectories()); core_logger->debug("{} file(s) queued for sorting after analysis.", new_files_to_sort.size()); const bool cancelled = stop_requested; run_on_ui([this, cancelled]() { if (cancelled && new_files_to_sort.empty()) { handle_analysis_cancelled(); } else { handle_analysis_finished(); } }); } catch (const std::exception& ex) { core_logger->error("Exception during analysis: {}", ex.what()); const bool cancelled = stop_analysis.load() || (text_cpu_fallback_choice_.has_value() && !text_cpu_fallback_choice_.value()); if (cancelled) { run_on_ui([this]() { handle_analysis_cancelled(); }); } else { run_on_ui([this, message = std::string("Analysis error: ") + ex.what()]() { handle_analysis_failure(message); }); } } } void MainApp::run_consistency_pass() { if (stop_analysis.load() || already_categorized_files.empty()) { return; } text_cpu_fallback_choice_.reset(); auto progress_sink = [this](const std::string& message) { run_on_ui([this, message]() { if (progress_dialog) { progress_dialog->append_text(message); } }); }; consistency_pass_service.run( already_categorized_files, new_files_with_categories, [this]() { return make_llm_client(); }, stop_analysis, settings.get_category_language(), progress_sink); } void MainApp::handle_development_prompt_logging(bool checked) { if (!development_mode_) { if (development_prompt_logging_action) { QSignalBlocker blocker(development_prompt_logging_action); development_prompt_logging_action->setChecked(false); } development_prompt_logging_enabled_ = false; apply_development_logging(); return; } development_prompt_logging_enabled_ = checked; settings.set_development_prompt_logging(checked); apply_development_logging(); } void MainApp::request_stop_analysis() { stop_analysis = true; statusBar()->showMessage(tr("Cancelling analysis…"), 4000); status_is_ready_ = false; } bool MainApp::prompt_text_cpu_fallback(const std::string& reason) { if (text_cpu_fallback_choice_.has_value()) { return text_cpu_fallback_choice_.value(); } auto show_dialog = [this]() -> bool { QMessageBox box(this); box.setIcon(QMessageBox::Question); box.setWindowTitle(tr("Switch local AI to CPU?")); box.setText(tr("The local model encountered a GPU error or ran out of memory.")); box.setInformativeText(tr("Retry on CPU instead? Cancel will stop this analysis.")); box.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); box.setDefaultButton(QMessageBox::Ok); return box.exec() == QMessageBox::Ok; }; bool decision = false; if (QThread::currentThread() == thread()) { decision = show_dialog(); } else { QMetaObject::invokeMethod( this, [&decision, show_dialog]() mutable { decision = show_dialog(); }, Qt::BlockingQueuedConnection); } text_cpu_fallback_choice_ = decision; if (!decision) { stop_analysis = true; append_progress(to_utf8(tr("[WARN] GPU fallback to CPU declined. Cancelling analysis."))); run_on_ui([this]() { request_stop_analysis(); }); if (core_logger && !reason.empty()) { core_logger->warn("GPU fallback declined: {}", reason); } return false; } if (core_logger && !reason.empty()) { core_logger->warn("GPU fallback accepted: {}", reason); } return true; } void MainApp::stop_running_analysis() { stop_analysis = true; if (analyze_thread.joinable()) { analyze_thread.join(); } if (progress_dialog) { progress_dialog->hide(); progress_dialog.reset(); } } void MainApp::show_llm_selection_dialog() { try { auto dialog = std::make_unique(settings, this); if (dialog->exec() == QDialog::Accepted) { settings.set_openai_api_key(dialog->get_openai_api_key()); settings.set_openai_model(dialog->get_openai_model()); settings.set_gemini_api_key(dialog->get_gemini_api_key()); settings.set_gemini_model(dialog->get_gemini_model()); settings.set_llm_choice(dialog->get_selected_llm_choice()); settings.set_llm_downloads_expanded(dialog->get_llm_downloads_expanded()); if (dialog->get_selected_llm_choice() == LLMChoice::Custom) { settings.set_active_custom_llm_id(dialog->get_selected_custom_llm_id()); } else { settings.set_active_custom_llm_id(""); } if (dialog->get_selected_llm_choice() == LLMChoice::Remote_Custom) { settings.set_active_custom_api_id(dialog->get_selected_custom_api_id()); } else { settings.set_active_custom_api_id(""); } using_local_llm = !is_remote_choice(settings.get_llm_choice()); settings.save(); } } catch (const std::exception& ex) { show_error_dialog(fmt::format("LLM selection error: {}", ex.what())); } } void MainApp::show_suitability_benchmark_dialog(bool /*auto_start*/) { if (benchmark_dialog) { benchmark_dialog->raise(); benchmark_dialog->activateWindow(); return; } benchmark_dialog = std::make_unique(settings, this); QObject::connect(benchmark_dialog.get(), &QDialog::finished, this, [this]() { benchmark_dialog.reset(); }); benchmark_dialog->show(); } void MainApp::maybe_show_suitability_benchmark() { if (settings.get_suitability_benchmark_completed()) { return; } if (settings.get_suitability_benchmark_suppressed()) { return; } if (!default_text_llm_files_available() && !visual_llm_files_available()) { return; } QTimer::singleShot(0, this, [this]() { show_suitability_benchmark_dialog(false); }); } void MainApp::on_about_activate() { MainAppHelpActions::show_about(this); } bool MainApp::should_log_prompts() const { return development_mode_ && development_prompt_logging_enabled_; } void MainApp::apply_development_logging() { consistency_pass_service.set_prompt_logging_enabled(should_log_prompts()); } std::unique_ptr MainApp::make_llm_client() { const LLMChoice choice = settings.get_llm_choice(); if (choice == LLMChoice::Remote_OpenAI) { const std::string api_key = settings.get_openai_api_key(); const std::string model = settings.get_openai_model(); if (api_key.empty()) { throw std::runtime_error("OpenAI API key is missing. Please add it from Select LLM."); } CategorizationSession session(api_key, model); auto client = std::make_unique(session.create_llm_client()); client->set_prompt_logging_enabled(should_log_prompts()); return client; } if (choice == LLMChoice::Remote_Gemini) { const std::string api_key = settings.get_gemini_api_key(); const std::string model = settings.get_gemini_model(); if (api_key.empty()) { throw std::runtime_error("Gemini API key is missing. Please add it from Select LLM."); } auto client = std::make_unique(api_key, model); client->set_prompt_logging_enabled(should_log_prompts()); return client; } if (choice == LLMChoice::Remote_Custom) { const auto id = settings.get_active_custom_api_id(); const CustomApiEndpoint endpoint = settings.find_custom_api_endpoint(id); if (endpoint.id.empty() || endpoint.base_url.empty() || endpoint.model.empty()) { throw std::runtime_error("Selected custom API endpoint is missing or invalid. Please re-select it."); } auto client = std::make_unique(endpoint.api_key, endpoint.model, endpoint.base_url); client->set_prompt_logging_enabled(should_log_prompts()); return client; } if (choice == LLMChoice::Custom) { const auto id = settings.get_active_custom_llm_id(); const CustomLLM custom = settings.find_custom_llm(id); if (custom.id.empty() || custom.path.empty()) { throw std::runtime_error("Selected custom LLM is missing or invalid. Please re-select it."); } auto client = std::make_unique( custom.path, [this](const std::string& reason) { return prompt_text_cpu_fallback(reason); }); client->set_status_callback([this](LocalLLMClient::Status status) { if (status == LocalLLMClient::Status::GpuFallbackToCpu) { report_progress(to_utf8(tr("[WARN] GPU acceleration failed to initialize. Continuing on CPU (slower)."))); } }); client->set_prompt_logging_enabled(should_log_prompts()); return client; } const char* env_var = nullptr; switch (choice) { case LLMChoice::Local_3b: env_var = "LOCAL_LLM_3B_DOWNLOAD_URL"; break; case LLMChoice::Local_3b_legacy: env_var = "LOCAL_LLM_3B_LEGACY_DOWNLOAD_URL"; break; case LLMChoice::Local_7b: env_var = "LOCAL_LLM_7B_DOWNLOAD_URL"; break; default: break; } const char* env_url = env_var ? std::getenv(env_var) : nullptr; if (!env_url) { throw std::runtime_error("Required environment variable for selected model is not set"); } auto client = std::make_unique( Utils::make_default_path_to_file_from_download_url(env_url), [this](const std::string& reason) { return prompt_text_cpu_fallback(reason); }); client->set_status_callback([this](LocalLLMClient::Status status) { if (status == LocalLLMClient::Status::GpuFallbackToCpu) { report_progress(to_utf8(tr("[WARN] GPU acceleration failed to initialize. Continuing on CPU (slower)."))); } }); client->set_prompt_logging_enabled(should_log_prompts()); return client; } void MainApp::notify_recategorization_reset(const std::vector& entries, const std::string& reason) { if (entries.empty()) { return; } auto shared_entries = std::make_shared>(entries); auto shared_reason = std::make_shared(reason); run_on_ui([this, shared_entries, shared_reason]() { if (!progress_dialog) { return; } for (const auto& entry : *shared_entries) { const QString message = tr("[WARN] %1 will be re-categorized: %2") .arg(QString::fromStdString(entry.file_name), QString::fromStdString(*shared_reason)); progress_dialog->append_text(to_utf8(message)); } }); } void MainApp::notify_recategorization_reset(const CategorizedFile& entry, const std::string& reason) { notify_recategorization_reset(std::vector{entry}, reason); } void MainApp::show_results_dialog(const std::vector& results) { try { const bool show_subcategory = use_subcategories_checkbox->isChecked(); const std::string undo_dir = settings.get_config_dir() + "/undo"; categorization_dialog = std::make_unique(&db_manager, show_subcategory, undo_dir, settings.get_category_language(), this); categorization_dialog->show_results(results, get_folder_path(), settings.get_include_subdirectories(), settings.get_offer_rename_images(), settings.get_offer_rename_documents()); const int newly_analyzed = static_cast(std::count_if( results.begin(), results.end(), [](const CategorizedFile& file) { return !file.from_cache; })); if (newly_analyzed > 0) { record_categorized_metrics(newly_analyzed); } } catch (const std::exception& ex) { if (ui_logger) { ui_logger->error("Error showing results dialog: {}", ex.what()); } show_error_dialog(fmt::format("Failed to show results dialog: {}", ex.what())); } } void MainApp::show_error_dialog(const std::string& message) { DialogUtils::show_error_dialog(this, message); } void MainApp::report_progress(const std::string& message) { run_on_ui([this, message]() { if (progress_dialog) { progress_dialog->append_text(message); } }); } std::string MainApp::get_folder_path() const { const QByteArray bytes = path_entry->text().toUtf8(); return normalize_directory_path( std::string(bytes.constData(), static_cast(bytes.size()))); } void MainApp::run_on_ui(std::function func) { QMetaObject::invokeMethod( this, [fn = std::move(func)]() mutable { if (fn) { fn(); } }, Qt::QueuedConnection); } void MainApp::run_on_ui_blocking(std::function func) { if (QThread::currentThread() == thread()) { if (func) { func(); } return; } QMetaObject::invokeMethod( this, [fn = std::move(func)]() mutable { if (fn) { fn(); } }, Qt::BlockingQueuedConnection); } void MainApp::changeEvent(QEvent* event) { QMainWindow::changeEvent(event); if (event && event->type() == QEvent::LanguageChange) { retranslate_ui(); } } void MainApp::closeEvent(QCloseEvent* event) { stop_running_analysis(); save_settings(); QMainWindow::closeEvent(event); } ================================================ FILE: app/lib/MainAppEditActions.cpp ================================================ #include "MainAppEditActions.hpp" #include #include #include void MainAppEditActions::on_paste(QLineEdit* line_edit) { if (!line_edit) { return; } const QString clipboard_text = QGuiApplication::clipboard()->text(QClipboard::Clipboard); if (!clipboard_text.isEmpty()) { line_edit->insert(clipboard_text); } } void MainAppEditActions::on_copy(QLineEdit* line_edit) { if (!line_edit) { return; } const QString selected_text = get_selection(line_edit, false); if (!selected_text.isEmpty()) { copy_to_clipboard(selected_text); } } void MainAppEditActions::on_cut(QLineEdit* line_edit) { if (!line_edit) { return; } const QString selected_text = get_selection(line_edit, true); if (!selected_text.isEmpty()) { copy_to_clipboard(selected_text); } } void MainAppEditActions::on_delete(QLineEdit* line_edit) { if (!line_edit) { return; } get_selection(line_edit, true); } void MainAppEditActions::copy_to_clipboard(const QString& text) { QGuiApplication::clipboard()->setText(text, QClipboard::Clipboard); } QString MainAppEditActions::get_selection(QLineEdit* line_edit, bool delete_selection) { if (!line_edit) { return {}; } const QString selected_text = line_edit->selectedText(); if (selected_text.isEmpty()) { return {}; } if (delete_selection) { line_edit->insert(QString()); } return selected_text; } ================================================ FILE: app/lib/MainAppHelpActions.cpp ================================================ #include "MainAppHelpActions.hpp" #include "AppInfo.hpp" #include #include #include #include #include #include #include #include #include #include #include namespace { QString support_page_url_string() { return QStringLiteral("https://filesorter.app/donate/"); } bool open_external_url(const QUrl& url) { if (QDesktopServices::openUrl(url)) { return true; } #if defined(Q_OS_LINUX) return QProcess::startDetached(QStringLiteral("xdg-open"), {url.toString(QUrl::FullyEncoded)}); #else return false; #endif } } // namespace void MainAppHelpActions::show_about(QWidget* parent) { QDialog dialog(parent); const QString display_name = app_display_name(); dialog.setWindowTitle(QObject::tr("About %1").arg(display_name)); dialog.resize(600, 420); auto* layout = new QVBoxLayout(&dialog); auto* tabs = new QTabWidget(&dialog); layout->addWidget(tabs); // About tab auto* about_tab = new QWidget(&dialog); auto* about_layout = new QVBoxLayout(about_tab); about_layout->setSpacing(8); if (QPixmap logo_pix(QStringLiteral(":/net/quicknode/AIFileSorter/images/logo.png")); !logo_pix.isNull()) { auto* logo_label = new QLabel(about_tab); logo_label->setAlignment(Qt::AlignHCenter); logo_label->setPixmap(logo_pix.scaled(128, 128, Qt::KeepAspectRatio, Qt::SmoothTransformation)); about_layout->addWidget(logo_label); } auto* program_name = new QLabel(QStringLiteral("

%1

").arg(display_name.toHtmlEscaped()), about_tab); program_name->setAlignment(Qt::AlignHCenter); about_layout->addWidget(program_name); const QString version_text = QStringLiteral("Version: %1").arg(QString::fromStdString(APP_VERSION.to_string())); auto* version_label = new QLabel(version_text, about_tab); version_label->setAlignment(Qt::AlignHCenter); about_layout->addWidget(version_label); auto* copyright_label = new QLabel(QStringLiteral("© 2024-2026 QuickNode. All rights reserved."), about_tab); copyright_label->setAlignment(Qt::AlignHCenter); about_layout->addWidget(copyright_label); auto* website_label = new QLabel(QStringLiteral( "Visit the Website"), about_tab); website_label->setOpenExternalLinks(true); website_label->setAlignment(Qt::AlignHCenter); about_layout->addWidget(website_label); about_layout->addStretch(1); tabs->addTab(about_tab, QObject::tr("About")); // Credits tab auto* credits_tab = new QWidget(&dialog); auto* credits_layout = new QVBoxLayout(credits_tab); credits_layout->setSpacing(8); if (QPixmap qn_logo_pix(QStringLiteral(":/net/quicknode/AIFileSorter/images/qn_logo.png")); !qn_logo_pix.isNull()) { auto* qn_logo = new QLabel(credits_tab); qn_logo->setAlignment(Qt::AlignHCenter); qn_logo->setPixmap(qn_logo_pix.scaled(160, 160, Qt::KeepAspectRatio, Qt::SmoothTransformation)); credits_layout->addWidget(qn_logo); } auto* author_label = new QLabel(QStringLiteral("Author: hyperfield"), credits_tab); author_label->setAlignment(Qt::AlignHCenter); credits_layout->addWidget(author_label); auto* author_details = new QLabel(QStringLiteral( "Author's brand name is QN (QuickNode).
" "Source code on GitHub is here."), credits_tab); author_details->setOpenExternalLinks(true); author_details->setAlignment(Qt::AlignHCenter); author_details->setWordWrap(true); credits_layout->addWidget(author_details); credits_layout->addStretch(1); tabs->addTab(credits_tab, QObject::tr("Credits")); auto* button_box = new QDialogButtonBox(QDialogButtonBox::Close, &dialog); QObject::connect(button_box, &QDialogButtonBox::rejected, &dialog, &QDialog::accept); layout->addWidget(button_box); dialog.exec(); } void MainAppHelpActions::show_agpl_info(QWidget* parent) { QDialog dialog(parent); dialog.setWindowTitle(QObject::tr("About the AGPL License")); dialog.resize(520, 320); auto* layout = new QVBoxLayout(&dialog); auto* summary = new QLabel(QObject::tr( "AI File Sorter is distributed under the GNU Affero General Public License v3.0." "

" "You can access the full source code at " "github.com/hyperfield/ai-file-sorter." "

" "A full copy of the license is provided with this application and available online at " "gnu.org."), &dialog); summary->setTextFormat(Qt::RichText); summary->setOpenExternalLinks(true); summary->setWordWrap(true); layout->addWidget(summary); layout->addStretch(1); auto* button_box = new QDialogButtonBox(QDialogButtonBox::Close, &dialog); QObject::connect(button_box, &QDialogButtonBox::rejected, &dialog, &QDialog::accept); layout->addWidget(button_box); dialog.exec(); } QString MainAppHelpActions::support_page_url() { return support_page_url_string(); } bool MainAppHelpActions::open_support_page() { const QUrl donation_url(support_page_url_string()); return open_external_url(donation_url); } ================================================ FILE: app/lib/MainAppUiBuilder.cpp ================================================ #include "MainAppUiBuilder.hpp" #include "AppInfo.hpp" #include "MainApp.hpp" #include "MainAppEditActions.hpp" #include "MainAppHelpActions.hpp" #include "UiTranslator.hpp" #include "Language.hpp" #include "CategoryLanguage.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace { class DisclosureToggleButton final : public QToolButton { public: explicit DisclosureToggleButton(QWidget* parent = nullptr) : QToolButton(parent) { setCheckable(true); setToolButtonStyle(Qt::ToolButtonIconOnly); setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); setArrowType(Qt::NoArrow); setAutoRaise(true); setFixedSize(QSize(14, 14)); } protected: void paintEvent(QPaintEvent*) override { QPainter painter(this); QStyleOption option; option.initFrom(this); option.rect = rect(); option.state |= QStyle::State_Children; if (isChecked()) { option.state |= QStyle::State_Open; } style()->drawPrimitive(QStyle::PE_IndicatorBranch, &option, &painter, this); } }; using MenuIconPainter = std::function; QColor with_enabled_alpha(QColor color, bool enabled, int disabled_alpha = 110) { if (!enabled) { color.setAlpha(std::min(color.alpha(), disabled_alpha)); } return color; } QIcon draw_menu_icon(MainApp& app, const MenuIconPainter& painter_fn) { int target_size = app.style()->pixelMetric(QStyle::PM_SmallIconSize); if (target_size <= 0) { target_size = 16; } const int padding = std::max(4, target_size / 4); const QSize canvas_size(target_size + padding * 2, target_size + padding * 2); QIcon icon; for (QIcon::Mode mode : {QIcon::Normal, QIcon::Disabled}) { const bool enabled = mode != QIcon::Disabled; QPixmap canvas(canvas_size); canvas.fill(Qt::transparent); QPainter painter(&canvas); painter.setRenderHint(QPainter::Antialiasing, true); painter.setRenderHint(QPainter::TextAntialiasing, true); painter_fn(painter, QRectF(padding, padding, target_size, target_size), enabled); painter.end(); icon.addPixmap(canvas, mode); } return icon; } QPainterPath sparkle_path(const QPointF& center, qreal outer_radius, qreal inner_radius) { const qreal diagonal = inner_radius * 0.72; QPainterPath path; path.moveTo(center.x(), center.y() - outer_radius); path.lineTo(center.x() + diagonal, center.y() - diagonal); path.lineTo(center.x() + outer_radius, center.y()); path.lineTo(center.x() + diagonal, center.y() + diagonal); path.lineTo(center.x(), center.y() + outer_radius); path.lineTo(center.x() - diagonal, center.y() + diagonal); path.lineTo(center.x() - outer_radius, center.y()); path.lineTo(center.x() - diagonal, center.y() - diagonal); path.closeSubpath(); return path; } void draw_card_label(QPainter& painter, const QRectF& card_rect, const QString& text, const QColor& color, qreal size_factor) { QFont font = QApplication::font(); font.setBold(true); font.setPixelSize(std::max(7, static_cast(card_rect.height() * size_factor))); painter.setFont(font); painter.setPen(color); painter.drawText(card_rect, Qt::AlignCenter, text); } void draw_translation_cards(QPainter& painter, const QRectF& rect, bool enabled, const QColor& front_start, const QColor& front_end, const QColor& front_label, const QColor& top_start, const QColor& top_end, const QColor& top_label, const QColor& bottom_start, const QColor& bottom_end, const QColor& bottom_label) { const QRectF top_card(rect.left() + rect.width() * 0.42, rect.top() + rect.height() * 0.03, rect.width() * 0.50, rect.height() * 0.50); const QRectF bottom_card(rect.left() + rect.width() * 0.36, rect.top() + rect.height() * 0.47, rect.width() * 0.50, rect.height() * 0.50); const QRectF front_card(rect.left() + rect.width() * 0.04, rect.top() + rect.height() * 0.22, rect.width() * 0.50, rect.height() * 0.50); const auto draw_card = [&](const QRectF& card, const QColor& start, const QColor& end, const QString& label, const QColor& label_color, qreal label_size) { QLinearGradient gradient(card.topLeft(), card.bottomRight()); gradient.setColorAt(0.0, with_enabled_alpha(start, enabled)); gradient.setColorAt(1.0, with_enabled_alpha(end, enabled)); painter.setPen(Qt::NoPen); painter.setBrush(gradient); const qreal radius = std::max(2.0, card.width() * 0.16); painter.drawRoundedRect(card, radius, radius); draw_card_label(painter, card, label, with_enabled_alpha(label_color, enabled), label_size); }; draw_card(top_card, top_start, top_end, QString(QChar(0x3042)), top_label, 0.44); draw_card(bottom_card, bottom_start, bottom_end, QString(QChar(0x6587)), bottom_label, 0.40); draw_card(front_card, front_start, front_end, QStringLiteral("A"), front_label, 0.54); } QIcon llm_menu_icon(MainApp& app) { return draw_menu_icon(app, [](QPainter& painter, const QRectF& rect, bool enabled) { const QPointF main_center(rect.center().x() + rect.width() * 0.06, rect.center().y() - rect.height() * 0.02); const QPointF accent_center(rect.left() + rect.width() * 0.28, rect.top() + rect.height() * 0.28); const qreal main_outer = rect.width() * 0.27; const qreal main_inner = rect.width() * 0.12; const qreal accent_outer = rect.width() * 0.13; const qreal accent_inner = rect.width() * 0.06; QLinearGradient main_gradient(main_center.x() - main_outer, main_center.y() - main_outer, main_center.x() + main_outer, main_center.y() + main_outer); main_gradient.setColorAt(0.0, with_enabled_alpha(QColor("#ffd866"), enabled)); main_gradient.setColorAt(1.0, with_enabled_alpha(QColor("#ff6b9f"), enabled)); painter.setPen(Qt::NoPen); painter.setBrush(main_gradient); painter.drawPath(sparkle_path(main_center, main_outer, main_inner)); painter.setBrush(with_enabled_alpha(QColor("#8a7cff"), enabled)); painter.drawPath(sparkle_path(accent_center, accent_outer, accent_inner)); painter.drawEllipse(QRectF(rect.right() - rect.width() * 0.17, rect.bottom() - rect.height() * 0.19, rect.width() * 0.09, rect.width() * 0.09)); }); } QIcon interface_language_menu_icon(MainApp& app) { return draw_menu_icon(app, [](QPainter& painter, const QRectF& rect, bool enabled) { draw_translation_cards(painter, rect, enabled, QColor("#1a59c9"), QColor("#1847b7"), QColor("#d8b4fe"), QColor("#6677ff"), QColor("#5160e8"), QColor("#bcdcff"), QColor("#4fc0ff"), QColor("#37a6f5"), QColor("#dff7ff")); }); } QIcon category_language_menu_icon(MainApp& app) { return draw_menu_icon(app, [](QPainter& painter, const QRectF& rect, bool enabled) { draw_translation_cards(painter, rect, enabled, QColor("#1f2937"), QColor("#374151"), QColor("#f9fafb"), QColor("#f3f4f6"), QColor("#d7dbe3"), QColor("#1f2937"), QColor("#6b7280"), QColor("#4b5563"), QColor("#f9fafb")); }); } QPainterPath tag_path(const QRectF& rect) { QPainterPath path; path.moveTo(rect.left() + rect.width() * 0.14, rect.top() + rect.height() * 0.24); path.lineTo(rect.left() + rect.width() * 0.66, rect.top() + rect.height() * 0.24); path.lineTo(rect.right() - rect.width() * 0.06, rect.center().y()); path.lineTo(rect.left() + rect.width() * 0.66, rect.bottom() - rect.height() * 0.24); path.lineTo(rect.left() + rect.width() * 0.14, rect.bottom() - rect.height() * 0.24); path.closeSubpath(); return path; } QIcon whitelist_menu_icon(MainApp& app) { return draw_menu_icon(app, [](QPainter& painter, const QRectF& rect, bool enabled) { const QRectF rear_tag = rect.adjusted(rect.width() * 0.12, rect.height() * 0.06, -rect.width() * 0.08, -rect.height() * 0.14); const QRectF front_tag = rect.adjusted(rect.width() * 0.02, rect.height() * 0.16, -rect.width() * 0.18, -rect.height() * 0.04); painter.setPen(Qt::NoPen); painter.setBrush(with_enabled_alpha(QColor("#f472b6"), enabled, 95)); painter.drawPath(tag_path(rear_tag)); QLinearGradient gradient(front_tag.topLeft(), front_tag.bottomRight()); gradient.setColorAt(0.0, with_enabled_alpha(QColor("#ffe08a"), enabled)); gradient.setColorAt(1.0, with_enabled_alpha(QColor("#ffc857"), enabled)); painter.setBrush(gradient); painter.setPen(QPen(with_enabled_alpha(QColor("#1f2937"), enabled), 1.1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); painter.drawPath(tag_path(front_tag)); painter.save(); painter.setCompositionMode(QPainter::CompositionMode_Clear); painter.setPen(Qt::NoPen); painter.setBrush(Qt::transparent); painter.drawEllipse(QRectF(front_tag.left() + front_tag.width() * 0.12, front_tag.center().y() - front_tag.height() * 0.09, front_tag.width() * 0.13, front_tag.width() * 0.13)); painter.restore(); QPainterPath check; check.moveTo(front_tag.left() + front_tag.width() * 0.40, front_tag.center().y()); check.lineTo(front_tag.left() + front_tag.width() * 0.50, front_tag.center().y() + front_tag.height() * 0.12); check.lineTo(front_tag.left() + front_tag.width() * 0.68, front_tag.center().y() - front_tag.height() * 0.12); painter.setPen(QPen(with_enabled_alpha(QColor("#1f2937"), enabled), 1.5, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); painter.drawPath(check); }); } } // namespace void MainAppUiBuilder::build(MainApp& app) { build_central_panel(app); build_menus(app); app.analysis_in_progress_ = false; app.status_is_ready_ = true; } void MainAppUiBuilder::build_central_panel(MainApp& app) { app.setWindowTitle(app_display_name()); app.resize(1000, 800); QWidget* central = new QWidget(&app); auto* main_layout = new QVBoxLayout(central); main_layout->setContentsMargins(12, 12, 12, 12); main_layout->setSpacing(8); auto* path_layout = new QHBoxLayout(); app.path_label = new QLabel(central); app.path_entry = new QLineEdit(central); app.browse_button = new QPushButton(central); path_layout->addWidget(app.path_label); path_layout->addWidget(app.path_entry, 1); path_layout->addWidget(app.browse_button); main_layout->addLayout(path_layout); auto* options_layout = new QHBoxLayout(); app.use_subcategories_checkbox = new QCheckBox(central); app.categorize_files_checkbox = new QCheckBox(central); app.categorize_directories_checkbox = new QCheckBox(central); app.include_subdirectories_checkbox = new QCheckBox(central); app.categorize_files_checkbox->setChecked(true); options_layout->addWidget(app.use_subcategories_checkbox); options_layout->addWidget(app.categorize_files_checkbox); options_layout->addWidget(app.categorize_directories_checkbox); options_layout->addWidget(app.include_subdirectories_checkbox); options_layout->addStretch(1); main_layout->addLayout(options_layout); auto* document_options_layout = new QVBoxLayout(); document_options_layout->setContentsMargins(0, 0, 0, 0); document_options_layout->setSpacing(4); auto* document_header_layout = new QHBoxLayout(); document_header_layout->setContentsMargins(0, 0, 0, 0); document_header_layout->setSpacing(6); app.analyze_documents_checkbox = new QCheckBox(central); app.document_options_toggle_button = new DisclosureToggleButton(central); app.document_options_toggle_button->setChecked(false); document_header_layout->addWidget(app.analyze_documents_checkbox); document_header_layout->addWidget(app.document_options_toggle_button); document_header_layout->addStretch(1); document_options_layout->addLayout(document_header_layout); app.document_options_container = new QWidget(central); auto* document_rename_layout = new QVBoxLayout(app.document_options_container); document_rename_layout->setContentsMargins(24, 0, 0, 0); document_rename_layout->setSpacing(2); app.process_documents_only_checkbox = new QCheckBox(central); app.offer_rename_documents_checkbox = new QCheckBox(central); app.rename_documents_only_checkbox = new QCheckBox(central); app.add_document_date_to_category_checkbox = new QCheckBox(central); document_rename_layout->addWidget(app.process_documents_only_checkbox); document_rename_layout->addWidget(app.offer_rename_documents_checkbox); document_rename_layout->addWidget(app.rename_documents_only_checkbox); document_rename_layout->addWidget(app.add_document_date_to_category_checkbox); app.document_options_container->setVisible(false); document_options_layout->addWidget(app.document_options_container); main_layout->addLayout(document_options_layout); auto* image_options_layout = new QVBoxLayout(); image_options_layout->setContentsMargins(0, 0, 0, 0); image_options_layout->setSpacing(4); auto* image_header_layout = new QHBoxLayout(); image_header_layout->setContentsMargins(0, 0, 0, 0); image_header_layout->setSpacing(6); app.analyze_images_checkbox = new QCheckBox(central); app.image_options_toggle_button = new DisclosureToggleButton(central); app.image_options_toggle_button->setChecked(false); image_header_layout->addWidget(app.analyze_images_checkbox); image_header_layout->addWidget(app.image_options_toggle_button); image_header_layout->addStretch(1); image_options_layout->addLayout(image_header_layout); app.image_options_container = new QWidget(central); auto* image_rename_layout = new QVBoxLayout(app.image_options_container); image_rename_layout->setContentsMargins(24, 0, 0, 0); image_rename_layout->setSpacing(2); app.process_images_only_checkbox = new QCheckBox(central); app.add_image_date_to_category_checkbox = new QCheckBox(central); app.add_image_date_place_to_filename_checkbox = new QCheckBox(central); app.offer_rename_images_checkbox = new QCheckBox(central); app.rename_images_only_checkbox = new QCheckBox(central); image_rename_layout->addWidget(app.process_images_only_checkbox); image_rename_layout->addWidget(app.add_image_date_to_category_checkbox); image_rename_layout->addWidget(app.add_image_date_place_to_filename_checkbox); image_rename_layout->addWidget(app.offer_rename_images_checkbox); image_rename_layout->addWidget(app.rename_images_only_checkbox); app.image_options_container->setVisible(false); image_options_layout->addWidget(app.image_options_container); main_layout->addLayout(image_options_layout); app.add_audio_video_metadata_to_filename_checkbox = new QCheckBox(central); auto* audio_video_row = new QHBoxLayout(); audio_video_row->setContentsMargins(0, 0, 0, 0); audio_video_row->addWidget(app.add_audio_video_metadata_to_filename_checkbox); audio_video_row->addStretch(1); main_layout->addLayout(audio_video_row); app.categorization_style_heading = new QLabel(central); app.categorization_style_refined_radio = new QRadioButton(central); app.categorization_style_consistent_radio = new QRadioButton(central); app.use_whitelist_checkbox = new QCheckBox(central); app.whitelist_selector = new QComboBox(central); app.whitelist_selector->setEnabled(false); app.whitelist_selector->setMinimumContentsLength(16); app.whitelist_selector->setSizeAdjustPolicy(QComboBox::AdjustToContents); QFontMetrics fm(app.whitelist_selector->font()); app.whitelist_selector->setMinimumWidth(fm.horizontalAdvance(QString(16, QChar('W'))) + 5); app.analyze_button = new QPushButton(central); QIcon analyze_icon = QIcon::fromTheme(QStringLiteral("sparkle")); if (analyze_icon.isNull()) { analyze_icon = QIcon::fromTheme(QStringLiteral("applications-education")); } if (analyze_icon.isNull()) { analyze_icon = app.style()->standardIcon(QStyle::SP_MediaPlay); } app.analyze_button->setIcon(analyze_icon); app.analyze_button->setIconSize(QSize(20, 20)); app.analyze_button->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed); app.analyze_button->setMinimumWidth(160); auto* analyze_layout = new QHBoxLayout(); auto* categorization_layout = new QVBoxLayout(); auto* toggle_row = new QHBoxLayout(); toggle_row->addWidget(app.categorization_style_refined_radio); toggle_row->addWidget(app.categorization_style_consistent_radio); toggle_row->addStretch(); categorization_layout->addWidget(app.categorization_style_heading); categorization_layout->addLayout(toggle_row); auto* whitelist_row = new QHBoxLayout(); whitelist_row->addWidget(app.use_whitelist_checkbox); whitelist_row->addWidget(app.whitelist_selector); whitelist_row->addStretch(); auto* control_block = new QVBoxLayout(); control_block->addLayout(categorization_layout); control_block->addSpacing(4); control_block->addLayout(whitelist_row); analyze_layout->addLayout(control_block); analyze_layout->addSpacing(12); analyze_layout->addWidget(app.analyze_button, 0, Qt::AlignBottom | Qt::AlignRight); main_layout->addLayout(analyze_layout); app.tree_model = new QStandardItemModel(0, 5, &app); app.results_stack = new QStackedWidget(central); app.tree_view = new QTreeView(app.results_stack); app.tree_view->setModel(app.tree_model); app.tree_view->setSelectionBehavior(QAbstractItemView::SelectRows); app.tree_view->setEditTriggers(QAbstractItemView::NoEditTriggers); app.tree_view->header()->setSectionResizeMode(QHeaderView::Stretch); app.tree_view->setUniformRowHeights(true); app.tree_view_page_index_ = app.results_stack->addWidget(app.tree_view); app.folder_contents_model = new QFileSystemModel(app.results_stack); app.folder_contents_model->setFilter(QDir::AllEntries | QDir::NoDotAndDotDot); app.folder_contents_model->setRootPath(QDir::homePath()); app.folder_contents_view = new QTreeView(app.results_stack); app.folder_contents_view->setModel(app.folder_contents_model); app.folder_contents_view->setRootIndex(app.folder_contents_model->index(QDir::homePath())); app.folder_contents_view->setSelectionBehavior(QAbstractItemView::SelectRows); app.folder_contents_view->setEditTriggers(QAbstractItemView::NoEditTriggers); app.folder_contents_view->setRootIsDecorated(false); app.folder_contents_view->setUniformRowHeights(true); app.folder_contents_view->setSortingEnabled(true); app.folder_contents_view->sortByColumn(0, Qt::AscendingOrder); app.folder_contents_view->setAlternatingRowColors(true); app.folder_view_page_index_ = app.results_stack->addWidget(app.folder_contents_view); app.results_stack->setCurrentIndex(app.tree_view_page_index_); main_layout->addWidget(app.results_stack, 1); app.setCentralWidget(central); } UiTranslator::Dependencies MainAppUiBuilder::build_translator_dependencies(MainApp& app) const { return UiTranslator::Dependencies{ .window = app, .primary = UiTranslator::PrimaryControls{ app.path_label, app.browse_button, app.analyze_button, app.use_subcategories_checkbox, app.categorization_style_heading, app.categorization_style_refined_radio, app.categorization_style_consistent_radio, app.use_whitelist_checkbox, app.whitelist_selector, app.categorize_files_checkbox, app.categorize_directories_checkbox, app.include_subdirectories_checkbox, app.analyze_images_checkbox, app.process_images_only_checkbox, app.add_image_date_to_category_checkbox, app.add_image_date_place_to_filename_checkbox, app.add_audio_video_metadata_to_filename_checkbox, app.offer_rename_images_checkbox, app.rename_images_only_checkbox, app.image_options_toggle_button, app.analyze_documents_checkbox, app.process_documents_only_checkbox, app.offer_rename_documents_checkbox, app.rename_documents_only_checkbox, app.add_document_date_to_category_checkbox, app.document_options_toggle_button}, .tree_model = app.tree_model, .menus = UiTranslator::MenuControls{ app.file_menu, app.edit_menu, app.view_menu, app.settings_menu, app.development_menu, app.development_settings_menu, app.language_menu, app.category_language_menu, app.help_menu}, .actions = UiTranslator::ActionControls{ app.file_quit_action, app.run_benchmark_action, app.copy_action, app.cut_action, app.undo_last_run_action, app.paste_action, app.delete_action, app.toggle_explorer_action, app.toggle_llm_action, app.manage_whitelists_action, app.development_prompt_logging_action, app.consistency_pass_action, app.english_action, app.dutch_action, app.french_action, app.german_action, app.italian_action, app.spanish_action, app.turkish_action, app.korean_action, app.category_language_english, app.category_language_french, app.category_language_german, app.category_language_italian, app.category_language_dutch, app.category_language_polish, app.category_language_portuguese, app.category_language_spanish, app.category_language_turkish, app.about_action, app.about_qt_action, app.about_agpl_action, app.support_project_action}, .language = UiTranslator::LanguageControls{ app.language_group, app.english_action, app.dutch_action, app.french_action, app.german_action, app.italian_action, app.spanish_action, app.turkish_action, app.korean_action}, .category_language = UiTranslator::CategoryLanguageControls{ app.category_language_group, app.category_language_dutch, app.category_language_english, app.category_language_french, app.category_language_german, app.category_language_italian, app.category_language_polish, app.category_language_portuguese, app.category_language_spanish, app.category_language_turkish}, .file_explorer_dock = app.file_explorer_dock, .settings = app.settings, .translator = [](const char* source) { return QCoreApplication::translate("UiTranslator", source); }}; } void MainAppUiBuilder::build_menus(MainApp& app) { build_file_menu(app); build_edit_menu(app); build_view_menu(app); build_settings_menu(app); if (app.is_development_mode()) { build_development_menu(app); } build_help_menu(app); } void MainAppUiBuilder::build_file_menu(MainApp& app) { app.file_menu = app.menuBar()->addMenu(QString()); app.run_benchmark_action = app.file_menu->addAction(icon_for(app, "view-statistics", QStyle::SP_MediaPlay), QString()); QObject::connect(app.run_benchmark_action, &QAction::triggered, &app, [&app]() { app.show_suitability_benchmark_dialog(false); }); app.file_menu->addSeparator(); app.file_quit_action = app.file_menu->addAction(icon_for(app, "application-exit", QStyle::SP_DialogCloseButton), QString()); app.file_quit_action->setShortcut(QKeySequence::Quit); app.file_quit_action->setMenuRole(QAction::QuitRole); QObject::connect(app.file_quit_action, &QAction::triggered, qApp, &QApplication::quit); } void MainAppUiBuilder::build_edit_menu(MainApp& app) { app.edit_menu = app.menuBar()->addMenu(QString()); app.undo_last_run_action = app.edit_menu->addAction(icon_for(app, "edit-undo", QStyle::SP_ArrowBack), QString()); QObject::connect(app.undo_last_run_action, &QAction::triggered, &app, &MainApp::undo_last_run); app.copy_action = app.edit_menu->addAction(icon_for(app, "edit-copy", QStyle::SP_FileDialogContentsView), QString()); QObject::connect(app.copy_action, &QAction::triggered, &app, [&app]() { MainAppEditActions::on_copy(app.path_entry); }); app.copy_action->setShortcut(QKeySequence::Copy); app.cut_action = app.edit_menu->addAction(icon_for(app, "edit-cut", QStyle::SP_FileDialogDetailedView), QString()); QObject::connect(app.cut_action, &QAction::triggered, &app, [&app]() { MainAppEditActions::on_cut(app.path_entry); }); app.cut_action->setShortcut(QKeySequence::Cut); app.paste_action = app.edit_menu->addAction(icon_for(app, "edit-paste", QStyle::SP_FileDialogListView), QString()); QObject::connect(app.paste_action, &QAction::triggered, &app, [&app]() { MainAppEditActions::on_paste(app.path_entry); }); app.paste_action->setShortcut(QKeySequence::Paste); app.delete_action = app.edit_menu->addAction(icon_for(app, "edit-delete", QStyle::SP_TrashIcon), QString()); QObject::connect(app.delete_action, &QAction::triggered, &app, [&app]() { MainAppEditActions::on_delete(app.path_entry); }); app.delete_action->setShortcut(QKeySequence::Delete); } void MainAppUiBuilder::build_view_menu(MainApp& app) { app.view_menu = app.menuBar()->addMenu(QString()); app.toggle_explorer_action = app.view_menu->addAction(icon_for(app, "system-file-manager", QStyle::SP_DirOpenIcon), QString()); app.toggle_explorer_action->setCheckable(true); app.toggle_explorer_action->setChecked(app.settings.get_show_file_explorer()); QObject::connect(app.toggle_explorer_action, &QAction::toggled, &app, [&app](bool checked) { if (app.file_explorer_dock) { app.file_explorer_dock->setVisible(checked); } app.settings.set_show_file_explorer(checked); app.update_results_view_mode(); }); app.file_explorer_menu_action = app.toggle_explorer_action; } void MainAppUiBuilder::build_settings_menu(MainApp& app) { app.settings_menu = app.menuBar()->addMenu(QString()); app.toggle_llm_action = app.settings_menu->addAction(llm_menu_icon(app), QString()); QObject::connect(app.toggle_llm_action, &QAction::triggered, &app, &MainApp::show_llm_selection_dialog); app.manage_whitelists_action = app.settings_menu->addAction(whitelist_menu_icon(app), QString()); QObject::connect(app.manage_whitelists_action, &QAction::triggered, &app, &MainApp::show_whitelist_manager); app.language_menu = app.settings_menu->addMenu(QString()); app.language_menu->setIcon(interface_language_menu_icon(app)); if (app.language_menu->menuAction()) { app.language_menu->menuAction()->setIcon(interface_language_menu_icon(app)); } app.language_group = new QActionGroup(&app); app.language_group->setExclusive(true); app.dutch_action = app.language_menu->addAction(QString()); app.dutch_action->setCheckable(true); app.dutch_action->setData(static_cast(Language::Dutch)); app.language_group->addAction(app.dutch_action); app.english_action = app.language_menu->addAction(QString()); app.english_action->setCheckable(true); app.english_action->setData(static_cast(Language::English)); app.language_group->addAction(app.english_action); app.french_action = app.language_menu->addAction(QString()); app.french_action->setCheckable(true); app.french_action->setData(static_cast(Language::French)); app.language_group->addAction(app.french_action); app.german_action = app.language_menu->addAction(QString()); app.german_action->setCheckable(true); app.german_action->setData(static_cast(Language::German)); app.language_group->addAction(app.german_action); app.italian_action = app.language_menu->addAction(QString()); app.italian_action->setCheckable(true); app.italian_action->setData(static_cast(Language::Italian)); app.language_group->addAction(app.italian_action); app.korean_action = app.language_menu->addAction(QString()); app.korean_action->setCheckable(true); app.korean_action->setData(static_cast(Language::Korean)); app.language_group->addAction(app.korean_action); app.spanish_action = app.language_menu->addAction(QString()); app.spanish_action->setCheckable(true); app.spanish_action->setData(static_cast(Language::Spanish)); app.language_group->addAction(app.spanish_action); app.turkish_action = app.language_menu->addAction(QString()); app.turkish_action->setCheckable(true); app.turkish_action->setData(static_cast(Language::Turkish)); app.language_group->addAction(app.turkish_action); QObject::connect(app.language_group, &QActionGroup::triggered, &app, [&app](QAction* action) { if (!action) { return; } const Language chosen = static_cast(action->data().toInt()); app.on_language_selected(chosen); }); app.category_language_menu = app.settings_menu->addMenu(QString()); app.category_language_menu->setIcon(category_language_menu_icon(app)); if (app.category_language_menu->menuAction()) { app.category_language_menu->menuAction()->setIcon(category_language_menu_icon(app)); } app.category_language_group = new QActionGroup(&app); app.category_language_group->setExclusive(true); const auto add_cat_lang = [&](CategoryLanguage lang) { QAction* act = app.category_language_menu->addAction(QString()); act->setCheckable(true); act->setData(static_cast(lang)); app.category_language_group->addAction(act); return act; }; app.category_language_dutch = add_cat_lang(CategoryLanguage::Dutch); app.category_language_english = add_cat_lang(CategoryLanguage::English); app.category_language_french = add_cat_lang(CategoryLanguage::French); app.category_language_german = add_cat_lang(CategoryLanguage::German); app.category_language_italian = add_cat_lang(CategoryLanguage::Italian); app.category_language_polish = add_cat_lang(CategoryLanguage::Polish); app.category_language_portuguese = add_cat_lang(CategoryLanguage::Portuguese); app.category_language_spanish = add_cat_lang(CategoryLanguage::Spanish); app.category_language_turkish = add_cat_lang(CategoryLanguage::Turkish); QObject::connect(app.category_language_group, &QActionGroup::triggered, &app, [&app](QAction* action) { if (!action) { return; } const CategoryLanguage chosen = static_cast(action->data().toInt()); app.on_category_language_selected(chosen); }); } void MainAppUiBuilder::build_development_menu(MainApp& app) { app.development_menu = app.menuBar()->addMenu(QString()); app.development_settings_menu = app.development_menu->addMenu(QString()); app.development_prompt_logging_action = app.development_settings_menu->addAction(QString()); app.development_prompt_logging_action->setCheckable(true); app.development_prompt_logging_action->setChecked(app.development_prompt_logging_enabled_); QObject::connect(app.development_prompt_logging_action, &QAction::toggled, &app, &MainApp::handle_development_prompt_logging); } void MainAppUiBuilder::build_help_menu(MainApp& app) { app.help_menu = app.menuBar()->addMenu(QString()); if (app.help_menu && app.help_menu->menuAction()) { app.help_menu->menuAction()->setMenuRole(QAction::ApplicationSpecificRole); } app.about_action = app.help_menu->addAction(icon_for(app, "help-about", QStyle::SP_MessageBoxInformation), QString()); app.about_action->setMenuRole(QAction::NoRole); QObject::connect(app.about_action, &QAction::triggered, &app, &MainApp::on_about_activate); app.about_qt_action = app.help_menu->addAction(icon_for(app, "help-about", QStyle::SP_MessageBoxInformation), QString()); app.about_qt_action->setMenuRole(QAction::NoRole); QObject::connect(app.about_qt_action, &QAction::triggered, &app, [&app]() { QMessageBox::aboutQt(&app); }); app.about_agpl_action = app.help_menu->addAction(icon_for(app, "help-about", QStyle::SP_MessageBoxInformation), QString()); app.about_agpl_action->setMenuRole(QAction::NoRole); QObject::connect(app.about_agpl_action, &QAction::triggered, &app, [&app]() { MainAppHelpActions::show_agpl_info(&app); }); #ifdef _WIN32 app.support_project_action = nullptr; #else app.support_project_action = app.help_menu->addAction(icon_for(app, "help-donate", QStyle::SP_DialogHelpButton), QString()); app.support_project_action->setMenuRole(QAction::NoRole); QObject::connect(app.support_project_action, &QAction::triggered, &app, []() { MainAppHelpActions::open_support_page(); }); #endif } QIcon MainAppUiBuilder::icon_for(MainApp& app, const char* name, QStyle::StandardPixmap fallback) { QIcon icon = QIcon::fromTheme(QString::fromLatin1(name)); if (icon.isNull()) { icon = app.style()->standardIcon(fallback); } if (!icon.isNull()) { const int targetSize = app.style()->pixelMetric(QStyle::PM_SmallIconSize); if (targetSize > 0) { QPixmap pixmap = icon.pixmap(targetSize, targetSize); if (!pixmap.isNull()) { const int padding = std::max(4, targetSize / 4); const QSize paddedSize(pixmap.width() + padding * 2, pixmap.height() + padding * 2); QPixmap padded(paddedSize); padded.fill(Qt::transparent); QPainter painter(&padded); painter.drawPixmap(padding, padding, pixmap); painter.end(); QIcon paddedIcon; paddedIcon.addPixmap(padded, QIcon::Normal); paddedIcon.addPixmap(padded, QIcon::Disabled); icon = paddedIcon; } } } return icon; } ================================================ FILE: app/lib/MediaRenameMetadataService.cpp ================================================ #include "MediaRenameMetadataService.hpp" #include "Utils.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #ifdef AI_FILE_SORTER_USE_MEDIAINFOLIB #if defined(__APPLE__) && !defined(UNICODE) && !defined(_UNICODE) // Homebrew's MediaInfoLib is built with the wide-character API enabled. #define UNICODE #define _UNICODE #endif #if defined(_WIN32) #include namespace MediaInfoCompat = MediaInfoDLL; #else #include namespace MediaInfoCompat = MediaInfoLib; #endif #if defined(UNICODE) || defined(_UNICODE) #include #endif #endif namespace { std::string trim_copy(std::string value) { const char* whitespace = " \t\n\r\f\v"; const auto start = value.find_first_not_of(whitespace); if (start == std::string::npos) { return std::string(); } const auto end = value.find_last_not_of(whitespace); return value.substr(start, end - start + 1); } std::string to_lower_copy(std::string value) { std::transform(value.begin(), value.end(), value.begin(), [](unsigned char ch) { return static_cast(std::tolower(ch)); }); return value; } const std::unordered_set& audio_extensions() { static const std::unordered_set extensions = { ".aac", ".aif", ".aiff", ".alac", ".ape", ".flac", ".m4a", ".mp3", ".ogg", ".oga", ".opus", ".wav", ".wma" }; return extensions; } const std::unordered_set& video_extensions() { static const std::unordered_set extensions = { ".3gp", ".avi", ".flv", ".m4v", ".mkv", ".mov", ".mp4", ".mpeg", ".mpg", ".mts", ".m2ts", ".ts", ".webm", ".wmv" }; return extensions; } bool is_supported_audio(const std::filesystem::path& path) { if (!path.has_extension()) { return false; } const std::string ext = to_lower_copy(Utils::path_to_utf8(path.extension())); return audio_extensions().contains(ext); } bool is_supported_video(const std::filesystem::path& path) { if (!path.has_extension()) { return false; } const std::string ext = to_lower_copy(Utils::path_to_utf8(path.extension())); return video_extensions().contains(ext); } bool has_metadata_parts(const MediaRenameMetadataService::MetadataFields& metadata) { return metadata.year.has_value() || metadata.artist.has_value() || metadata.album.has_value() || metadata.title.has_value(); } #ifndef AI_FILE_SORTER_USE_MEDIAINFOLIB constexpr std::size_t kMaxId3TagSizeBytes = 2U * 1024U * 1024U; bool read_exact(std::istream& input, char* destination, std::size_t size) { if (size == 0) { return true; } input.read(destination, static_cast(size)); return input.gcount() == static_cast(size); } std::uint32_t read_u32_be(const std::uint8_t* bytes) { return (static_cast(bytes[0]) << 24) | (static_cast(bytes[1]) << 16) | (static_cast(bytes[2]) << 8) | static_cast(bytes[3]); } std::uint32_t read_u32_le(const std::uint8_t* bytes) { return static_cast(bytes[0]) | (static_cast(bytes[1]) << 8) | (static_cast(bytes[2]) << 16) | (static_cast(bytes[3]) << 24); } std::uint32_t read_u24_be(const std::uint8_t* bytes) { return (static_cast(bytes[0]) << 16) | (static_cast(bytes[1]) << 8) | static_cast(bytes[2]); } std::uint64_t read_u64_be(const std::uint8_t* bytes) { return (static_cast(bytes[0]) << 56) | (static_cast(bytes[1]) << 48) | (static_cast(bytes[2]) << 40) | (static_cast(bytes[3]) << 32) | (static_cast(bytes[4]) << 24) | (static_cast(bytes[5]) << 16) | (static_cast(bytes[6]) << 8) | static_cast(bytes[7]); } std::uint32_t read_synchsafe_u32(const std::uint8_t* bytes) { return (static_cast(bytes[0] & 0x7F) << 21) | (static_cast(bytes[1] & 0x7F) << 14) | (static_cast(bytes[2] & 0x7F) << 7) | static_cast(bytes[3] & 0x7F); } std::string sanitize_metadata_value(std::string value) { std::string sanitized; sanitized.reserve(value.size()); for (unsigned char ch : value) { if (ch == '\0') { continue; } if (std::iscntrl(ch)) { sanitized.push_back(' '); continue; } sanitized.push_back(static_cast(ch)); } return trim_copy(sanitized); } void assign_if_missing(std::optional& target, const std::optional& candidate) { if (!target.has_value() && candidate.has_value() && !candidate->empty()) { target = candidate; } } void assign_vorbis_comment_field(const std::string& key, const std::string& value, MediaRenameMetadataService::MetadataFields& metadata) { if (value.empty()) { return; } const std::string lowered_key = to_lower_copy(key); if (lowered_key == "title") { assign_if_missing(metadata.title, sanitize_metadata_value(value)); return; } if (lowered_key == "artist" || lowered_key == "albumartist" || lowered_key == "album artist") { assign_if_missing(metadata.artist, sanitize_metadata_value(value)); return; } if (lowered_key == "album") { assign_if_missing(metadata.album, sanitize_metadata_value(value)); return; } if (lowered_key == "date" || lowered_key == "year" || lowered_key == "originaldate") { assign_if_missing(metadata.year, sanitize_metadata_value(value)); } } std::optional decode_id3_text_frame(const std::uint8_t* bytes, std::size_t size) { if (bytes == nullptr || size <= 1) { return std::nullopt; } const std::uint8_t encoding = bytes[0]; const std::uint8_t* payload = bytes + 1; const std::size_t payload_size = size - 1; std::string decoded; if (encoding == 0 || encoding == 3) { decoded.assign(reinterpret_cast(payload), payload_size); } else if (encoding == 1 || encoding == 2) { bool little_endian = (encoding == 1); std::size_t offset = 0; if (encoding == 1 && payload_size >= 2) { if (payload[0] == 0xFF && payload[1] == 0xFE) { little_endian = true; offset = 2; } else if (payload[0] == 0xFE && payload[1] == 0xFF) { little_endian = false; offset = 2; } } decoded.reserve(payload_size / 2); for (std::size_t index = offset; index + 1 < payload_size; index += 2) { const std::uint16_t code_unit = little_endian ? static_cast(payload[index]) | (static_cast(payload[index + 1]) << 8) : (static_cast(payload[index]) << 8) | static_cast(payload[index + 1]); if (code_unit == 0) { break; } if (code_unit <= 0x7F) { decoded.push_back(static_cast(code_unit)); } else { decoded.push_back(' '); } } } else { return std::nullopt; } if (const auto null_index = decoded.find('\0'); null_index != std::string::npos) { decoded.resize(null_index); } decoded = sanitize_metadata_value(decoded); if (decoded.empty()) { return std::nullopt; } return decoded; } std::vector remove_unsynchronization(const std::vector& input) { std::vector decoded; decoded.reserve(input.size()); for (std::size_t index = 0; index < input.size(); ++index) { const std::uint8_t byte = input[index]; if (byte == 0xFF && index + 1 < input.size() && input[index + 1] == 0x00) { decoded.push_back(0xFF); ++index; continue; } decoded.push_back(byte); } return decoded; } bool parse_vorbis_comment_payload(const std::uint8_t* bytes, std::size_t size, MediaRenameMetadataService::MetadataFields& metadata) { if (bytes == nullptr || size < 8) { return false; } std::size_t offset = 0; const auto read_u32 = [&](std::uint32_t& value) -> bool { if (offset + 4 > size) { return false; } value = read_u32_le(bytes + offset); offset += 4; return true; }; std::uint32_t vendor_length = 0; if (!read_u32(vendor_length) || offset + vendor_length > size) { return false; } offset += vendor_length; std::uint32_t comment_count = 0; if (!read_u32(comment_count)) { return false; } for (std::uint32_t index = 0; index < comment_count; ++index) { std::uint32_t comment_length = 0; if (!read_u32(comment_length) || offset + comment_length > size) { return false; } const std::string entry(reinterpret_cast(bytes + offset), comment_length); offset += comment_length; const auto separator_index = entry.find('='); if (separator_index == std::string::npos || separator_index == 0 || separator_index + 1 >= entry.size()) { continue; } const std::string key = trim_copy(entry.substr(0, separator_index)); const std::string value = entry.substr(separator_index + 1); assign_vorbis_comment_field(key, value, metadata); } return has_metadata_parts(metadata); } bool parse_id3v2_frames(const std::vector& tag_data, int id3_major_version, std::uint8_t id3_flags, MediaRenameMetadataService::MetadataFields& metadata) { if (id3_major_version < 2 || id3_major_version > 4 || tag_data.empty()) { return false; } std::vector data = tag_data; if ((id3_flags & 0x80) != 0) { data = remove_unsynchronization(data); } std::size_t offset = 0; if ((id3_flags & 0x40) != 0) { if (data.size() < 4) { return false; } if (id3_major_version == 3) { const std::size_t ext_size = read_u32_be(data.data()); if (ext_size + 4 > data.size()) { return false; } offset = ext_size + 4; } else if (id3_major_version == 4) { const std::size_t ext_size = read_synchsafe_u32(data.data()); if (ext_size > data.size()) { return false; } offset = ext_size; } } auto apply_frame = [&](const std::string& frame_id, const std::optional& value) { if (!value.has_value()) { return; } if (frame_id == "TIT2" || frame_id == "TT2") { assign_if_missing(metadata.title, *value); return; } if (frame_id == "TPE1" || frame_id == "TP1" || frame_id == "TPE2" || frame_id == "TP2") { assign_if_missing(metadata.artist, *value); return; } if (frame_id == "TALB" || frame_id == "TAL") { assign_if_missing(metadata.album, *value); return; } if (frame_id == "TDRC" || frame_id == "TYER" || frame_id == "TYE" || frame_id == "TDOR" || frame_id == "TDRL") { assign_if_missing(metadata.year, *value); } }; while (offset < data.size()) { std::string frame_id; std::size_t frame_size = 0; std::size_t frame_header_size = 0; if (id3_major_version == 2) { if (offset + 6 > data.size()) { break; } const std::uint8_t* frame_header = data.data() + offset; if (frame_header[0] == 0 && frame_header[1] == 0 && frame_header[2] == 0) { break; } frame_id.assign(reinterpret_cast(frame_header), 3); frame_size = read_u24_be(frame_header + 3); frame_header_size = 6; } else { if (offset + 10 > data.size()) { break; } const std::uint8_t* frame_header = data.data() + offset; if (frame_header[0] == 0 && frame_header[1] == 0 && frame_header[2] == 0 && frame_header[3] == 0) { break; } frame_id.assign(reinterpret_cast(frame_header), 4); frame_size = id3_major_version == 4 ? read_synchsafe_u32(frame_header + 4) : read_u32_be(frame_header + 4); frame_header_size = 10; } if (frame_size == 0 || offset + frame_header_size + frame_size > data.size()) { break; } const std::uint8_t* frame_body = data.data() + offset + frame_header_size; apply_frame(frame_id, decode_id3_text_frame(frame_body, frame_size)); offset += frame_header_size + frame_size; } return has_metadata_parts(metadata); } bool parse_id3v2_from_file(const std::filesystem::path& media_path, MediaRenameMetadataService::MetadataFields& metadata) { std::ifstream input(media_path, std::ios::binary); if (!input) { return false; } std::uint8_t header[10] = {}; if (!read_exact(input, reinterpret_cast(header), sizeof(header))) { return false; } if (std::memcmp(header, "ID3", 3) != 0) { return false; } const int id3_major_version = static_cast(header[3]); if (id3_major_version < 2 || id3_major_version > 4) { return false; } const std::uint32_t tag_size = read_synchsafe_u32(header + 6); if (tag_size == 0 || tag_size > kMaxId3TagSizeBytes) { return false; } std::vector tag_data(tag_size); if (!read_exact(input, reinterpret_cast(tag_data.data()), tag_data.size())) { return false; } return parse_id3v2_frames(tag_data, id3_major_version, header[5], metadata); } bool parse_id3v1_from_file(const std::filesystem::path& media_path, MediaRenameMetadataService::MetadataFields& metadata) { std::ifstream input(media_path, std::ios::binary); if (!input) { return false; } input.seekg(0, std::ios::end); const std::streamoff file_size = input.tellg(); if (file_size < 128) { return false; } input.seekg(-128, std::ios::end); std::array tag{}; if (!read_exact(input, tag.data(), tag.size())) { return false; } if (std::memcmp(tag.data(), "TAG", 3) != 0) { return false; } const auto read_field = [&](std::size_t offset, std::size_t length) -> std::optional { std::string value(tag.data() + offset, length); while (!value.empty() && (value.back() == '\0' || std::isspace(static_cast(value.back())))) { value.pop_back(); } value = sanitize_metadata_value(value); if (value.empty()) { return std::nullopt; } return value; }; assign_if_missing(metadata.title, read_field(3, 30)); assign_if_missing(metadata.artist, read_field(33, 30)); assign_if_missing(metadata.album, read_field(63, 30)); assign_if_missing(metadata.year, read_field(93, 4)); return has_metadata_parts(metadata); } bool parse_flac_vorbis_comments(const std::filesystem::path& media_path, MediaRenameMetadataService::MetadataFields& metadata) { std::ifstream input(media_path, std::ios::binary); if (!input) { return false; } std::array signature{}; if (!read_exact(input, signature.data(), signature.size()) || std::memcmp(signature.data(), "fLaC", 4) != 0) { return false; } bool is_last_block = false; while (!is_last_block && input.good()) { std::uint8_t block_header[4] = {}; if (!read_exact(input, reinterpret_cast(block_header), sizeof(block_header))) { return false; } is_last_block = (block_header[0] & 0x80U) != 0; const std::uint8_t block_type = static_cast(block_header[0] & 0x7FU); const std::uint32_t block_length = read_u24_be(block_header + 1); if (block_type == 4) { std::vector block(block_length); if (!read_exact(input, reinterpret_cast(block.data()), block.size())) { return false; } parse_vorbis_comment_payload(block.data(), block.size(), metadata); } else { input.seekg(static_cast(block_length), std::ios::cur); if (!input.good()) { return false; } } } return has_metadata_parts(metadata); } bool parse_ogg_comments(const std::filesystem::path& media_path, MediaRenameMetadataService::MetadataFields& metadata) { std::ifstream input(media_path, std::ios::binary); if (!input) { return false; } enum class OggCodec { Unknown, Vorbis, Opus }; OggCodec codec = OggCodec::Unknown; std::vector packet; std::size_t packet_index = 0; while (input.good()) { std::uint8_t page_header[27] = {}; if (!read_exact(input, reinterpret_cast(page_header), sizeof(page_header))) { break; } if (std::memcmp(page_header, "OggS", 4) != 0 || page_header[4] != 0) { return false; } const std::uint8_t segment_count = page_header[26]; std::vector segment_table(segment_count); if (segment_count > 0 && !read_exact(input, reinterpret_cast(segment_table.data()), segment_table.size())) { return false; } std::size_t body_size = 0; for (const std::uint8_t segment : segment_table) { body_size += segment; } std::vector body(body_size); if (body_size > 0 && !read_exact(input, reinterpret_cast(body.data()), body.size())) { return false; } std::size_t body_offset = 0; for (const std::uint8_t segment : segment_table) { packet.insert(packet.end(), body.begin() + static_cast(body_offset), body.begin() + static_cast(body_offset + segment)); body_offset += segment; if (segment == 255) { continue; } if (packet_index == 0) { if (packet.size() >= 7 && packet[0] == 0x01 && std::memcmp(packet.data() + 1, "vorbis", 6) == 0) { codec = OggCodec::Vorbis; } else if (packet.size() >= 8 && std::memcmp(packet.data(), "OpusHead", 8) == 0) { codec = OggCodec::Opus; } else { return false; } } else if (packet_index == 1) { if (codec == OggCodec::Vorbis && packet.size() >= 7 && packet[0] == 0x03 && std::memcmp(packet.data() + 1, "vorbis", 6) == 0) { return parse_vorbis_comment_payload(packet.data() + 7, packet.size() - 7, metadata); } if (codec == OggCodec::Opus && packet.size() >= 8 && std::memcmp(packet.data(), "OpusTags", 8) == 0) { return parse_vorbis_comment_payload(packet.data() + 8, packet.size() - 8, metadata); } return false; } packet.clear(); ++packet_index; } } return has_metadata_parts(metadata); } constexpr std::uint32_t make_fourcc(std::uint8_t c0, std::uint8_t c1, std::uint8_t c2, std::uint8_t c3) { return (static_cast(c0) << 24) | (static_cast(c1) << 16) | (static_cast(c2) << 8) | static_cast(c3); } constexpr std::uint32_t kAtomMoov = make_fourcc('m', 'o', 'o', 'v'); constexpr std::uint32_t kAtomUdta = make_fourcc('u', 'd', 't', 'a'); constexpr std::uint32_t kAtomMeta = make_fourcc('m', 'e', 't', 'a'); constexpr std::uint32_t kAtomIlst = make_fourcc('i', 'l', 's', 't'); constexpr std::uint32_t kAtomData = make_fourcc('d', 'a', 't', 'a'); constexpr std::uint32_t kAtomTrak = make_fourcc('t', 'r', 'a', 'k'); constexpr std::uint32_t kAtomMdia = make_fourcc('m', 'd', 'i', 'a'); constexpr std::uint32_t kAtomMinf = make_fourcc('m', 'i', 'n', 'f'); constexpr std::uint32_t kAtomStbl = make_fourcc('s', 't', 'b', 'l'); constexpr std::uint32_t kAtomEdts = make_fourcc('e', 'd', 't', 's'); constexpr std::uint32_t kAtomDinf = make_fourcc('d', 'i', 'n', 'f'); constexpr std::uint32_t kAtomMvex = make_fourcc('m', 'v', 'e', 'x'); constexpr std::uint32_t kTagName = make_fourcc(0xA9, 'n', 'a', 'm'); constexpr std::uint32_t kTagArtist = make_fourcc(0xA9, 'A', 'R', 'T'); constexpr std::uint32_t kTagAlbumArtist = make_fourcc('a', 'A', 'R', 'T'); constexpr std::uint32_t kTagAlbum = make_fourcc(0xA9, 'a', 'l', 'b'); constexpr std::uint32_t kTagDate = make_fourcc(0xA9, 'd', 'a', 'y'); constexpr std::uint32_t kTagTitle3gp = make_fourcc('t', 'i', 't', 'l'); constexpr std::uint32_t kTagArtist3gp = make_fourcc('a', 'u', 't', 'h'); constexpr std::uint32_t kTagAlbum3gp = make_fourcc('a', 'l', 'b', 'm'); constexpr std::uint32_t kTagYear3gp = make_fourcc('y', 'r', 'r', 'c'); bool seek_to(std::istream& input, std::uint64_t offset) { constexpr std::uint64_t kMaxStreamOff = static_cast(std::numeric_limits::max()); if (offset > kMaxStreamOff) { return false; } input.clear(); input.seekg(static_cast(offset), std::ios::beg); return input.good(); } bool read_at(std::istream& input, std::uint64_t offset, std::uint8_t* destination, std::size_t size) { if (destination == nullptr || size == 0) { return true; } if (!seek_to(input, offset)) { return false; } return read_exact(input, reinterpret_cast(destination), size); } bool is_mp4_container_atom(std::uint32_t atom_type) { return atom_type == kAtomMoov || atom_type == kAtomUdta || atom_type == kAtomMeta || atom_type == kAtomIlst || atom_type == kAtomTrak || atom_type == kAtomMdia || atom_type == kAtomMinf || atom_type == kAtomStbl || atom_type == kAtomEdts || atom_type == kAtomDinf || atom_type == kAtomMvex; } bool is_mp4_metadata_key_atom(std::uint32_t atom_type) { return atom_type == kTagName || atom_type == kTagArtist || atom_type == kTagAlbumArtist || atom_type == kTagAlbum || atom_type == kTagDate || atom_type == kTagTitle3gp || atom_type == kTagArtist3gp || atom_type == kTagAlbum3gp || atom_type == kTagYear3gp; } std::string decode_utf16_ascii_fallback(const std::uint8_t* bytes, std::size_t size) { if (bytes == nullptr || size < 2) { return std::string(); } bool little_endian = false; std::size_t offset = 0; if (size >= 2) { if (bytes[0] == 0xFF && bytes[1] == 0xFE) { little_endian = true; offset = 2; } else if (bytes[0] == 0xFE && bytes[1] == 0xFF) { little_endian = false; offset = 2; } } std::string decoded; decoded.reserve(size / 2); for (std::size_t index = offset; index + 1 < size; index += 2) { const std::uint16_t code_unit = little_endian ? static_cast(bytes[index]) | (static_cast(bytes[index + 1]) << 8) : (static_cast(bytes[index]) << 8) | static_cast(bytes[index + 1]); if (code_unit == 0) { break; } if (code_unit <= 0x7F) { decoded.push_back(static_cast(code_unit)); } else { decoded.push_back(' '); } } return sanitize_metadata_value(decoded); } std::optional parse_mp4_data_text(const std::vector& payload) { if (payload.size() < 8) { return std::nullopt; } const std::uint32_t marker_a = read_u32_be(payload.data()); const std::uint32_t marker_b = read_u32_be(payload.data() + 4); std::uint32_t data_type = marker_a; if ((marker_a == 0 || marker_a > 32) && (marker_b == 1 || marker_b == 2 || marker_b == 0 || marker_b == 21)) { data_type = marker_b; } const std::uint8_t* text_bytes = payload.data() + 8; const std::size_t text_size = payload.size() - 8; if (text_size == 0) { return std::nullopt; } std::string decoded; if (data_type == 2) { decoded = decode_utf16_ascii_fallback(text_bytes, text_size); } else { decoded.assign(reinterpret_cast(text_bytes), text_size); if (const auto null_index = decoded.find('\0'); null_index != std::string::npos) { decoded.resize(null_index); } decoded = sanitize_metadata_value(decoded); } if (decoded.empty()) { return std::nullopt; } return decoded; } void assign_mp4_metadata_field(std::uint32_t atom_type, const std::string& value, MediaRenameMetadataService::MetadataFields& metadata) { if (value.empty()) { return; } if (atom_type == kTagName || atom_type == kTagTitle3gp) { assign_if_missing(metadata.title, value); return; } if (atom_type == kTagArtist || atom_type == kTagAlbumArtist || atom_type == kTagArtist3gp) { assign_if_missing(metadata.artist, value); return; } if (atom_type == kTagAlbum || atom_type == kTagAlbum3gp) { assign_if_missing(metadata.album, value); return; } if (atom_type == kTagDate || atom_type == kTagYear3gp) { assign_if_missing(metadata.year, value); } } void parse_mp4_atoms(std::istream& input, std::uint64_t range_start, std::uint64_t range_end, std::optional current_tag, std::size_t depth, MediaRenameMetadataService::MetadataFields& metadata) { if (depth > 12 || range_start >= range_end) { return; } std::uint64_t offset = range_start; while (offset + 8 <= range_end) { std::uint8_t header[16] = {}; if (!read_at(input, offset, header, 8)) { return; } std::uint64_t atom_size = read_u32_be(header); const std::uint32_t atom_type = read_u32_be(header + 4); std::uint64_t atom_header_size = 8; if (atom_size == 1) { if (!read_at(input, offset + 8, header + 8, 8)) { return; } atom_size = read_u64_be(header + 8); atom_header_size = 16; } else if (atom_size == 0) { atom_size = range_end - offset; } if (atom_size < atom_header_size) { return; } const std::uint64_t atom_end = offset + atom_size; if (atom_end < offset || atom_end > range_end) { return; } std::uint64_t payload_start = offset + atom_header_size; const std::uint64_t payload_end = atom_end; if (atom_type == kAtomMeta) { if (payload_start + 4 > payload_end) { offset = atom_end; continue; } payload_start += 4; } if (atom_type == kAtomData && current_tag.has_value()) { const std::uint64_t payload_size = payload_end - payload_start; if (payload_size >= 8 && payload_size <= 64 * 1024) { std::vector data(static_cast(payload_size)); if (read_at(input, payload_start, data.data(), data.size())) { if (const auto text = parse_mp4_data_text(data)) { assign_mp4_metadata_field(*current_tag, *text, metadata); } } } } bool descend = false; std::optional next_tag = current_tag; if (is_mp4_metadata_key_atom(atom_type)) { descend = true; next_tag = atom_type; } else if (is_mp4_container_atom(atom_type)) { descend = true; if (atom_type == kAtomIlst) { next_tag.reset(); } } else if (current_tag.has_value() && atom_type != kAtomData) { descend = true; } if (descend && payload_start < payload_end) { parse_mp4_atoms(input, payload_start, payload_end, next_tag, depth + 1, metadata); } if (atom_size == 0) { return; } offset = atom_end; } } bool parse_mp4_style_metadata(const std::filesystem::path& media_path, MediaRenameMetadataService::MetadataFields& metadata) { std::ifstream input(media_path, std::ios::binary); if (!input) { return false; } input.seekg(0, std::ios::end); const std::streamoff file_size = input.tellg(); if (file_size <= 0) { return false; } parse_mp4_atoms(input, 0, static_cast(file_size), std::nullopt, 0, metadata); return has_metadata_parts(metadata); } std::optional parse_media_metadata_without_mediainfo( const std::filesystem::path& media_path) { if (!MediaRenameMetadataService::is_supported_media(media_path)) { return std::nullopt; } MediaRenameMetadataService::MetadataFields metadata; const std::string extension = to_lower_copy(Utils::path_to_utf8(media_path.extension())); if (is_supported_audio(media_path)) { parse_id3v2_from_file(media_path, metadata); if (extension == ".mp3") { parse_id3v1_from_file(media_path, metadata); } else if (extension == ".flac") { parse_flac_vorbis_comments(media_path, metadata); } else if (extension == ".ogg" || extension == ".oga" || extension == ".opus") { parse_ogg_comments(media_path, metadata); } else if (extension == ".m4a") { parse_mp4_style_metadata(media_path, metadata); } } if (is_supported_video(media_path)) { if (extension == ".mp4" || extension == ".m4v" || extension == ".mov" || extension == ".3gp") { parse_mp4_style_metadata(media_path, metadata); } } if (!has_metadata_parts(metadata)) { return std::nullopt; } return metadata; } #endif #ifdef AI_FILE_SORTER_USE_MEDIAINFOLIB std::string media_info_to_utf8(const MediaInfoCompat::String& value) { #if defined(UNICODE) || defined(_UNICODE) const std::wstring wide_value(value.begin(), value.end()); return trim_copy(QString::fromStdWString(wide_value).toUtf8().toStdString()); #else return trim_copy(std::string(value.begin(), value.end())); #endif } std::string query_field(MediaInfoCompat::MediaInfo& media_info, MediaInfoCompat::stream_t stream_kind, size_t stream_number, const MediaInfoCompat::Char* parameter) { return media_info_to_utf8(media_info.Get(stream_kind, stream_number, parameter, MediaInfoCompat::Info_Text, MediaInfoCompat::Info_Name)); } template std::optional query_first_field(MediaInfoCompat::MediaInfo& media_info, MediaInfoCompat::stream_t stream_kind, size_t stream_number, const std::array& keys) { for (const auto* key : keys) { const std::string value = query_field(media_info, stream_kind, stream_number, key); if (!value.empty()) { return value; } } return std::nullopt; } std::optional query_first_available(MediaInfoCompat::MediaInfo& media_info, const std::vector>>& probes) { for (const auto& probe : probes) { if (auto value = query_first_field(media_info, probe.first, 0, probe.second)) { return value; } } return std::nullopt; } #endif } // namespace std::optional MediaRenameMetadataService::suggest_name(const std::filesystem::path& media_path) const { if (!is_supported_media(media_path)) { return std::nullopt; } const auto metadata = extract_metadata(media_path); if (!metadata.has_value()) { return std::nullopt; } const std::string suggested = compose_filename(media_path, *metadata); if (suggested.empty()) { return std::nullopt; } const std::string original = Utils::path_to_utf8(media_path.filename()); if (to_lower_copy(suggested) == to_lower_copy(original)) { return std::nullopt; } return suggested; } bool MediaRenameMetadataService::is_supported_media(const std::filesystem::path& path) { return is_supported_audio(path) || is_supported_video(path); } std::string MediaRenameMetadataService::compose_filename(const std::filesystem::path& original_path, const MetadataFields& metadata) { const std::string original_name = Utils::path_to_utf8(original_path.filename()); if (original_name.empty()) { return std::string(); } if (!has_metadata_parts(metadata)) { return original_name; } const std::string extension = Utils::path_to_utf8(original_path.extension()); const std::string fallback_stem = Utils::path_to_utf8(original_path.stem()); std::vector parts; parts.reserve(4); if (metadata.year.has_value()) { if (const auto year = normalize_year(*metadata.year)) { parts.push_back(*year); } } const auto append_slug = [&parts](const std::optional& value) { if (!value.has_value() || value->empty()) { return; } const std::string slug = MediaRenameMetadataService::slugify(*value); if (!slug.empty()) { parts.push_back(slug); } }; append_slug(metadata.artist); append_slug(metadata.album); std::string title_slug; if (metadata.title.has_value()) { title_slug = slugify(*metadata.title); } if (title_slug.empty()) { title_slug = slugify(fallback_stem); } if (!title_slug.empty()) { parts.push_back(title_slug); } if (parts.empty()) { return original_name; } std::string base_name; for (size_t index = 0; index < parts.size(); ++index) { if (index > 0) { base_name.push_back('_'); } base_name += parts[index]; } if (base_name.empty()) { return original_name; } return extension.empty() ? base_name : base_name + extension; } std::optional MediaRenameMetadataService::extract_metadata( const std::filesystem::path& media_path) { #ifndef AI_FILE_SORTER_USE_MEDIAINFOLIB auto metadata = parse_media_metadata_without_mediainfo(media_path); if (!metadata.has_value()) { return std::nullopt; } if (metadata->year.has_value()) { metadata->year = normalize_year(*metadata->year); if (!metadata->year.has_value()) { metadata->year.reset(); } } if (!has_metadata_parts(*metadata)) { return std::nullopt; } return metadata; #else if (!is_supported_media(media_path)) { return std::nullopt; } MediaInfoCompat::MediaInfo media_info; #if defined(UNICODE) || defined(_UNICODE) const std::wstring wide_path = media_path.wstring(); const MediaInfoCompat::String open_path(wide_path.begin(), wide_path.end()); #else const std::string utf8_path = Utils::path_to_utf8(media_path); const MediaInfoCompat::String open_path(utf8_path.begin(), utf8_path.end()); #endif if (media_info.Open(open_path) == 0) { return std::nullopt; } MetadataFields metadata; const bool audio_file = is_supported_audio(media_path); const bool video_file = is_supported_video(media_path); if (audio_file) { static constexpr std::array kArtistGeneral = { __T("Performer"), __T("Album_Artist"), __T("Artist"), __T("Composer"), __T("Track/Performer"), __T("Track/Artist") }; static constexpr std::array kArtistAudio = { __T("Performer"), __T("Album_Artist"), __T("Artist"), __T("Composer"), __T("Track/Performer"), __T("Track/Artist") }; static constexpr std::array kAlbumGeneral = { __T("Album"), __T("Track/Album"), __T("Movie"), __T("Collection"), __T("Show"), __T("PackageName") }; static constexpr std::array kTitleGeneral = { __T("Title"), __T("Track"), __T("Track/Title"), __T("Song"), __T("Movie"), __T("Name") }; static constexpr std::array kTitleAudio = { __T("Title"), __T("Track"), __T("Track/Title"), __T("Song"), __T("Name"), __T("Encoded_Library/Name") }; metadata.artist = query_first_field(media_info, MediaInfoCompat::Stream_General, 0, kArtistGeneral); if (!metadata.artist.has_value()) { metadata.artist = query_first_field(media_info, MediaInfoCompat::Stream_Audio, 0, kArtistAudio); } metadata.album = query_first_field(media_info, MediaInfoCompat::Stream_General, 0, kAlbumGeneral); metadata.title = query_first_field(media_info, MediaInfoCompat::Stream_General, 0, kTitleGeneral); if (!metadata.title.has_value()) { metadata.title = query_first_field(media_info, MediaInfoCompat::Stream_Audio, 0, kTitleAudio); } } if (video_file) { static constexpr std::array kArtistVideoGeneral = { __T("Performer"), __T("Director"), __T("Composer"), __T("Producer"), __T("Artist"), __T("Encoded_Library/Name") }; static constexpr std::array kAlbumVideoGeneral = { __T("Movie"), __T("Show"), __T("Album"), __T("Collection"), __T("Season"), __T("PackageName") }; static constexpr std::array kTitleVideoGeneral = { __T("Title"), __T("Movie"), __T("Track"), __T("Episode"), __T("Name"), __T("Series") }; static constexpr std::array kTitleVideoStream = { __T("Title"), __T("Track"), __T("Name"), __T("Movie"), __T("Episode"), __T("Series") }; if (!metadata.artist.has_value()) { metadata.artist = query_first_field(media_info, MediaInfoCompat::Stream_General, 0, kArtistVideoGeneral); } if (!metadata.album.has_value()) { metadata.album = query_first_field(media_info, MediaInfoCompat::Stream_General, 0, kAlbumVideoGeneral); } if (!metadata.title.has_value()) { metadata.title = query_first_field(media_info, MediaInfoCompat::Stream_General, 0, kTitleVideoGeneral); } if (!metadata.title.has_value()) { metadata.title = query_first_field(media_info, MediaInfoCompat::Stream_Video, 0, kTitleVideoStream); } } static const std::vector>> kYearProbes = { { MediaInfoCompat::Stream_General, { __T("Recorded_Date"), __T("Released_Date"), __T("Encoded_Date"), __T("Mastered_Date"), __T("Tagged_Date"), __T("Date") } }, { MediaInfoCompat::Stream_Audio, { __T("Recorded_Date"), __T("Released_Date"), __T("Encoded_Date"), __T("Date"), __T("Mastered_Date"), __T("Tagged_Date") } }, { MediaInfoCompat::Stream_Video, { __T("Recorded_Date"), __T("Released_Date"), __T("Encoded_Date"), __T("Date"), __T("Mastered_Date"), __T("Tagged_Date") } } }; if (const auto raw_year = query_first_available(media_info, kYearProbes)) { metadata.year = normalize_year(*raw_year); } media_info.Close(); if (!has_metadata_parts(metadata)) { return std::nullopt; } return metadata; #endif } std::string MediaRenameMetadataService::slugify(const std::string& value) { std::string slug; slug.reserve(value.size()); bool last_separator = false; for (unsigned char ch : value) { if (std::isalnum(ch)) { slug.push_back(static_cast(std::tolower(ch))); last_separator = false; } else if (!last_separator && !slug.empty()) { slug.push_back('_'); last_separator = true; } } while (!slug.empty() && slug.back() == '_') { slug.pop_back(); } return slug; } std::optional MediaRenameMetadataService::normalize_year(const std::string& value) { if (value.size() < 4) { return std::nullopt; } for (size_t index = 0; index + 3 < value.size(); ++index) { const char c0 = value[index]; const char c1 = value[index + 1]; const char c2 = value[index + 2]; const char c3 = value[index + 3]; if (!std::isdigit(static_cast(c0)) || !std::isdigit(static_cast(c1)) || !std::isdigit(static_cast(c2)) || !std::isdigit(static_cast(c3))) { continue; } const bool prefixed_by_digit = index > 0 && std::isdigit(static_cast(value[index - 1])); const bool suffixed_by_digit = (index + 4) < value.size() && std::isdigit(static_cast(value[index + 4])); if (prefixed_by_digit || suffixed_by_digit) { continue; } const int year = (c0 - '0') * 1000 + (c1 - '0') * 100 + (c2 - '0') * 10 + (c3 - '0'); if (year >= 1900 && year <= 2100) { return std::string{c0, c1, c2, c3}; } } return std::nullopt; } ================================================ FILE: app/lib/MovableCategorizedFile.cpp ================================================ #include "MovableCategorizedFile.hpp" #include "Utils.hpp" #include "Logger.hpp" #include #include #include #include #include namespace { template void with_core_logger(Callable callable) { if (auto logger = Logger::get_logger("core_logger")) { callable(*logger); } } std::string to_lower_copy_str(std::string value) { std::transform(value.begin(), value.end(), value.begin(), [](unsigned char c) { return static_cast(std::tolower(c)); }); return value; } bool contains_only_allowed_chars(const std::string& value) { for (unsigned char ch : value) { if (std::iscntrl(ch)) { return false; } static const std::string forbidden = R"(<>:"/\|?*)"; if (forbidden.find(static_cast(ch)) != std::string::npos) { return false; } // Everything else is allowed (including non-ASCII letters and punctuation). } return true; } bool has_leading_or_trailing_space_or_dot(const std::string& value) { if (value.empty()) { return false; } const unsigned char first = static_cast(value.front()); const unsigned char last = static_cast(value.back()); // Only guard leading/trailing whitespace; dots are allowed. return std::isspace(first) || std::isspace(last); } bool is_reserved_windows_name(const std::string& value) { static const std::vector reserved = { "con","prn","aux","nul", "com1","com2","com3","com4","com5","com6","com7","com8","com9", "lpt1","lpt2","lpt3","lpt4","lpt5","lpt6","lpt7","lpt8","lpt9" }; const std::string lower = to_lower_copy_str(value); return std::find(reserved.begin(), reserved.end(), lower) != reserved.end(); } bool looks_like_extension_label(const std::string& value) { const auto dot_pos = value.rfind('.'); if (dot_pos == std::string::npos || dot_pos == value.size() - 1) { return false; } const std::string ext = value.substr(dot_pos + 1); if (ext.empty() || ext.size() > 5) { return false; } return std::all_of(ext.begin(), ext.end(), [](unsigned char ch) { return std::isalpha(ch); }); } bool validate_labels(const std::string& category, const std::string& subcategory, std::string& error) { constexpr size_t kMaxLabelLength = 80; if (category.empty() || subcategory.empty()) { error = "Category or subcategory is empty"; return false; } if (category.size() > kMaxLabelLength || subcategory.size() > kMaxLabelLength) { error = "Category or subcategory exceeds max length"; return false; } if (!contains_only_allowed_chars(category) || !contains_only_allowed_chars(subcategory)) { error = "Category or subcategory contains disallowed characters"; return false; } if (looks_like_extension_label(category) || looks_like_extension_label(subcategory)) { error = "Category or subcategory looks like a file extension"; return false; } if (is_reserved_windows_name(category) || is_reserved_windows_name(subcategory)) { error = "Category or subcategory is a reserved name"; return false; } if (has_leading_or_trailing_space_or_dot(category) || has_leading_or_trailing_space_or_dot(subcategory)) { error = "Category or subcategory has leading/trailing space or dot"; return false; } return true; } } MovableCategorizedFile::MovePaths MovableCategorizedFile::build_move_paths(bool use_subcategory) const { const std::filesystem::path base_dir = Utils::utf8_to_path(dir_path); const std::filesystem::path category_segment = Utils::utf8_to_path(category); const std::filesystem::path subcategory_segment = Utils::utf8_to_path(subcategory); const std::filesystem::path file_segment = Utils::utf8_to_path(file_name); const std::filesystem::path destination_segment = Utils::utf8_to_path(destination_file_name); const std::filesystem::path categorized_root = use_subcategory ? base_dir / category_segment / subcategory_segment : base_dir / category_segment; return MovePaths{ Utils::utf8_to_path(source_dir) / file_segment, categorized_root / destination_segment }; } bool MovableCategorizedFile::source_is_available(const std::filesystem::path& source_path) const { if (std::filesystem::exists(source_path)) { return true; } with_core_logger([&](auto& logger) { logger.warn("Source file missing when moving '{}': {}", file_name, Utils::path_to_utf8(source_path)); }); return false; } bool MovableCategorizedFile::destination_is_available(const std::filesystem::path& destination_path) const { if (!std::filesystem::exists(destination_path)) { return true; } with_core_logger([&](auto& logger) { logger.info("Destination already contains '{}'; skipping move", Utils::path_to_utf8(destination_path)); }); return false; } bool MovableCategorizedFile::perform_move(const std::filesystem::path& source_path, const std::filesystem::path& destination_path) const { try { std::filesystem::rename(source_path, destination_path); with_core_logger([&](auto& logger) { logger.info("Moved '{}' to '{}'", Utils::path_to_utf8(source_path), Utils::path_to_utf8(destination_path)); }); return true; } catch (const std::filesystem::filesystem_error& e) { with_core_logger([&](auto& logger) { logger.error("Failed to move '{}' to '{}': {}", Utils::path_to_utf8(source_path), Utils::path_to_utf8(destination_path), e.what()); }); return false; } } MovableCategorizedFile::MovableCategorizedFile( const std::string& dir_path, const std::string& cat, const std::string& subcat, const std::string& file_name, const std::string& destination_name) : MovableCategorizedFile(dir_path, dir_path, cat, subcat, file_name, destination_name) { } MovableCategorizedFile::MovableCategorizedFile( const std::string& source_dir, const std::string& destination_root, const std::string& cat, const std::string& subcat, const std::string& file_name, const std::string& destination_name) : file_name(file_name), destination_file_name(destination_name.empty() ? file_name : destination_name), source_dir(source_dir), dir_path(destination_root), category(cat), subcategory(subcat) { std::string validation_error; if (!validate_labels(category, subcategory, validation_error)) { if (auto logger = Logger::get_logger("core_logger")) { logger->error("Invalid path components while constructing MovableCategorizedFile (dir='{}', category='{}', subcategory='{}', file='{}'): {}", dir_path, category, subcategory, file_name, validation_error); } throw std::runtime_error("Invalid category/subcategory: " + validation_error); } if (dir_path.empty() || category.empty() || subcategory.empty() || file_name.empty()) { if (auto logger = Logger::get_logger("core_logger")) { logger->error("Invalid path components while constructing MovableCategorizedFile (dir='{}', category='{}', subcategory='{}', file='{}')", dir_path, category, subcategory, file_name); } throw std::runtime_error("Invalid path component in CategorizedFile constructor."); } const std::filesystem::path base_dir = Utils::utf8_to_path(dir_path); category_path = base_dir / Utils::utf8_to_path(category); subcategory_path = category_path / Utils::utf8_to_path(subcategory); destination_path = subcategory_path / Utils::utf8_to_path(destination_file_name); } void MovableCategorizedFile::create_cat_dirs(bool use_subcategory) { try { if (!std::filesystem::exists(category_path)) { std::filesystem::create_directory(category_path); } if (use_subcategory && !std::filesystem::exists(subcategory_path)) { std::filesystem::create_directory(subcategory_path); } } catch (const std::filesystem::filesystem_error& e) { if (auto logger = Logger::get_logger("core_logger")) { logger->error("Failed to create directories for '{}': {}", file_name, e.what()); } throw; } } bool MovableCategorizedFile::move_file(bool use_subcategory) { const MovePaths paths = build_move_paths(use_subcategory); if (!source_is_available(paths.source)) { return false; } if (!destination_is_available(paths.destination)) { return false; } return perform_move(paths.source, paths.destination); } MovableCategorizedFile::PreviewPaths MovableCategorizedFile::preview_move_paths(bool use_subcategory) const { const MovePaths paths = build_move_paths(use_subcategory); return PreviewPaths{ Utils::path_to_utf8(paths.source), Utils::path_to_utf8(paths.destination) }; } std::string MovableCategorizedFile::get_subcategory_path() const { return Utils::path_to_utf8(subcategory_path); } std::string MovableCategorizedFile::get_category_path() const { return Utils::path_to_utf8(category_path); } std::string MovableCategorizedFile::get_destination_path() const { return Utils::path_to_utf8(destination_path); } std::string MovableCategorizedFile::get_file_name() const { return file_name; } std::string MovableCategorizedFile::get_dir_path() const { return dir_path; } std::string MovableCategorizedFile::get_category() const { return category; } std::string MovableCategorizedFile::get_subcategory() const { return subcategory; } void MovableCategorizedFile::set_category(std::string& category) { this->category = category; } void MovableCategorizedFile::set_subcategory(std::string& subcategory) { this->subcategory = subcategory; } MovableCategorizedFile::~MovableCategorizedFile() {} ================================================ FILE: app/lib/PugixmlBundle.cpp ================================================ #if defined(AI_FILE_SORTER_USE_PUGIXML) #include "pugixml.hpp" #include "pugixml.cpp" #endif ================================================ FILE: app/lib/ResultsCoordinator.cpp ================================================ #include "ResultsCoordinator.hpp" #include #include ResultsCoordinator::ResultsCoordinator(FileScanner& scanner) : scanner(scanner) { } std::vector ResultsCoordinator::list_directory(const std::string& directory, FileScanOptions options) const { return scanner.get_directory_entries(directory, options); } std::vector ResultsCoordinator::find_files_to_categorize( const std::string& directory_path, FileScanOptions options, const std::unordered_set& cached_files, bool use_full_path_keys) const { std::vector actual_files = list_directory(directory_path, options); std::vector found_files; found_files.reserve(actual_files.size()); for (const auto& entry : actual_files) { const std::string key = use_full_path_keys ? entry.full_path : entry.file_name; if (!cached_files.contains(key)) { found_files.push_back(entry); } } return found_files; } std::vector ResultsCoordinator::compute_files_to_sort( const std::string& directory_path, FileScanOptions options, const std::vector& actual_files, const std::vector& categorized_files, bool use_full_path_keys) const { (void)directory_path; (void)options; std::vector files_to_sort; files_to_sort.reserve(actual_files.size()); for (const auto& entry : actual_files) { const auto it = std::find_if( categorized_files.begin(), categorized_files.end(), [&entry, use_full_path_keys](const CategorizedFile& categorized_file) { if (categorized_file.type != entry.type) { return false; } if (use_full_path_keys) { const auto full_path = std::filesystem::path(categorized_file.file_path) / std::filesystem::path(categorized_file.file_name); return full_path == std::filesystem::path(entry.full_path); } return categorized_file.file_name == entry.file_name; }); if (it != categorized_files.end()) { files_to_sort.push_back(*it); } } return files_to_sort; } std::unordered_set ResultsCoordinator::extract_file_names( const std::vector& categorized_files, bool use_full_path_keys) const { std::unordered_set file_names; file_names.reserve(categorized_files.size()); for (const auto& file : categorized_files) { if (use_full_path_keys) { const auto full_path = std::filesystem::path(file.file_path) / std::filesystem::path(file.file_name); file_names.insert(full_path.string()); } else { file_names.insert(file.file_name); } } return file_names; } ================================================ FILE: app/lib/Settings.cpp ================================================ #include "Settings.hpp" #include "Types.hpp" #include "Logger.hpp" #include "Language.hpp" #include "Utils.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef _WIN32 #include #include #endif namespace { template void settings_log(spdlog::level::level_enum level, const char* fmt, Args&&... args) { auto message = fmt::format(fmt::runtime(fmt), std::forward(args)...); if (auto logger = Logger::get_logger("core_logger")) { logger->log(level, "{}", message); } else { std::fprintf(stderr, "%s\n", message.c_str()); } } int parse_int_or(const std::string& value, int fallback) { try { return std::stoi(value); } catch (...) { return fallback; } } std::vector parse_list(const std::string& value) { std::vector result; std::stringstream ss(value); std::string item; while (std::getline(ss, item, ',')) { auto not_space = [](unsigned char ch) { return !std::isspace(ch); }; item.erase(item.begin(), std::find_if(item.begin(), item.end(), not_space)); item.erase(std::find_if(item.rbegin(), item.rend(), not_space).base(), item.end()); if (!item.empty()) { result.push_back(item); } } return result; } std::string trim_copy(const std::string& value) { auto trimmed = value; auto not_space = [](unsigned char ch) { return !std::isspace(ch); }; trimmed.erase(trimmed.begin(), std::find_if(trimmed.begin(), trimmed.end(), not_space)); trimmed.erase(std::find_if(trimmed.rbegin(), trimmed.rend(), not_space).base(), trimmed.end()); return trimmed; } std::string join_list(const std::vector& items) { std::ostringstream oss; for (size_t i = 0; i < items.size(); ++i) { if (i > 0) { oss << ","; } oss << items[i]; } return oss.str(); } std::string to_bool_string(bool value) { return value ? "true" : "false"; } std::string encode_multiline(const std::string& value) { std::string output; output.reserve(value.size()); for (char ch : value) { if (ch == '\\') { output.append("\\\\"); } else if (ch == '\n') { output.append("\\n"); } else { output.push_back(ch); } } return output; } std::string decode_multiline(const std::string& value) { std::string output; output.reserve(value.size()); for (size_t i = 0; i < value.size(); ++i) { char ch = value[i]; if (ch == '\\' && i + 1 < value.size()) { char next = value[i + 1]; if (next == 'n') { output.push_back('\n'); ++i; continue; } if (next == '\\') { output.push_back('\\'); ++i; continue; } } output.push_back(ch); } return output; } std::string llm_choice_to_string(LLMChoice choice) { switch (choice) { case LLMChoice::Remote_OpenAI: return "Remote_OpenAI"; case LLMChoice::Remote_Gemini: return "Remote_Gemini"; case LLMChoice::Remote_Custom: return "Remote_Custom"; case LLMChoice::Local_3b: return "Local_3b"; case LLMChoice::Local_3b_legacy: return "Local_3b_legacy"; case LLMChoice::Local_7b: return "Local_7b"; case LLMChoice::Custom: return "Custom"; default: return "Unset"; } } void set_bool_setting(IniConfig& config, const std::string& section, const char* key, bool value) { config.setValue(section, key, to_bool_string(value)); } void set_optional_setting(IniConfig& config, const std::string& section, const char* key, const std::string& value) { if (!value.empty()) { config.setValue(section, key, value); } } std::string generate_custom_llm_id() { using clock = std::chrono::steady_clock; const auto now = clock::now().time_since_epoch().count(); std::mt19937_64 rng(static_cast(now)); const uint64_t value = rng(); std::ostringstream oss; oss << "llm_" << std::hex << value; return oss.str(); } std::string generate_custom_api_id() { using clock = std::chrono::steady_clock; const auto now = clock::now().time_since_epoch().count(); std::mt19937_64 rng(static_cast(now)); const uint64_t value = rng(); std::ostringstream oss; oss << "api_" << std::hex << value; return oss.str(); } Language system_default_language() { switch (QLocale::system().language()) { case QLocale::French: return Language::French; case QLocale::German: return Language::German; case QLocale::Italian: return Language::Italian; case QLocale::Spanish: return Language::Spanish; case QLocale::Turkish: return Language::Turkish; case QLocale::Korean: return Language::Korean; case QLocale::Dutch: return Language::Dutch; default: return Language::English; } } std::string path_from_env_url(const char* env_key) { const char* url = std::getenv(env_key); if (!url || *url == '\0') { return {}; } try { return Utils::make_default_path_to_file_from_download_url(url); } catch (...) { return {}; } } bool file_exists_for_env_url(const char* env_key) { const std::string path = path_from_env_url(env_key); if (path.empty()) { return false; } std::error_code ec; return std::filesystem::exists(path, ec); } } Settings::Settings() : use_subcategories(true), categorize_files(true), categorize_directories(false), include_subdirectories(false), use_consistency_hints(false), use_whitelist(false), default_sort_folder(""), sort_folder("") { std::string AppName = "AIFileSorter"; config_path = define_config_path(); config_dir = std::filesystem::path(config_path).parent_path(); try { if (!std::filesystem::exists(config_dir)) { std::filesystem::create_directories(config_dir); } } catch (const std::filesystem::filesystem_error &e) { settings_log(spdlog::level::err, "Error creating configuration directory: {}", e.what()); } auto to_utf8 = [](const QString& value) -> std::string { const QByteArray bytes = value.toUtf8(); return std::string(bytes.constData(), static_cast(bytes.size())); }; QString downloads = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation); if (!downloads.isEmpty()) { default_sort_folder = to_utf8(downloads); } else { QString home = QStandardPaths::writableLocation(QStandardPaths::HomeLocation); if (!home.isEmpty()) { default_sort_folder = to_utf8(home); } } if (default_sort_folder.empty()) { default_sort_folder = Utils::path_to_utf8(std::filesystem::current_path()); } sort_folder = default_sort_folder; // Default language follows system locale on first run (before any config file exists). language = system_default_language(); category_language = CategoryLanguage::English; analyze_images_by_content = false; offer_rename_images = false; add_image_date_place_to_filename = false; add_audio_video_metadata_to_filename = true; add_image_date_to_category = false; analyze_documents_by_content = false; offer_rename_documents = false; rename_documents_only = false; process_documents_only = false; add_document_date_to_category = false; } LLMChoice Settings::parse_llm_choice() const { const std::string value = config.getValue("Settings", "LLMChoice", "Unset"); if (value == "Remote" || value == "Remote_OpenAI") return LLMChoice::Remote_OpenAI; if (value == "Remote_Gemini") return LLMChoice::Remote_Gemini; if (value == "Remote_Custom") return LLMChoice::Remote_Custom; if (value == "Local_3b") return LLMChoice::Local_3b; if (value == "Local_3b_legacy") return LLMChoice::Local_3b_legacy; if (value == "Local_7b") return LLMChoice::Local_7b; if (value == "Custom") return LLMChoice::Custom; return LLMChoice::Unset; } void Settings::load_basic_settings(const std::function& load_bool, const std::function& load_int) { llm_choice = parse_llm_choice(); set_openai_api_key(config.getValue("Settings", "RemoteApiKey", "")); set_openai_model(config.getValue("Settings", "RemoteModel", "gpt-4o-mini")); set_gemini_api_key(config.getValue("Settings", "GeminiApiKey", "")); set_gemini_model(config.getValue("Settings", "GeminiModel", "gemini-2.5-flash-lite")); llm_downloads_expanded = load_bool("LLMDownloadsExpanded", true); use_subcategories = load_bool("UseSubcategories", false); use_consistency_hints = load_bool("UseConsistencyHints", false); categorize_files = load_bool("CategorizeFiles", true); categorize_directories = load_bool("CategorizeDirectories", false); include_subdirectories = load_bool("IncludeSubdirectories", false); analyze_images_by_content = load_bool("AnalyzeImagesByContent", false); offer_rename_images = load_bool("OfferRenameImages", false); add_image_date_place_to_filename = load_bool("AddImageDatePlaceToFilename", false); add_audio_video_metadata_to_filename = load_bool("AddAudioVideoMetadataToFilename", true); add_image_date_to_category = load_bool("AddImageDateToCategory", false); rename_images_only = load_bool("RenameImagesOnly", false); process_images_only = load_bool("ProcessImagesOnly", false); analyze_documents_by_content = load_bool("AnalyzeDocumentsByContent", false); offer_rename_documents = load_bool("OfferRenameDocuments", false); rename_documents_only = load_bool("RenameDocumentsOnly", false); process_documents_only = load_bool("ProcessDocumentsOnly", false); add_document_date_to_category = load_bool("AddDocumentDateToCategory", false); const bool image_expand_default = process_images_only || offer_rename_images || rename_images_only || add_image_date_place_to_filename || add_image_date_to_category; if (config.hasValue("Settings", "ImageOptionsExpanded")) { image_options_expanded = load_bool("ImageOptionsExpanded", image_expand_default); } else { image_options_expanded = image_expand_default; } const bool document_expand_default = process_documents_only || offer_rename_documents || rename_documents_only || add_document_date_to_category; if (config.hasValue("Settings", "DocumentOptionsExpanded")) { document_options_expanded = load_bool("DocumentOptionsExpanded", document_expand_default); } else { document_options_expanded = document_expand_default; } if (rename_images_only && !offer_rename_images) { offer_rename_images = true; } if (rename_documents_only && !offer_rename_documents) { offer_rename_documents = true; } if (include_subdirectories && categorize_directories) { categorize_directories = false; } sort_folder = config.getValue("Settings", "SortFolder", default_sort_folder.empty() ? std::string("/") : default_sort_folder); show_file_explorer = load_bool("ShowFileExplorer", true); suitability_benchmark_completed = load_bool("SuitabilityBenchmarkCompleted", false); suitability_benchmark_suppressed = load_bool("SuitabilityBenchmarkSuppressed", false); benchmark_last_report = decode_multiline(config.getValue("Settings", "BenchmarkLastReport", "")); benchmark_last_run = config.getValue("Settings", "BenchmarkLastRun", ""); consistency_pass_enabled = load_bool("ConsistencyPass", false); development_prompt_logging = load_bool("DevelopmentPromptLogging", false); skipped_version = config.getValue("Settings", "SkippedVersion", "0.0.0"); if (config.hasValue("Settings", "Language")) { language = languageFromString(QString::fromStdString(config.getValue("Settings", "Language", "English"))); } else { language = system_default_language(); } category_language = categoryLanguageFromString(QString::fromStdString(config.getValue("Settings", "CategoryLanguage", "English"))); categorized_file_count = load_int("CategorizedFileCount", 0, 0); next_support_prompt_threshold = load_int("SupportPromptThreshold", 50, 50); } void Settings::load_whitelist_settings(const std::function& load_bool) { allowed_categories = parse_list(config.getValue("Settings", "AllowedCategories", "")); allowed_subcategories = parse_list(config.getValue("Settings", "AllowedSubcategories", "")); use_whitelist = load_bool("UseWhitelist", false); active_whitelist = config.getValue("Settings", "ActiveWhitelist", ""); } void Settings::load_custom_llm_settings() { active_custom_llm_id = config.getValue("LLMs", "ActiveCustomId", ""); custom_llms.clear(); const auto custom_ids = parse_list(config.getValue("LLMs", "CustomIds", "")); for (const auto& id : custom_ids) { const std::string section = "LLM_" + id; CustomLLM entry; entry.id = id; entry.name = config.getValue(section, "Name", ""); entry.description = config.getValue(section, "Description", ""); entry.path = config.getValue(section, "Path", ""); if (!entry.name.empty() && !entry.path.empty()) { custom_llms.push_back(entry); } } } void Settings::load_custom_api_settings() { active_custom_api_id = config.getValue("CustomApis", "ActiveCustomApiId", ""); custom_api_endpoints.clear(); const auto api_ids = parse_list(config.getValue("CustomApis", "CustomApiIds", "")); for (const auto& id : api_ids) { const std::string section = "CustomApi_" + id; CustomApiEndpoint entry; entry.id = id; entry.name = config.getValue(section, "Name", ""); entry.description = config.getValue(section, "Description", ""); entry.base_url = config.getValue(section, "BaseUrl", ""); entry.api_key = config.getValue(section, "ApiKey", ""); entry.model = config.getValue(section, "Model", ""); entry.name = trim_copy(entry.name); entry.description = trim_copy(entry.description); entry.base_url = trim_copy(entry.base_url); entry.api_key = trim_copy(entry.api_key); entry.model = trim_copy(entry.model); if (is_valid_custom_api_endpoint(entry)) { custom_api_endpoints.push_back(entry); } } } void Settings::log_loaded_settings() const { if (auto logger = Logger::get_logger("core_logger")) { logger->info("Loaded settings from '{}' (allowed categories: {}, allowed subcategories: {}, use whitelist: {}, active whitelist: '{}', custom llms: {}, custom apis: {}, category language: {})", config_path, allowed_categories.size(), allowed_subcategories.size(), use_whitelist, active_whitelist, custom_llms.size(), custom_api_endpoints.size(), categoryLanguageDisplay(category_language)); } } void Settings::save_core_settings() { static const std::string settings_section = "Settings"; config.setValue(settings_section, "LLMChoice", llm_choice_to_string(llm_choice)); config.setValue(settings_section, "RemoteApiKey", openai_api_key); config.setValue(settings_section, "RemoteModel", openai_model.empty() ? "gpt-4o-mini" : openai_model); config.setValue(settings_section, "GeminiApiKey", gemini_api_key); config.setValue(settings_section, "GeminiModel", gemini_model.empty() ? "gemini-2.5-flash-lite" : gemini_model); set_bool_setting(config, settings_section, "LLMDownloadsExpanded", llm_downloads_expanded); set_bool_setting(config, settings_section, "UseSubcategories", use_subcategories); set_bool_setting(config, settings_section, "UseConsistencyHints", use_consistency_hints); set_bool_setting(config, settings_section, "CategorizeFiles", categorize_files); set_bool_setting(config, settings_section, "CategorizeDirectories", categorize_directories); set_bool_setting(config, settings_section, "IncludeSubdirectories", include_subdirectories); if (rename_images_only) { offer_rename_images = true; } if (rename_documents_only) { offer_rename_documents = true; } set_bool_setting(config, settings_section, "AnalyzeImagesByContent", analyze_images_by_content); set_bool_setting(config, settings_section, "OfferRenameImages", offer_rename_images); set_bool_setting(config, settings_section, "AddImageDatePlaceToFilename", add_image_date_place_to_filename); set_bool_setting(config, settings_section, "AddAudioVideoMetadataToFilename", add_audio_video_metadata_to_filename); set_bool_setting(config, settings_section, "AddImageDateToCategory", add_image_date_to_category); set_bool_setting(config, settings_section, "ImageOptionsExpanded", image_options_expanded); set_bool_setting(config, settings_section, "RenameImagesOnly", rename_images_only); set_bool_setting(config, settings_section, "ProcessImagesOnly", process_images_only); set_bool_setting(config, settings_section, "AnalyzeDocumentsByContent", analyze_documents_by_content); set_bool_setting(config, settings_section, "OfferRenameDocuments", offer_rename_documents); set_bool_setting(config, settings_section, "DocumentOptionsExpanded", document_options_expanded); set_bool_setting(config, settings_section, "RenameDocumentsOnly", rename_documents_only); set_bool_setting(config, settings_section, "ProcessDocumentsOnly", process_documents_only); set_bool_setting(config, settings_section, "AddDocumentDateToCategory", add_document_date_to_category); config.setValue(settings_section, "SortFolder", this->sort_folder); set_optional_setting(config, settings_section, "SkippedVersion", skipped_version); set_bool_setting(config, settings_section, "ShowFileExplorer", show_file_explorer); set_bool_setting(config, settings_section, "SuitabilityBenchmarkCompleted", suitability_benchmark_completed); set_bool_setting(config, settings_section, "SuitabilityBenchmarkSuppressed", suitability_benchmark_suppressed); set_optional_setting(config, settings_section, "BenchmarkLastReport", encode_multiline(benchmark_last_report)); set_optional_setting(config, settings_section, "BenchmarkLastRun", benchmark_last_run); set_bool_setting(config, settings_section, "ConsistencyPass", consistency_pass_enabled); set_bool_setting(config, settings_section, "DevelopmentPromptLogging", development_prompt_logging); config.setValue(settings_section, "Language", languageToString(language).toStdString()); config.setValue(settings_section, "CategoryLanguage", categoryLanguageToString(category_language).toStdString()); config.setValue(settings_section, "CategorizedFileCount", std::to_string(categorized_file_count)); config.setValue(settings_section, "SupportPromptThreshold", std::to_string(next_support_prompt_threshold)); } void Settings::save_whitelist_settings() { static const std::string settings_section = "Settings"; config.setValue(settings_section, "AllowedCategories", join_list(allowed_categories)); config.setValue(settings_section, "AllowedSubcategories", join_list(allowed_subcategories)); set_bool_setting(config, settings_section, "UseWhitelist", use_whitelist); set_optional_setting(config, settings_section, "ActiveWhitelist", active_whitelist); } void Settings::save_custom_llms() { static const std::string llm_section = "LLMs"; set_optional_setting(config, llm_section, "ActiveCustomId", active_custom_llm_id); std::vector ids; ids.reserve(custom_llms.size()); for (const auto& entry : custom_llms) { if (!is_valid_custom_llm(entry)) { continue; } ids.push_back(entry.id); const std::string section = "LLM_" + entry.id; config.setValue(section, "Name", entry.name); config.setValue(section, "Description", entry.description); config.setValue(section, "Path", entry.path); } config.setValue(llm_section, "CustomIds", join_list(ids)); } void Settings::save_custom_api_endpoints() { static const std::string api_section = "CustomApis"; set_optional_setting(config, api_section, "ActiveCustomApiId", active_custom_api_id); std::vector ids; ids.reserve(custom_api_endpoints.size()); for (const auto& entry : custom_api_endpoints) { if (!is_valid_custom_api_endpoint(entry)) { continue; } ids.push_back(entry.id); const std::string section = "CustomApi_" + entry.id; config.setValue(section, "Name", entry.name); config.setValue(section, "Description", entry.description); config.setValue(section, "BaseUrl", entry.base_url); config.setValue(section, "ApiKey", entry.api_key); config.setValue(section, "Model", entry.model); } config.setValue(api_section, "CustomApiIds", join_list(ids)); } std::string Settings::define_config_path() { std::string AppName = "AIFileSorter"; if (const char* override_root = std::getenv("AI_FILE_SORTER_CONFIG_DIR")) { std::filesystem::path base = override_root; return (base / AppName / "config.ini").string(); } #ifdef _WIN32 char appDataPath[MAX_PATH]; if (SUCCEEDED(SHGetFolderPathA(NULL, CSIDL_APPDATA, NULL, 0, appDataPath))) { return std::string(appDataPath) + "\\" + AppName + "\\config.ini"; } #elif defined(__APPLE__) return std::string(getenv("HOME")) + "/Library/Application Support/" + AppName + "/config.ini"; #else return std::string(getenv("HOME")) + "/.config/" + AppName + "/config.ini"; #endif return "config.ini"; } std::string Settings::get_config_dir() { return config_dir.string(); } bool Settings::load() { if (!config.load(config_path)) { sort_folder = default_sort_folder.empty() ? std::string("/") : default_sort_folder; // Keep language defaults derived from system locale when no config is found. return false; } const auto load_bool = [&](const char* key, bool def) { return config.getValue("Settings", key, def ? "true" : "false") == "true"; }; const auto load_int = [&](const char* key, int def, int min_val = std::numeric_limits::min()) { int value = parse_int_or(config.getValue("Settings", key, std::to_string(def)), def); return value < min_val ? min_val : value; }; load_basic_settings(load_bool, load_int); if (llm_choice == LLMChoice::Local_3b && !file_exists_for_env_url("LOCAL_LLM_3B_DOWNLOAD_URL") && file_exists_for_env_url("LOCAL_LLM_3B_LEGACY_DOWNLOAD_URL")) { llm_choice = LLMChoice::Local_3b_legacy; } load_whitelist_settings(load_bool); load_custom_llm_settings(); load_custom_api_settings(); log_loaded_settings(); return true; } bool Settings::save() { save_core_settings(); save_whitelist_settings(); save_custom_llms(); save_custom_api_endpoints(); return config.save(config_path); } LLMChoice Settings::get_llm_choice() const { return llm_choice; } void Settings::set_llm_choice(LLMChoice choice) { llm_choice = choice; } std::string Settings::get_openai_api_key() const { return openai_api_key; } void Settings::set_openai_api_key(const std::string& key) { auto trimmed = key; auto not_space = [](unsigned char ch) { return !std::isspace(ch); }; trimmed.erase(trimmed.begin(), std::find_if(trimmed.begin(), trimmed.end(), not_space)); trimmed.erase(std::find_if(trimmed.rbegin(), trimmed.rend(), not_space).base(), trimmed.end()); openai_api_key = trimmed; } std::string Settings::get_openai_model() const { return openai_model; } void Settings::set_openai_model(const std::string& model) { auto trimmed = model; auto not_space = [](unsigned char ch) { return !std::isspace(ch); }; trimmed.erase(trimmed.begin(), std::find_if(trimmed.begin(), trimmed.end(), not_space)); trimmed.erase(std::find_if(trimmed.rbegin(), trimmed.rend(), not_space).base(), trimmed.end()); if (trimmed.empty()) { trimmed = "gpt-4o-mini"; } openai_model = trimmed; } std::string Settings::get_gemini_api_key() const { return gemini_api_key; } void Settings::set_gemini_api_key(const std::string& key) { auto trimmed = key; auto not_space = [](unsigned char ch) { return !std::isspace(ch); }; trimmed.erase(trimmed.begin(), std::find_if(trimmed.begin(), trimmed.end(), not_space)); trimmed.erase(std::find_if(trimmed.rbegin(), trimmed.rend(), not_space).base(), trimmed.end()); gemini_api_key = trimmed; } std::string Settings::get_gemini_model() const { return gemini_model; } void Settings::set_gemini_model(const std::string& model) { auto trimmed = model; auto not_space = [](unsigned char ch) { return !std::isspace(ch); }; trimmed.erase(trimmed.begin(), std::find_if(trimmed.begin(), trimmed.end(), not_space)); trimmed.erase(std::find_if(trimmed.rbegin(), trimmed.rend(), not_space).base(), trimmed.end()); if (trimmed.empty()) { trimmed = "gemini-2.5-flash-lite"; } gemini_model = trimmed; } bool Settings::get_llm_downloads_expanded() const { return llm_downloads_expanded; } void Settings::set_llm_downloads_expanded(bool value) { llm_downloads_expanded = value; } std::string Settings::get_active_custom_llm_id() const { return active_custom_llm_id; } void Settings::set_active_custom_llm_id(const std::string& id) { active_custom_llm_id = id; } const std::vector& Settings::get_custom_llms() const { return custom_llms; } CustomLLM Settings::find_custom_llm(const std::string& id) const { const auto it = std::find_if(custom_llms.begin(), custom_llms.end(), [&id](const CustomLLM& item) { return item.id == id; }); if (it != custom_llms.end()) { return *it; } return {}; } std::string Settings::upsert_custom_llm(const CustomLLM& llm) { CustomLLM copy = llm; if (copy.id.empty()) { copy.id = generate_custom_llm_id(); } const auto it = std::find_if(custom_llms.begin(), custom_llms.end(), [©](const CustomLLM& item) { return item.id == copy.id; }); if (it != custom_llms.end()) { *it = copy; } else { custom_llms.push_back(copy); } return copy.id; } void Settings::remove_custom_llm(const std::string& id) { custom_llms.erase(std::remove_if(custom_llms.begin(), custom_llms.end(), [&id](const CustomLLM& item) { return item.id == id; }), custom_llms.end()); if (active_custom_llm_id == id) { active_custom_llm_id.clear(); } } std::string Settings::get_active_custom_api_id() const { return active_custom_api_id; } void Settings::set_active_custom_api_id(const std::string& id) { active_custom_api_id = id; } const std::vector& Settings::get_custom_api_endpoints() const { return custom_api_endpoints; } CustomApiEndpoint Settings::find_custom_api_endpoint(const std::string& id) const { const auto it = std::find_if(custom_api_endpoints.begin(), custom_api_endpoints.end(), [&id](const CustomApiEndpoint& item) { return item.id == id; }); if (it != custom_api_endpoints.end()) { return *it; } return {}; } std::string Settings::upsert_custom_api_endpoint(const CustomApiEndpoint& endpoint) { CustomApiEndpoint copy = endpoint; if (copy.id.empty()) { copy.id = generate_custom_api_id(); } copy.name = trim_copy(copy.name); copy.description = trim_copy(copy.description); copy.base_url = trim_copy(copy.base_url); copy.api_key = trim_copy(copy.api_key); copy.model = trim_copy(copy.model); const auto it = std::find_if(custom_api_endpoints.begin(), custom_api_endpoints.end(), [©](const CustomApiEndpoint& item) { return item.id == copy.id; }); if (it != custom_api_endpoints.end()) { *it = copy; } else { custom_api_endpoints.push_back(copy); } return copy.id; } void Settings::remove_custom_api_endpoint(const std::string& id) { custom_api_endpoints.erase(std::remove_if(custom_api_endpoints.begin(), custom_api_endpoints.end(), [&id](const CustomApiEndpoint& item) { return item.id == id; }), custom_api_endpoints.end()); if (active_custom_api_id == id) { active_custom_api_id.clear(); } } bool Settings::is_llm_chosen() const { return llm_choice != LLMChoice::Unset; } CategoryLanguage Settings::get_category_language() const { return category_language; } void Settings::set_category_language(CategoryLanguage language) { category_language = language; } bool Settings::get_use_subcategories() const { return use_subcategories; } void Settings::set_use_subcategories(bool value) { use_subcategories = value; } bool Settings::get_use_consistency_hints() const { return use_consistency_hints; } void Settings::set_use_consistency_hints(bool value) { use_consistency_hints = value; } bool Settings::get_categorize_files() const { return categorize_files; } void Settings::set_categorize_files(bool value) { categorize_files = value; } bool Settings::get_categorize_directories() const { return categorize_directories; } void Settings::set_categorize_directories(bool value) { categorize_directories = value; } bool Settings::get_include_subdirectories() const { return include_subdirectories; } void Settings::set_include_subdirectories(bool value) { include_subdirectories = value; } bool Settings::get_analyze_images_by_content() const { return analyze_images_by_content; } void Settings::set_analyze_images_by_content(bool value) { analyze_images_by_content = value; } bool Settings::get_offer_rename_images() const { return offer_rename_images; } void Settings::set_offer_rename_images(bool value) { offer_rename_images = value; } bool Settings::get_add_image_date_place_to_filename() const { return add_image_date_place_to_filename; } void Settings::set_add_image_date_place_to_filename(bool value) { add_image_date_place_to_filename = value; } bool Settings::get_add_audio_video_metadata_to_filename() const { return add_audio_video_metadata_to_filename; } void Settings::set_add_audio_video_metadata_to_filename(bool value) { add_audio_video_metadata_to_filename = value; } bool Settings::get_add_image_date_to_category() const { return add_image_date_to_category; } void Settings::set_add_image_date_to_category(bool value) { add_image_date_to_category = value; } bool Settings::get_image_options_expanded() const { return image_options_expanded; } void Settings::set_image_options_expanded(bool value) { image_options_expanded = value; } bool Settings::get_rename_images_only() const { return rename_images_only; } void Settings::set_rename_images_only(bool value) { rename_images_only = value; } bool Settings::get_process_images_only() const { return process_images_only; } void Settings::set_process_images_only(bool value) { process_images_only = value; } bool Settings::get_analyze_documents_by_content() const { return analyze_documents_by_content; } void Settings::set_analyze_documents_by_content(bool value) { analyze_documents_by_content = value; } bool Settings::get_offer_rename_documents() const { return offer_rename_documents; } void Settings::set_offer_rename_documents(bool value) { offer_rename_documents = value; } bool Settings::get_document_options_expanded() const { return document_options_expanded; } void Settings::set_document_options_expanded(bool value) { document_options_expanded = value; } bool Settings::get_rename_documents_only() const { return rename_documents_only; } void Settings::set_rename_documents_only(bool value) { rename_documents_only = value; } bool Settings::get_process_documents_only() const { return process_documents_only; } void Settings::set_process_documents_only(bool value) { process_documents_only = value; } bool Settings::get_add_document_date_to_category() const { return add_document_date_to_category; } void Settings::set_add_document_date_to_category(bool value) { add_document_date_to_category = value; } std::string Settings::get_sort_folder() const { return sort_folder; } void Settings::set_sort_folder(const std::string &path) { this->sort_folder = path; } bool Settings::get_consistency_pass_enabled() const { return consistency_pass_enabled; } void Settings::set_consistency_pass_enabled(bool value) { consistency_pass_enabled = value; } bool Settings::get_development_prompt_logging() const { return development_prompt_logging; } void Settings::set_development_prompt_logging(bool value) { development_prompt_logging = value; } bool Settings::get_use_whitelist() const { return use_whitelist; } void Settings::set_use_whitelist(bool value) { use_whitelist = value; } std::string Settings::get_active_whitelist() const { return active_whitelist; } void Settings::set_active_whitelist(const std::string& name) { active_whitelist = name; } void Settings::set_skipped_version(const std::string &version) { skipped_version = version; } std::string Settings::get_skipped_version() { return skipped_version; } void Settings::set_show_file_explorer(bool value) { show_file_explorer = value; } bool Settings::get_show_file_explorer() const { return show_file_explorer; } bool Settings::get_suitability_benchmark_completed() const { return suitability_benchmark_completed; } bool Settings::get_suitability_benchmark_suppressed() const { return suitability_benchmark_suppressed; } void Settings::set_suitability_benchmark_completed(bool value) { suitability_benchmark_completed = value; } void Settings::set_suitability_benchmark_suppressed(bool value) { suitability_benchmark_suppressed = value; } std::string Settings::get_benchmark_last_report() const { return benchmark_last_report; } void Settings::set_benchmark_last_report(const std::string& value) { benchmark_last_report = value; } std::string Settings::get_benchmark_last_run() const { return benchmark_last_run; } void Settings::set_benchmark_last_run(const std::string& value) { benchmark_last_run = value; } Language Settings::get_language() const { return language; } void Settings::set_language(Language value) { language = value; } int Settings::get_total_categorized_files() const { return categorized_file_count; } void Settings::add_categorized_files(int count) { if (count <= 0) { return; } categorized_file_count += count; } int Settings::get_next_support_prompt_threshold() const { return next_support_prompt_threshold; } void Settings::set_next_support_prompt_threshold(int threshold) { if (threshold < 50) { threshold = 50; } next_support_prompt_threshold = threshold; } std::vector Settings::get_allowed_categories() const { return allowed_categories; } void Settings::set_allowed_categories(std::vector values) { allowed_categories = std::move(values); } std::vector Settings::get_allowed_subcategories() const { return allowed_subcategories; } void Settings::set_allowed_subcategories(std::vector values) { allowed_subcategories = std::move(values); } ================================================ FILE: app/lib/SuitabilityBenchmarkDialog.cpp ================================================ #include "SuitabilityBenchmarkDialog.hpp" #include "DocumentTextAnalyzer.hpp" #include "ILLMClient.hpp" #include "LlavaImageAnalyzer.hpp" #include "LlmCatalog.hpp" #include "LocalLLMClient.hpp" #include "Settings.hpp" #include "Types.hpp" #include "Utils.hpp" #include "ggml-backend.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace { struct VisualLlmPaths { std::filesystem::path model_path; std::filesystem::path mmproj_path; }; std::optional resolve_visual_llm_paths(std::string* error); enum class PerfClass { Optimal, Acceptable, TooLong }; struct PerfThresholds { double optimal_max{0.0}; double acceptable_max{0.0}; }; std::string trim_copy(const std::string& value) { std::string trimmed = value; auto not_space = [](unsigned char ch) { return !std::isspace(ch); }; trimmed.erase(trimmed.begin(), std::find_if(trimmed.begin(), trimmed.end(), not_space)); trimmed.erase(std::find_if(trimmed.rbegin(), trimmed.rend(), not_space).base(), trimmed.end()); return trimmed; } std::string format_duration(std::chrono::steady_clock::duration elapsed) { using namespace std::chrono; const double seconds = duration_cast(elapsed).count() / 1000.0; std::ostringstream oss; oss << std::fixed << std::setprecision(1) << seconds << "s"; return oss.str(); } double duration_seconds(std::chrono::steady_clock::duration elapsed) { using namespace std::chrono; return duration_cast(elapsed).count() / 1000.0; } std::string format_seconds(double seconds) { std::ostringstream oss; oss << std::fixed << std::setprecision(1) << seconds << "s"; return oss.str(); } double read_env_double(const char* key, double fallback) { const char* value = std::getenv(key); if (!value || !*value) { return fallback; } try { size_t idx = 0; const double parsed = std::stod(value, &idx); if (idx == 0) { return fallback; } return parsed; } catch (const std::exception&) { return fallback; } } PerfThresholds thresholds_for_choice(LLMChoice choice) { switch (choice) { case LLMChoice::Local_3b: return PerfThresholds{ read_env_double("BENCH_CAT_LOCAL_3B_OPTIMAL_MAX", 2.0), read_env_double("BENCH_CAT_LOCAL_3B_ACCEPTABLE_MAX", 5.0)}; case LLMChoice::Local_3b_legacy: return PerfThresholds{ read_env_double("BENCH_CAT_LOCAL_3B_LEGACY_OPTIMAL_MAX", 5.0), read_env_double("BENCH_CAT_LOCAL_3B_LEGACY_ACCEPTABLE_MAX", 10.0)}; case LLMChoice::Local_7b: return PerfThresholds{ read_env_double("BENCH_CAT_LOCAL_7B_OPTIMAL_MAX", 8.0), read_env_double("BENCH_CAT_LOCAL_7B_ACCEPTABLE_MAX", 12.0)}; default: return PerfThresholds{ read_env_double("BENCH_CAT_DEFAULT_OPTIMAL_MAX", 5.0), read_env_double("BENCH_CAT_DEFAULT_ACCEPTABLE_MAX", 10.0)}; } } PerfThresholds thresholds_for_document_choice(LLMChoice choice) { switch (choice) { case LLMChoice::Local_3b: return PerfThresholds{ read_env_double("BENCH_DOC_LOCAL_3B_OPTIMAL_MAX", 4.0), read_env_double("BENCH_DOC_LOCAL_3B_ACCEPTABLE_MAX", 7.0)}; case LLMChoice::Local_3b_legacy: return PerfThresholds{ read_env_double("BENCH_DOC_LOCAL_3B_LEGACY_OPTIMAL_MAX", 8.0), read_env_double("BENCH_DOC_LOCAL_3B_LEGACY_ACCEPTABLE_MAX", 12.0)}; case LLMChoice::Local_7b: return PerfThresholds{ read_env_double("BENCH_DOC_LOCAL_7B_OPTIMAL_MAX", 12.0), read_env_double("BENCH_DOC_LOCAL_7B_ACCEPTABLE_MAX", 15.0)}; default: return PerfThresholds{ read_env_double("BENCH_DOC_DEFAULT_OPTIMAL_MAX", 8.0), read_env_double("BENCH_DOC_DEFAULT_ACCEPTABLE_MAX", 12.0)}; } } PerfThresholds image_thresholds() { return PerfThresholds{ read_env_double("BENCH_IMAGE_OPTIMAL_MAX", 15.0), read_env_double("BENCH_IMAGE_ACCEPTABLE_MAX", 25.0)}; } PerfClass classify_perf(double seconds, const PerfThresholds& thresholds) { if (seconds <= thresholds.optimal_max) { return PerfClass::Optimal; } if (seconds <= thresholds.acceptable_max) { return PerfClass::Acceptable; } return PerfClass::TooLong; } int perf_rank(PerfClass perf) { switch (perf) { case PerfClass::Optimal: return 0; case PerfClass::Acceptable: return 1; case PerfClass::TooLong: return 2; } return 2; } PerfClass worst_perf(PerfClass a, PerfClass b) { return perf_rank(a) >= perf_rank(b) ? a : b; } QString perf_color(PerfClass perf) { switch (perf) { case PerfClass::Optimal: return QStringLiteral("#1f6feb"); case PerfClass::Acceptable: return QStringLiteral("#f2c200"); case PerfClass::TooLong: return QStringLiteral("#d73a49"); } return QStringLiteral("#1f6feb"); } QString highlight_figures(const QString& text) { static const QRegularExpression figure_pattern(QStringLiteral(R"(\b\d+(?:\.\d+)?\s*(?:MiB|s)\b)")); const QString escaped = text.toHtmlEscaped(); QString result; result.reserve(escaped.size() + 32); int last_pos = 0; auto match_it = figure_pattern.globalMatch(escaped); while (match_it.hasNext()) { const auto match = match_it.next(); const int start = match.capturedStart(); const int end = match.capturedEnd(); if (start < last_pos) { continue; } result += escaped.mid(last_pos, start - last_pos); result += QStringLiteral("%1").arg(match.captured(0)); last_pos = end; } result += escaped.mid(last_pos); return result; } QString bold_llm_label(const std::string& label) { return QStringLiteral("%1").arg(QString::fromStdString(label).toHtmlEscaped()); } QString colored_seconds(double seconds, PerfClass perf) { return QStringLiteral("%2") .arg(perf_color(perf)) .arg(QString::fromStdString(format_seconds(seconds))); } QString colored_seconds_list(const std::vector& seconds, const std::function& classifier) { QStringList parts; parts.reserve(static_cast(seconds.size())); for (double value : seconds) { const PerfClass perf = classifier(value); parts << colored_seconds(value, perf); } return parts.join(QStringLiteral(", ")); } std::string format_mib(size_t bytes) { constexpr double kToMiB = 1024.0 * 1024.0; std::ostringstream oss; oss << std::fixed << std::setprecision(1) << (static_cast(bytes) / kToMiB) << " MiB"; return oss.str(); } std::string to_lower_copy(std::string value) { std::transform(value.begin(), value.end(), value.begin(), [](unsigned char ch) { return static_cast(std::tolower(ch)); }); return value; } std::string read_env_lower(const char* key) { const char* value = std::getenv(key); if (!value || !*value) { return {}; } return to_lower_copy(value); } std::optional read_env_value(const char* key) { const char* value = std::getenv(key); if (!value) { return std::nullopt; } return std::string(value); } void set_env_value(const char* key, const std::optional& value) { #if defined(_WIN32) if (value.has_value()) { _putenv_s(key, value->c_str()); } else { _putenv_s(key, ""); } #else if (value.has_value()) { setenv(key, value->c_str(), 1); } else { unsetenv(key); } #endif } bool case_insensitive_contains(std::string_view haystack, std::string_view needle) { if (needle.empty()) { return true; } const std::string hay = to_lower_copy(std::string(haystack)); const std::string nee = to_lower_copy(std::string(needle)); return hay.find(nee) != std::string::npos; } std::string format_timestamp(std::chrono::system_clock::time_point point) { std::time_t time_value = std::chrono::system_clock::to_time_t(point); std::tm local_time{}; #if defined(_WIN32) localtime_s(&local_time, &time_value); #else localtime_r(&time_value, &local_time); #endif std::ostringstream oss; oss << std::put_time(&local_time, "%Y-%m-%d %H:%M:%S"); return oss.str(); } struct DefaultModel { std::string label; std::filesystem::path path; LLMChoice choice; }; struct BackendTarget { std::string key; std::string label; }; struct BenchmarkBackendInfo { bool cuda_available{false}; bool vulkan_available{false}; bool metal_available{false}; std::string vulkan_device; std::string metal_device; std::optional blas_label; }; struct EnvEntry { std::string key; std::optional value; }; class EnvSnapshot { public: static EnvSnapshot capture(const std::array& keys) { EnvSnapshot snapshot; for (const char* key : keys) { snapshot.entries_.push_back(EnvEntry{key, read_env_value(key)}); } return snapshot; } void restore() const { for (const auto& entry : entries_) { set_env_value(entry.key.c_str(), entry.value); } } private: std::vector entries_; }; class ScopedEnvRestore { public: explicit ScopedEnvRestore(const EnvSnapshot& snapshot) : snapshot_(snapshot) { } ~ScopedEnvRestore() { snapshot_.restore(); } private: const EnvSnapshot& snapshot_; }; BackendTarget resolve_backend_target(std::string_view override_value) { if (override_value == "cpu") { return {"cpu", QObject::tr("CPU").toStdString()}; } if (override_value == "metal") { return {"metal", QObject::tr("Metal").toStdString()}; } if (override_value == "cuda") { return {"cuda", QObject::tr("CUDA").toStdString()}; } if (override_value == "vulkan") { return {"vulkan", QObject::tr("Vulkan").toStdString()}; } if (override_value == "auto") { #if defined(__APPLE__) return {"metal", QObject::tr("Metal (auto)").toStdString()}; #else return {"vulkan", QObject::tr("Vulkan (auto)").toStdString()}; #endif } if (!override_value.empty()) { return {"auto", QObject::tr("%1 (auto)").arg(QString::fromStdString(std::string(override_value))).toStdString()}; } #if defined(__APPLE__) return {"metal", QObject::tr("Metal (auto)").toStdString()}; #else return {"vulkan", QObject::tr("Vulkan (auto)").toStdString()}; #endif } std::string format_backend_label(std::string_view name) { if (name.empty()) { return QObject::tr("Auto").toStdString(); } const std::string lowered = to_lower_copy(std::string(name)); if (lowered == "vulkan") { return QObject::tr("Vulkan").toStdString(); } if (lowered == "cuda") { return QObject::tr("CUDA").toStdString(); } if (lowered == "metal") { return QObject::tr("Metal").toStdString(); } if (lowered == "cpu") { return QObject::tr("CPU").toStdString(); } return std::string(name); } std::optional resolve_default_model_path(const char* env_var) { const char* url = std::getenv(env_var); if (!url || !*url) { return std::nullopt; } try { std::filesystem::path path = Utils::make_default_path_to_file_from_download_url(url); if (std::filesystem::exists(path)) { return path; } } catch (...) { return std::nullopt; } return std::nullopt; } std::vector collect_default_models() { std::vector models; std::unordered_set seen; for (const auto& entry : default_llm_entries()) { auto path = resolve_default_model_path(entry.url_env); if (!path) { continue; } const std::string path_key = path->string(); if (!seen.insert(path_key).second) { continue; } models.push_back(DefaultModel{default_llm_label(entry).toStdString(), *path, entry.choice}); } return models; } void load_ggml_backends_once(); std::optional detect_blas_backend_label() { load_ggml_backends_once(); const size_t device_count = ggml_backend_dev_count(); for (size_t i = 0; i < device_count; ++i) { auto* device = ggml_backend_dev_get(i); if (!device) { continue; } const auto type = ggml_backend_dev_type(device); if (type != GGML_BACKEND_DEVICE_TYPE_ACCEL && type != GGML_BACKEND_DEVICE_TYPE_CPU) { continue; } const char* dev_name = ggml_backend_dev_name(device); const char* dev_desc = ggml_backend_dev_description(device); auto* reg = ggml_backend_dev_backend_reg(device); const char* reg_name = reg ? ggml_backend_reg_name(reg) : nullptr; auto matches = [&](std::string_view needle) { return case_insensitive_contains(dev_name ? dev_name : "", needle) || case_insensitive_contains(dev_desc ? dev_desc : "", needle) || case_insensitive_contains(reg_name ? reg_name : "", needle); }; if (matches("openblas")) { return std::string("OpenBLAS"); } if (matches("accelerate")) { return std::string("Accelerate"); } if (matches("mkl")) { return std::string("MKL"); } if (matches("blis")) { return std::string("BLIS"); } if (matches("blas")) { return std::string("BLAS"); } } return std::nullopt; } struct BackendMemorySnapshot { size_t free_bytes{0}; size_t total_bytes{0}; std::string name; }; void load_ggml_backends_once() { static bool loaded = false; if (loaded) { return; } const char* ggml_dir = std::getenv("AI_FILE_SORTER_GGML_DIR"); if (ggml_dir && *ggml_dir) { ggml_backend_load_all_from_path(ggml_dir); } else { ggml_backend_load_all(); } loaded = true; } std::optional query_backend_memory(std::string_view backend_name) { load_ggml_backends_once(); const size_t device_count = ggml_backend_dev_count(); BackendMemorySnapshot best{}; bool found = false; for (size_t i = 0; i < device_count; ++i) { auto* device = ggml_backend_dev_get(i); if (!device) { continue; } if (ggml_backend_dev_type(device) != GGML_BACKEND_DEVICE_TYPE_GPU) { continue; } auto* reg = ggml_backend_dev_backend_reg(device); const char* reg_name = reg ? ggml_backend_reg_name(reg) : nullptr; if (!case_insensitive_contains(reg_name ? reg_name : "", backend_name)) { continue; } size_t free_bytes = 0; size_t total_bytes = 0; ggml_backend_dev_memory(device, &free_bytes, &total_bytes); if (free_bytes == 0 && total_bytes == 0) { continue; } if (!found || total_bytes > best.total_bytes) { best.free_bytes = free_bytes; best.total_bytes = (total_bytes != 0) ? total_bytes : free_bytes; const char* dev_name = ggml_backend_dev_name(device); best.name = dev_name ? dev_name : ""; found = true; } } if (found) { return best; } return std::nullopt; } bool is_backend_available(std::string_view backend_name) { load_ggml_backends_once(); const std::string name(backend_name); ggml_backend_reg_t reg = ggml_backend_reg_by_name(name.c_str()); if (!reg) { return false; } return ggml_backend_reg_dev_count(reg) > 0; } QString build_cpu_backend_note(const QString& reason, const std::optional& blas_label) { QString details = reason; if (blas_label.has_value()) { if (!details.isEmpty()) { details += QStringLiteral("; "); } details += QString::fromStdString(*blas_label); } if (details.isEmpty()) { return QObject::tr("CPU"); } return QObject::tr("CPU (%1)").arg(details); } QString build_gpu_backend_note(const BackendTarget& target) { return QObject::tr("GPU (target: %1)").arg(QString::fromStdString(target.label)); } QString build_backend_note(const BackendTarget& target, const BenchmarkBackendInfo& info, bool gpu_fallback) { if (target.key == "cpu") { return build_cpu_backend_note(QString(), info.blas_label); } if (gpu_fallback) { QString reason; if (target.key == "vulkan" && !info.vulkan_available) { reason = QObject::tr("GPU via Vulkan unavailable"); } else if (target.key == "cuda" && !info.cuda_available) { reason = QObject::tr("GPU via CUDA unavailable"); if (!info.vulkan_available) { reason += QStringLiteral("; ") + QObject::tr("Vulkan unavailable"); } } else if (target.key == "metal" && !info.metal_available) { reason = QObject::tr("GPU via Metal unavailable"); } else { reason = QObject::tr("GPU init failed"); } return build_cpu_backend_note(reason, info.blas_label); } return build_gpu_backend_note(target); } std::string join_duration_list(const std::vector& seconds) { std::ostringstream oss; for (size_t i = 0; i < seconds.size(); ++i) { if (i > 0) { oss << ", "; } oss << format_seconds(seconds[i]); } return oss.str(); } double median_seconds(std::vector seconds) { if (seconds.empty()) { return 0.0; } std::sort(seconds.begin(), seconds.end()); const size_t mid = seconds.size() / 2; if (seconds.size() % 2 == 1) { return seconds[mid]; } return (seconds[mid - 1] + seconds[mid]) / 2.0; } bool has_visual_llm_files() { return resolve_visual_llm_paths(nullptr).has_value(); } bool has_any_llm_available() { return !collect_default_models().empty() || has_visual_llm_files(); } std::filesystem::path create_temp_dir() { auto ensure_writable_dir = [](const std::filesystem::path& dir) { std::error_code ec; std::filesystem::create_directories(dir, ec); if (ec || !std::filesystem::exists(dir)) { return false; } const std::filesystem::path probe = dir / ".aifs-write-probe"; std::ofstream out(probe, std::ios::out | std::ios::trunc); if (!out) { return false; } out << "ok"; out.close(); std::filesystem::remove(probe, ec); return true; }; std::vector roots; std::error_code ec; std::filesystem::path temp_root = std::filesystem::temp_directory_path(ec); if (!ec && !temp_root.empty()) { roots.push_back(temp_root); } if (const char* tmpdir = std::getenv("TMPDIR"); tmpdir && *tmpdir) { roots.emplace_back(tmpdir); } if (const char* home = std::getenv("HOME"); home && *home) { roots.emplace_back(std::filesystem::path(home) / ".cache"); } ec.clear(); std::filesystem::path cwd = std::filesystem::current_path(ec); if (!ec && !cwd.empty()) { roots.push_back(cwd); } const auto stamp = std::chrono::duration_cast( std::chrono::system_clock::now().time_since_epoch()).count(); for (const auto& root : roots) { std::filesystem::path base = root / "aifs-benchmark"; if (!ensure_writable_dir(base)) { continue; } for (int attempt = 0; attempt < 16; ++attempt) { std::filesystem::path run_dir = base / ("run-" + std::to_string(stamp) + "-" + std::to_string(attempt)); if (ensure_writable_dir(run_dir)) { return run_dir; } } } return std::filesystem::path(); } bool write_sample_document(const std::filesystem::path& path) { std::error_code ec; std::filesystem::create_directories(path.parent_path(), ec); if (ec) { return false; } std::ofstream out(path); if (!out) { return false; } out << "Project Phoenix Q1 Summary\n"; out << "This report covers milestones, risks, and budget updates for Q1 2025.\n"; out << "Key topics include cloud migration, incident response, and hiring plans.\n"; out << "Overall progress is steady with a focus on cost optimization and delivery timelines.\n"; return static_cast(out); } bool write_sample_image(const std::filesystem::path& path) { std::error_code ec; std::filesystem::create_directories(path.parent_path(), ec); if (ec) { return false; } QImage image(96, 96, QImage::Format_RGB32); image.fill(QColor(30, 120, 200)); QPainter painter(&image); painter.fillRect(QRect(18, 18, 60, 60), QColor(240, 200, 60)); painter.end(); return image.save(QString::fromStdString(path.string()), "PNG"); } std::optional resolve_mmproj_path(const std::filesystem::path& primary) { if (std::filesystem::exists(primary)) { return primary; } const auto llm_dir = std::filesystem::path(Utils::get_default_llm_destination()); static const char* kAltMmprojNames[] = { "mmproj-model-f16.gguf", "llava-v1.6-mistral-7b-mmproj-f16.gguf" }; for (const char* alt_name : kAltMmprojNames) { const auto candidate = llm_dir / alt_name; if (std::filesystem::exists(candidate)) { return candidate; } } return std::nullopt; } std::optional resolve_visual_llm_paths(std::string* error) { const char* model_url = std::getenv("LLAVA_MODEL_URL"); const char* mmproj_url = std::getenv("LLAVA_MMPROJ_URL"); if (!model_url || !*model_url || !mmproj_url || !*mmproj_url) { if (error) { *error = "Missing visual LLM download URLs."; } return std::nullopt; } std::filesystem::path model_path; std::filesystem::path mmproj_primary; try { model_path = std::filesystem::path(Utils::make_default_path_to_file_from_download_url(model_url)); mmproj_primary = std::filesystem::path(Utils::make_default_path_to_file_from_download_url(mmproj_url)); } catch (...) { if (error) { *error = "Failed to resolve visual LLM file paths."; } return std::nullopt; } if (!std::filesystem::exists(model_path)) { if (error) { *error = "Visual LLM model file is missing."; } return std::nullopt; } auto mmproj_path = resolve_mmproj_path(mmproj_primary); if (!mmproj_path) { if (error) { *error = "Visual LLM mmproj file is missing."; } return std::nullopt; } return VisualLlmPaths{model_path, *mmproj_path}; } bool should_use_visual_gpu() { const char* backend = std::getenv("AI_FILE_SORTER_GPU_BACKEND"); if (!backend || !*backend) { return true; } std::string lowered = backend; std::transform(lowered.begin(), lowered.end(), lowered.begin(), [](unsigned char ch) { return static_cast(std::tolower(ch)); }); return lowered != "cpu"; } std::optional> parse_category_pair(const std::string& response) { std::istringstream stream(response); std::string line; std::string category; std::string subcategory; while (std::getline(stream, line)) { std::string trimmed = trim_copy(line); if (trimmed.empty()) { continue; } if (trimmed.rfind("Category", 0) == 0) { const auto pos = trimmed.find(':'); if (pos != std::string::npos) { category = trim_copy(trimmed.substr(pos + 1)); } continue; } if (trimmed.rfind("Subcategory", 0) == 0) { const auto pos = trimmed.find(':'); if (pos != std::string::npos) { subcategory = trim_copy(trimmed.substr(pos + 1)); } continue; } if (!trimmed.empty() && (trimmed.front() == '-' || trimmed.front() == '*')) { trimmed = trim_copy(trimmed.substr(1)); } size_t pos = trimmed.find(" : "); size_t delim_len = 0; if (pos != std::string::npos) { delim_len = 3; } else { pos = trimmed.find(':'); delim_len = (pos != std::string::npos) ? 1 : 0; } if (pos != std::string::npos && delim_len > 0) { const std::string raw_category = trim_copy(trimmed.substr(0, pos)); const std::string raw_subcategory = trim_copy(trimmed.substr(pos + delim_len)); if (!raw_category.empty() && !raw_subcategory.empty()) { category = Utils::sanitize_path_label(raw_category); subcategory = Utils::sanitize_path_label(raw_subcategory); break; } } } if (!category.empty() && !subcategory.empty()) { return std::make_pair(category, subcategory); } return std::nullopt; } struct StepResult { bool success{false}; bool skipped{false}; std::string detail; std::chrono::steady_clock::duration duration{}; }; struct TextModelOutcome { bool skipped{true}; bool categorization_ok{false}; bool document_ok{false}; std::optional categorization_perf; std::optional document_perf; struct ModelPerf { std::string label; LLMChoice choice{LLMChoice::Unset}; PerfClass cat_perf{PerfClass::TooLong}; PerfClass doc_perf{PerfClass::TooLong}; double cat_median{0.0}; double doc_median{0.0}; }; std::vector model_results; }; StepResult run_categorization_test(ILLMClient& llm, const std::filesystem::path& temp_dir) { StepResult result; const auto start = std::chrono::steady_clock::now(); try { const std::string file_name = "Quarterly_Report_Q1_2025.pdf"; const std::filesystem::path file_path = temp_dir / file_name; const std::string response = llm.categorize_file(file_name, file_path.string(), FileType::File, std::string()); const auto parsed = parse_category_pair(response); result.success = parsed.has_value(); if (!result.success) { result.detail = "Unexpected response format."; } } catch (const std::exception& ex) { result.detail = ex.what(); } result.duration = std::chrono::steady_clock::now() - start; return result; } StepResult run_document_test(ILLMClient& llm, const std::filesystem::path& temp_dir) { StepResult result; if (temp_dir.empty()) { result.detail = "No writable temporary directory available."; return result; } const std::filesystem::path doc_path = temp_dir / "benchmark_document.txt"; if (!write_sample_document(doc_path)) { result.detail = "Failed to create sample document."; return result; } const auto start = std::chrono::steady_clock::now(); try { DocumentTextAnalyzer analyzer; const auto analysis = analyzer.analyze(doc_path, llm); result.success = !analysis.suggested_name.empty(); if (!result.success) { result.detail = "Empty suggestion."; } } catch (const std::exception& ex) { result.detail = ex.what(); } result.duration = std::chrono::steady_clock::now() - start; return result; } StepResult run_image_test(const std::filesystem::path& temp_dir) { StepResult result; #if defined(AI_FILE_SORTER_HAS_MTMD) if (temp_dir.empty()) { result.detail = "No writable temporary directory available."; return result; } std::string visual_error; auto visual_paths = resolve_visual_llm_paths(&visual_error); if (!visual_paths) { result.skipped = true; result.detail = visual_error.empty() ? "Visual LLM files unavailable." : visual_error; return result; } const std::filesystem::path image_path = temp_dir / "benchmark_image.png"; if (!write_sample_image(image_path)) { result.detail = "Failed to create sample image."; return result; } const auto start = std::chrono::steady_clock::now(); try { LlavaImageAnalyzer::Settings settings; settings.use_gpu = should_use_visual_gpu(); LlavaImageAnalyzer analyzer(visual_paths->model_path, visual_paths->mmproj_path, settings); const auto analysis = analyzer.analyze(image_path); result.success = !analysis.suggested_name.empty(); if (!result.success) { result.detail = "Empty suggestion."; } } catch (const std::exception& ex) { result.detail = ex.what(); } result.duration = std::chrono::steady_clock::now() - start; #else result.skipped = true; result.detail = "Visual LLM support is not available in this build."; #endif return result; } TextModelOutcome run_text_model_checks(const std::vector& models, const std::filesystem::path& temp_dir, const EnvSnapshot& baseline_env, const BenchmarkBackendInfo& backend_info, const std::function& post_line, const std::function& post_line_html, const std::function& should_stop) { TextModelOutcome outcome; constexpr int kPerItemRuns = 3; if (models.empty()) { return outcome; } outcome.skipped = false; outcome.categorization_ok = true; outcome.document_ok = true; bool first_model = true; for (const auto& model : models) { if (should_stop && should_stop()) { break; } baseline_env.restore(); ScopedEnvRestore env_restore(baseline_env); if (post_line) { if (!first_model) { post_line(QStringLiteral("----")); } if (post_line_html) { post_line_html(QObject::tr("Default model: %1").arg(bold_llm_label(model.label))); } else { post_line(QObject::tr("Default model: %1").arg(QString::fromStdString(model.label))); } } try { LocalLLMClient client(model.path.string()); StepResult cat_warm; StepResult cat_init; std::vector cat_runs; StepResult doc_warm; StepResult doc_init; std::vector doc_runs; bool status_fallback = false; client.set_status_callback([&status_fallback](LocalLLMClient::Status status) { if (status == LocalLLMClient::Status::GpuFallbackToCpu) { status_fallback = true; } }); const std::string backend_before_cat = read_env_lower("AI_FILE_SORTER_GPU_BACKEND"); const BackendTarget cat_target = resolve_backend_target(backend_before_cat); if (post_line) { post_line(QObject::tr(" Measuring categorization (warm-up + %1 run(s))...") .arg(kPerItemRuns + 1)); } cat_warm = run_categorization_test(client, temp_dir); if (should_stop && should_stop()) { return outcome; } cat_init = run_categorization_test(client, temp_dir); if (should_stop && should_stop()) { return outcome; } cat_runs.reserve(static_cast(kPerItemRuns)); for (int i = 0; i < kPerItemRuns; ++i) { cat_runs.push_back(run_categorization_test(client, temp_dir)); if (should_stop && should_stop()) { return outcome; } } const std::string backend_after_cat = read_env_lower("AI_FILE_SORTER_GPU_BACKEND"); const bool env_fallback_cat = (cat_target.key != "cpu" && backend_after_cat == "cpu"); const bool cat_fallback = status_fallback || env_fallback_cat; bool cat_success = cat_warm.success && cat_init.success; for (const auto& run : cat_runs) { cat_success = cat_success && run.success; } status_fallback = false; const std::string backend_before_doc = read_env_lower("AI_FILE_SORTER_GPU_BACKEND"); const BackendTarget doc_target = resolve_backend_target(backend_before_doc); if (post_line) { post_line(QObject::tr(" Measuring document analysis (warm-up + %1 run(s))...") .arg(kPerItemRuns + 1)); } doc_warm = run_document_test(client, temp_dir); if (should_stop && should_stop()) { return outcome; } doc_init = run_document_test(client, temp_dir); if (should_stop && should_stop()) { return outcome; } doc_runs.reserve(static_cast(kPerItemRuns)); for (int i = 0; i < kPerItemRuns; ++i) { doc_runs.push_back(run_document_test(client, temp_dir)); if (should_stop && should_stop()) { return outcome; } } const std::string backend_after_doc = read_env_lower("AI_FILE_SORTER_GPU_BACKEND"); const bool env_fallback_doc = (doc_target.key != "cpu" && backend_after_doc == "cpu"); const bool doc_fallback = status_fallback || env_fallback_doc; bool doc_success = doc_warm.success && doc_init.success; for (const auto& run : doc_runs) { doc_success = doc_success && run.success; } outcome.categorization_ok = outcome.categorization_ok && cat_success; outcome.document_ok = outcome.document_ok && doc_success; std::vector cat_per_seconds; cat_per_seconds.reserve(cat_runs.size()); for (const auto& run : cat_runs) { cat_per_seconds.push_back(duration_seconds(run.duration)); } const double cat_median = median_seconds(cat_per_seconds); const PerfClass cat_perf = classify_perf(cat_median, thresholds_for_choice(model.choice)); outcome.categorization_perf = outcome.categorization_perf.has_value() ? std::optional(worst_perf(*outcome.categorization_perf, cat_perf)) : std::optional(cat_perf); std::vector doc_per_seconds; doc_per_seconds.reserve(doc_runs.size()); for (const auto& run : doc_runs) { doc_per_seconds.push_back(duration_seconds(run.duration)); } const double doc_median = median_seconds(doc_per_seconds); const PerfClass doc_perf = classify_perf(doc_median, thresholds_for_document_choice(model.choice)); outcome.document_perf = outcome.document_perf.has_value() ? std::optional(worst_perf(*outcome.document_perf, doc_perf)) : std::optional(doc_perf); outcome.model_results.push_back(TextModelOutcome::ModelPerf{ model.label, model.choice, cat_perf, doc_perf, cat_median, doc_median }); if (post_line) { post_line(QObject::tr("Categorization: %1") .arg(cat_success ? QObject::tr("done") : QObject::tr("failed"))); if (post_line_html) { post_line_html(QObject::tr(" Warm-up: %1") .arg(colored_seconds(duration_seconds(cat_warm.duration), PerfClass::Optimal))); post_line_html(QObject::tr(" Init: %1") .arg(colored_seconds(duration_seconds(cat_init.duration), PerfClass::Optimal))); post_line_html(QObject::tr(" Per-item (median of %1): %2") .arg(cat_per_seconds.size()) .arg(colored_seconds(cat_median, cat_perf))); post_line_html(QObject::tr(" Per-item runs: %1") .arg(colored_seconds_list( cat_per_seconds, [model](double value) { return classify_perf(value, thresholds_for_choice(model.choice)); }))); } else { post_line(QObject::tr(" Warm-up: %1") .arg(QString::fromStdString(format_duration(cat_warm.duration)))); post_line(QObject::tr(" Init: %1") .arg(QString::fromStdString(format_duration(cat_init.duration)))); post_line(QObject::tr(" Per-item (median of %1): %2") .arg(cat_per_seconds.size()) .arg(QString::fromStdString(format_seconds(cat_median)))); post_line(QObject::tr(" Per-item runs: %1") .arg(QString::fromStdString(join_duration_list(cat_per_seconds)))); } if (!cat_success) { std::string detail = cat_warm.detail; if (detail.empty()) { detail = cat_init.detail; } if (detail.empty()) { for (const auto& run : cat_runs) { if (!run.detail.empty()) { detail = run.detail; break; } } } if (!detail.empty()) { post_line(QObject::tr("Details: %1").arg(QString::fromStdString(detail))); } } post_line(QObject::tr("Backend used: %1") .arg(build_backend_note(cat_target, backend_info, cat_fallback))); post_line(QObject::tr("Document analysis: %1") .arg(doc_success ? QObject::tr("done") : QObject::tr("failed"))); if (post_line_html) { post_line_html(QObject::tr(" Warm-up: %1") .arg(colored_seconds(duration_seconds(doc_warm.duration), PerfClass::Optimal))); post_line_html(QObject::tr(" Init: %1") .arg(colored_seconds(duration_seconds(doc_init.duration), PerfClass::Optimal))); post_line_html(QObject::tr(" Per-item (median of %1): %2") .arg(doc_per_seconds.size()) .arg(colored_seconds(doc_median, doc_perf))); post_line_html(QObject::tr(" Per-item runs: %1") .arg(colored_seconds_list( doc_per_seconds, [model](double value) { return classify_perf(value, thresholds_for_document_choice(model.choice)); }))); } else { post_line(QObject::tr(" Warm-up: %1") .arg(QString::fromStdString(format_duration(doc_warm.duration)))); post_line(QObject::tr(" Init: %1") .arg(QString::fromStdString(format_duration(doc_init.duration)))); post_line(QObject::tr(" Per-item (median of %1): %2") .arg(doc_per_seconds.size()) .arg(QString::fromStdString(format_seconds(doc_median)))); post_line(QObject::tr(" Per-item runs: %1") .arg(QString::fromStdString(join_duration_list(doc_per_seconds)))); } if (!doc_success) { std::string detail = doc_warm.detail; if (detail.empty()) { detail = doc_init.detail; } if (detail.empty()) { for (const auto& run : doc_runs) { if (!run.detail.empty()) { detail = run.detail; break; } } } if (!detail.empty()) { post_line(QObject::tr("Details: %1").arg(QString::fromStdString(detail))); } } post_line(QObject::tr("Backend used: %1") .arg(build_backend_note(doc_target, backend_info, doc_fallback))); } } catch (const std::exception& ex) { outcome.categorization_ok = false; outcome.document_ok = false; if (post_line) { post_line(QObject::tr("Model failed to load: %1") .arg(QString::fromStdString(ex.what()))); } } first_model = false; } return outcome; } QString perf_label_qt(PerfClass perf) { switch (perf) { case PerfClass::Optimal: return QObject::tr("optimal"); case PerfClass::Acceptable: return QObject::tr("acceptable"); case PerfClass::TooLong: return QObject::tr("a bit long"); } return QObject::tr("a bit long"); } QString colored_perf_label(PerfClass perf) { return QStringLiteral("%2") .arg(perf_color(perf)) .arg(perf_label_qt(perf)); } QString build_recommended_list(const QStringList& labels) { QStringList items; items.reserve(labels.size()); for (const auto& label : labels) { const QString trimmed = label.trimmed(); if (!trimmed.isEmpty()) { items << trimmed; } } if (items.empty()) { items << QObject::tr("n/a"); } QString html; for (int i = 0; i < items.size(); ++i) { if (i > 0) { html += QStringLiteral("
"); } html += QStringLiteral("- %1").arg(items[i].toHtmlEscaped()); } return html; } QStringList build_result_lines(const TextModelOutcome& text_models, const StepResult& image) { QStringList lines; lines << QStringLiteral("%1") .arg(QObject::tr("Result")); if (text_models.skipped) { lines << QObject::tr("Categorization speed: unavailable"); lines << QObject::tr("Document analysis speed: unavailable"); } else { PerfClass cat_perf = PerfClass::TooLong; PerfClass doc_perf = PerfClass::TooLong; for (const auto& entry : text_models.model_results) { if (perf_rank(entry.cat_perf) < perf_rank(cat_perf)) { cat_perf = entry.cat_perf; } if (perf_rank(entry.doc_perf) < perf_rank(doc_perf)) { doc_perf = entry.doc_perf; } } lines << QObject::tr("Categorization speed: %1").arg(colored_perf_label(cat_perf)); lines << QObject::tr("Document analysis speed: %1").arg(colored_perf_label(doc_perf)); } if (image.skipped) { lines << QObject::tr("Image analysis speed: unavailable"); } else if (image.success) { const double seconds = duration_seconds(image.duration); const PerfClass image_perf = classify_perf(seconds, image_thresholds()); lines << QObject::tr("Image analysis speed: %1").arg(colored_perf_label(image_perf)); } else { lines << QObject::tr("Image analysis speed: %1").arg(colored_perf_label(PerfClass::TooLong)); } QStringList recommended_labels; if (!text_models.model_results.empty()) { std::vector optimal; std::vector acceptable; std::vector quite_long; for (const auto& entry : text_models.model_results) { if (entry.cat_perf == PerfClass::Optimal && entry.doc_perf == PerfClass::Optimal) { optimal.push_back(&entry); } else if (entry.cat_perf != PerfClass::TooLong && entry.doc_perf != PerfClass::TooLong) { acceptable.push_back(&entry); } else { quite_long.push_back(&entry); } } if (optimal.size() == 1) { recommended_labels << QString::fromStdString(optimal.front()->label); } else if (optimal.size() > 1) { for (const auto* entry : optimal) { recommended_labels << QString::fromStdString(entry->label); } } else if (acceptable.size() == 1) { recommended_labels << QString::fromStdString(acceptable.front()->label); } else if (acceptable.size() > 1) { for (const auto* entry : acceptable) { recommended_labels << QString::fromStdString(entry->label); } } else if (!quite_long.empty()) { double best_score = std::numeric_limits::max(); for (const auto* entry : quite_long) { const double score = entry->cat_median + entry->doc_median; best_score = std::min(best_score, score); } for (const auto* entry : quite_long) { const double score = entry->cat_median + entry->doc_median; if (std::abs(score - best_score) < 0.0001) { recommended_labels << QString::fromStdString(entry->label); } } } } lines << QString(); const QString recommended_header = QObject::tr("Recommended Local LLM choice: %1").arg(QString()); lines << QStringLiteral("%1") .arg(recommended_header.toHtmlEscaped()); lines << build_recommended_list(recommended_labels); lines << QString(); lines << QStringLiteral("%1") .arg(QObject::tr("You can toggle LLMs in Settings -> Select LLM").toHtmlEscaped()); return lines; } } // namespace SuitabilityBenchmarkDialog::SuitabilityBenchmarkDialog(Settings& settings, QWidget* parent) : QDialog(parent) , settings_(settings) { resize(820, 560); setup_ui(); retranslate_ui(); load_previous_results(); } SuitabilityBenchmarkDialog::~SuitabilityBenchmarkDialog() { if (worker_.joinable()) { worker_.join(); } } void SuitabilityBenchmarkDialog::setup_ui() { auto* layout = new QVBoxLayout(this); intro_label_ = new QLabel(this); intro_label_->setTextFormat(Qt::RichText); intro_label_->setWordWrap(true); layout->addWidget(intro_label_); output_view_ = new QTextEdit(this); output_view_->setReadOnly(true); output_view_->setAcceptRichText(true); output_view_->setLineWrapMode(QTextEdit::WidgetWidth); layout->addWidget(output_view_, 1); progress_bar_ = new QProgressBar(this); progress_bar_->setVisible(false); progress_bar_->setRange(0, 0); layout->addWidget(progress_bar_); auto* button_layout = new QHBoxLayout(); suppress_checkbox_ = new QCheckBox(this); suppress_checkbox_->setChecked(settings_.get_suitability_benchmark_suppressed()); button_layout->addWidget(suppress_checkbox_); button_layout->addStretch(1); stop_button_ = new QPushButton(this); stop_button_->setEnabled(false); button_layout->addWidget(stop_button_); run_button_ = new QPushButton(this); button_layout->addWidget(run_button_); close_button_ = new QPushButton(this); button_layout->addWidget(close_button_); layout->addLayout(button_layout); connect(run_button_, &QPushButton::clicked, this, &SuitabilityBenchmarkDialog::start_benchmark); connect(stop_button_, &QPushButton::clicked, this, &SuitabilityBenchmarkDialog::request_stop); connect(close_button_, &QPushButton::clicked, this, &QDialog::accept); connect(suppress_checkbox_, &QCheckBox::toggled, this, [this](bool checked) { settings_.set_suitability_benchmark_suppressed(checked); settings_.save(); }); } void SuitabilityBenchmarkDialog::retranslate_ui() { setWindowTitle(QObject::tr("Compatibility Benchmark")); if (intro_label_) { const QString intro_main = QObject::tr("Run a quick performance check to estimate how image analysis, document analysis, and file categorization will perform on your system."); const QString intro_warning = QObject::tr("It is recommended to quit any CPU- and GPU-intensive applications before running this test."); intro_label_->setText(QStringLiteral("%1

%2") .arg(intro_main.toHtmlEscaped(), intro_warning.toHtmlEscaped())); } if (run_button_) { run_button_->setText(QObject::tr("Run benchmark")); } if (suppress_checkbox_) { suppress_checkbox_->setText(QObject::tr("Do not auto-show this dialog again")); } if (stop_button_) { stop_button_->setText(QObject::tr("Stop Benchmark")); } if (close_button_) { close_button_->setText(QObject::tr("Close")); } if (showing_previous_results_) { render_previous_results(); } } void SuitabilityBenchmarkDialog::changeEvent(QEvent* event) { QDialog::changeEvent(event); if (event && event->type() == QEvent::LanguageChange) { retranslate_ui(); } } void SuitabilityBenchmarkDialog::load_previous_results() { last_run_stamp_ = QString::fromStdString(settings_.get_benchmark_last_run()); last_report_ = QString::fromStdString(settings_.get_benchmark_last_report()); render_previous_results(); } void SuitabilityBenchmarkDialog::render_previous_results() { if (!output_view_) { return; } const bool was_recording = recording_; recording_ = false; output_view_->clear(); showing_previous_results_ = true; if (last_report_.isEmpty()) { append_line(QObject::tr("No previous results yet."), false); recording_ = was_recording; return; } if (!last_run_stamp_.isEmpty()) { append_line(QObject::tr("Last run: %1").arg(last_run_stamp_), false); } append_line(QObject::tr("Previous results:"), false); const QStringList lines = last_report_.split('\n'); for (const QString& line : lines) { append_line(line, line.contains('<')); } if (auto* scroll = output_view_->verticalScrollBar()) { scroll->setValue(scroll->maximum()); } recording_ = was_recording; } void SuitabilityBenchmarkDialog::closeEvent(QCloseEvent* event) { if (running_) { if (event) { event->ignore(); } return; } QDialog::closeEvent(event); } void SuitabilityBenchmarkDialog::start_benchmark() { if (running_) { return; } if (worker_.joinable()) { worker_.join(); } if (!has_any_llm_available()) { if (output_view_) { output_view_->clear(); } append_line(QObject::tr("No downloaded LLM files detected. Download a categorization or visual model to run the benchmark."), false); return; } if (output_view_) { output_view_->clear(); } showing_previous_results_ = false; recording_ = true; current_report_.clear(); stop_requested_ = false; set_running_state(true); worker_ = std::thread(&SuitabilityBenchmarkDialog::run_benchmark_worker, this); } void SuitabilityBenchmarkDialog::run_benchmark_worker() { QPointer self(this); auto post_line = [self](const QString& text) { if (!self) { return; } QMetaObject::invokeMethod(self, [self, text]() { if (self) { self->append_line(text, false); } }, Qt::QueuedConnection); }; auto post_line_html = [self](const QString& html) { if (!self) { return; } QMetaObject::invokeMethod(self, [self, html]() { if (self) { self->append_line(html, true); } }, Qt::QueuedConnection); }; auto finish = [self]() { if (!self) { return; } QMetaObject::invokeMethod(self, [self]() { if (self) { self->finish_benchmark(); } }, Qt::QueuedConnection); }; auto should_stop = [self]() -> bool { if (!self) { return true; } return self->stop_requested_.load(); }; try { post_line(QObject::tr("Starting system compatibility check...")); static const std::array kBenchmarkEnvKeys = { "AI_FILE_SORTER_GPU_BACKEND", "LLAMA_ARG_DEVICE", "GGML_DISABLE_CUDA" }; const EnvSnapshot baseline_env = EnvSnapshot::capture(kBenchmarkEnvKeys); ScopedEnvRestore env_restore(baseline_env); const unsigned int hw_threads = std::max(1u, std::thread::hardware_concurrency()); post_line(QObject::tr("CPU threads detected: %1").arg(hw_threads)); const char* backend_env = std::getenv("AI_FILE_SORTER_GPU_BACKEND"); std::string backend_override = read_env_lower("AI_FILE_SORTER_GPU_BACKEND"); if (backend_env && *backend_env) { post_line(QObject::tr("GPU backend override: %1").arg(QString::fromUtf8(backend_env))); } bool cuda_available = false; std::optional vk_memory; bool metal_available = false; std::optional metal_memory; #if defined(__APPLE__) metal_available = is_backend_available("Metal"); post_line(QObject::tr("Metal available: %1") .arg(metal_available ? QObject::tr("yes") : QObject::tr("no"))); metal_memory = query_backend_memory("metal"); if (metal_memory.has_value()) { post_line(QObject::tr("GPU memory allocation (Metal): %1 free / %2 total") .arg(QString::fromStdString(format_mib(metal_memory->free_bytes))) .arg(QString::fromStdString(format_mib(metal_memory->total_bytes)))); } else { post_line(QObject::tr("GPU memory allocation (Metal): unavailable")); } #else cuda_available = Utils::is_cuda_available(); post_line(QObject::tr("CUDA available: %1") .arg(cuda_available ? QObject::tr("yes") : QObject::tr("no"))); if (cuda_available) { auto cuda_info = Utils::query_cuda_memory(); if (cuda_info && cuda_info->valid()) { QString line = QObject::tr("CUDA memory (allocatable): %1 free / %2 total") .arg(QString::fromStdString(format_mib(cuda_info->free_bytes))) .arg(QString::fromStdString(format_mib(cuda_info->total_bytes))); if (cuda_info->device_total_bytes > 0) { line += QObject::tr(" (device total: %1)") .arg(QString::fromStdString(format_mib(cuda_info->device_total_bytes))); } post_line(line); } } vk_memory = query_backend_memory("vulkan"); if (vk_memory.has_value()) { post_line(QObject::tr("GPU memory allocation (Vulkan): %1 free / %2 total") .arg(QString::fromStdString(format_mib(vk_memory->free_bytes))) .arg(QString::fromStdString(format_mib(vk_memory->total_bytes)))); } else { post_line(QObject::tr("GPU memory allocation (Vulkan): unavailable")); } #endif BenchmarkBackendInfo backend_info; backend_info.cuda_available = cuda_available; backend_info.vulkan_available = vk_memory.has_value(); backend_info.vulkan_device = vk_memory ? vk_memory->name : std::string(); backend_info.metal_available = metal_available; backend_info.metal_device = metal_memory ? metal_memory->name : std::string(); backend_info.blas_label = detect_blas_backend_label(); const auto temp_dir = create_temp_dir(); if (temp_dir.empty()) { post_line(QObject::tr("Temporary directory setup failed; benchmark sample file creation may fail.")); } const std::vector default_models = collect_default_models(); if (default_models.empty()) { post_line(QObject::tr("No default models downloaded; skipping categorization and document checks.")); } else { post_line(QObject::tr("Default models detected: %1").arg(default_models.size())); } post_line(QStringLiteral("----")); const TextModelOutcome text_outcome = run_text_model_checks(default_models, temp_dir, baseline_env, backend_info, post_line, post_line_html, should_stop); if (should_stop()) { post_line(QObject::tr("Benchmark stopped.")); finish(); return; } post_line(QStringLiteral("----")); post_line(QObject::tr("Running image analysis test...")); baseline_env.restore(); ScopedEnvRestore image_env_restore(baseline_env); if (should_stop()) { post_line(QObject::tr("Benchmark stopped.")); finish(); return; } StepResult image_result = run_image_test(temp_dir); if (image_result.skipped) { const QString detail = image_result.detail.empty() ? QObject::tr("unavailable") : QString::fromStdString(image_result.detail); post_line(QObject::tr("Image analysis: skipped (%1)").arg(detail)); } else { const double seconds = duration_seconds(image_result.duration); const PerfClass image_perf = classify_perf(seconds, image_thresholds()); post_line(QObject::tr("Image analysis: %1") .arg(image_result.success ? QObject::tr("done") : QObject::tr("failed"))); post_line_html(QObject::tr(" Time: %1") .arg(colored_seconds(seconds, image_perf))); if (!image_result.success && !image_result.detail.empty()) { post_line(QObject::tr("Details: %1").arg(QString::fromStdString(image_result.detail))); } } if (should_stop()) { post_line(QObject::tr("Benchmark stopped.")); finish(); return; } if (!image_result.skipped) { std::string visual_backend = read_env_lower("AI_FILE_SORTER_GPU_BACKEND"); if (visual_backend.empty()) { visual_backend = read_env_lower("LLAMA_ARG_DEVICE"); } QString backend_note; if (!should_use_visual_gpu()) { backend_note = build_cpu_backend_note(QObject::tr("GPU disabled by backend override"), std::nullopt); } else if (case_insensitive_contains(visual_backend, "vulkan") && !backend_info.vulkan_available) { backend_note = build_cpu_backend_note(QObject::tr("GPU via Vulkan unavailable"), std::nullopt); } else if (case_insensitive_contains(visual_backend, "metal") && !backend_info.metal_available) { backend_note = build_cpu_backend_note(QObject::tr("GPU via Metal unavailable"), std::nullopt); } else { BackendTarget visual_target = resolve_backend_target(visual_backend); if (visual_target.key == "cpu") { backend_note = build_cpu_backend_note(QObject::tr("GPU disabled by backend override"), std::nullopt); } else { if (!visual_backend.empty()) { visual_target.label = format_backend_label(visual_backend); } backend_note = build_gpu_backend_note(visual_target); } } post_line(QObject::tr("Backend used (image analysis): %1") .arg(backend_note)); } post_line(QStringLiteral("----")); const QStringList result_lines = build_result_lines(text_outcome, image_result); for (const QString& line : result_lines) { if (line.contains('<')) { post_line_html(line); } else { post_line(line); } } std::error_code cleanup_error; std::filesystem::remove_all(temp_dir, cleanup_error); } catch (const std::exception& ex) { post_line(QObject::tr("Benchmark failed: %1").arg(QString::fromStdString(ex.what()))); } finish(); } void SuitabilityBenchmarkDialog::request_stop() { if (!running_) { return; } stop_requested_ = true; append_line(QObject::tr("[STOP] Benchmark will stop after the current step is processed."), false); } void SuitabilityBenchmarkDialog::append_line(const QString& text, bool is_html) { if (!output_view_) { return; } const QString html = is_html ? text : highlight_figures(text); QTextCursor cursor(output_view_->textCursor()); cursor.movePosition(QTextCursor::End); cursor.insertHtml(html); cursor.insertBlock(); output_view_->setTextCursor(cursor); if (auto* scroll = output_view_->verticalScrollBar()) { scroll->setValue(scroll->maximum()); } if (recording_) { current_report_.push_back(html); } } void SuitabilityBenchmarkDialog::set_running_state(bool running) { running_ = running; if (progress_bar_) { progress_bar_->setVisible(running); } if (run_button_) { run_button_->setEnabled(!running); } if (stop_button_) { stop_button_->setEnabled(running); } if (close_button_) { close_button_->setEnabled(!running); } } void SuitabilityBenchmarkDialog::finish_benchmark() { recording_ = false; const std::string timestamp = format_timestamp(std::chrono::system_clock::now()); settings_.set_benchmark_last_run(timestamp); settings_.set_benchmark_last_report(current_report_.join('\n').toStdString()); settings_.set_suitability_benchmark_completed(true); settings_.save(); set_running_state(false); } ================================================ FILE: app/lib/SupportCodeManager.cpp ================================================ #include "SupportCodeManager.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace { constexpr std::uint32_t kBlobMagic = 0xA15F50C2u; constexpr std::uint32_t kBlobVersion = 2u; constexpr std::size_t kSaltSize = 16u; constexpr std::size_t kHashSize = 32u; constexpr std::size_t kBlobSize = 120u; constexpr std::size_t kSignatureSize = 64u; constexpr char kCodePrefix[] = "AIFS1"; constexpr char kPayloadPrefix[] = "aifs-support:v1:"; // This must match the private key held by the website-side signer. constexpr std::array kVerificationPublicKey{ 0xd4, 0x56, 0x9d, 0x00, 0x24, 0x50, 0xf5, 0xa2, 0x90, 0x94, 0xff, 0x0f, 0xf8, 0xee, 0xcc, 0x7b, 0x4f, 0xfa, 0x05, 0x2a, 0xf8, 0x35, 0x37, 0xba, 0x4e, 0xde, 0x3c, 0xc5, 0x16, 0xf5, 0x66, 0xe1, }; constexpr std::array kBlobPepper{ 0x6f, 0x24, 0x94, 0x11, 0x5d, 0xca, 0x37, 0xa8, 0x7b, 0xe0, 0x12, 0x49, 0xf6, 0x9d, 0x58, 0x03, 0xc4, 0x71, 0x2e, 0xb9, 0x8a, 0x16, 0xdd, 0x60, 0x34, 0xf3, 0x8c, 0x27, 0x90, 0x4a, 0xbe, 0x15, }; #ifdef AI_FILE_SORTER_TEST_BUILD constexpr char kTestPayload[] = "aifs-support:v1:test-build"; #endif std::string trim_ascii(std::string_view value) { std::size_t first = 0; while (first < value.size() && std::isspace(static_cast(value[first])) != 0) { ++first; } std::size_t last = value.size(); while (last > first && std::isspace(static_cast(value[last - 1])) != 0) { --last; } return std::string(value.substr(first, last - first)); } QByteArray appendable_base64url(std::string_view segment) { if (segment.empty()) { return {}; } QByteArray encoded(segment.data(), static_cast(segment.size())); const int remainder = encoded.size() % 4; if (remainder != 0) { encoded.append(QByteArray(4 - remainder, '=')); } return encoded; } QByteArray decode_base64url(std::string_view segment) { if (segment.empty()) { return {}; } return QByteArray::fromBase64( appendable_base64url(segment), QByteArray::Base64UrlEncoding | QByteArray::AbortOnBase64DecodingErrors); } bool is_supported_payload(const QByteArray& payload) { if (!payload.startsWith(kPayloadPrefix)) { return false; } if (payload.size() <= static_cast(std::char_traits::length(kPayloadPrefix)) || payload.size() > 160) { return false; } for (int i = static_cast(std::char_traits::length(kPayloadPrefix)); i < payload.size(); ++i) { const unsigned char ch = static_cast(payload.at(i)); if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9') || ch == '-' || ch == '_' || ch == ':' || ch == '.') { continue; } return false; } return true; } bool verify_signature(const QByteArray& payload, const QByteArray& signature) { EVP_PKEY* key = EVP_PKEY_new_raw_public_key( EVP_PKEY_ED25519, nullptr, kVerificationPublicKey.data(), kVerificationPublicKey.size()); if (!key) { return false; } EVP_MD_CTX* ctx = EVP_MD_CTX_new(); if (!ctx) { EVP_PKEY_free(key); return false; } const bool verified = EVP_DigestVerifyInit(ctx, nullptr, nullptr, nullptr, key) == 1 && EVP_DigestVerify( ctx, reinterpret_cast(signature.constData()), static_cast(signature.size()), reinterpret_cast(payload.constData()), static_cast(payload.size())) == 1; EVP_MD_CTX_free(ctx); EVP_PKEY_free(key); return verified; } QByteArray to_byte_array(std::uint32_t value) { QByteArray bytes(4, Qt::Uninitialized); bytes[0] = static_cast(value & 0xffu); bytes[1] = static_cast((value >> 8) & 0xffu); bytes[2] = static_cast((value >> 16) & 0xffu); bytes[3] = static_cast((value >> 24) & 0xffu); return bytes; } std::uint32_t from_little_endian_u32(const unsigned char* data) { return static_cast(data[0]) | (static_cast(data[1]) << 8) | (static_cast(data[2]) << 16) | (static_cast(data[3]) << 24); } std::uint32_t leading_u32(const QByteArray& value) { if (value.size() < 4) { return 0; } const auto* data = reinterpret_cast(value.constData()); return from_little_endian_u32(data); } QByteArray sha256_labeled(std::string_view label, std::initializer_list segments) { QCryptographicHash hash(QCryptographicHash::Sha256); hash.addData(label.data(), static_cast(label.size())); hash.addData(reinterpret_cast(kBlobPepper.data()), static_cast(kBlobPepper.size())); for (const QByteArray& segment : segments) { hash.addData(segment); } return hash.result(); } std::array random_salt() { std::array salt{}; for (std::size_t i = 0; i < salt.size(); i += sizeof(quint32)) { const quint32 word = QRandomGenerator::global()->generate(); const std::size_t remaining = std::min(sizeof(word), salt.size() - i); for (std::size_t j = 0; j < remaining; ++j) { salt[i + j] = static_cast((word >> (j * 8)) & 0xffu); } } return salt; } QByteArray to_byte_array(const std::array& value) { return QByteArray(reinterpret_cast(value.data()), static_cast(value.size())); } std::filesystem::path blob_filename() { return "support_prompt_state.bin"; } } // namespace SupportCodeManager::SupportCodeManager(std::filesystem::path config_dir) : config_dir_(std::move(config_dir)) {} bool SupportCodeManager::is_valid_code(const std::string& code) { return decode_payload(code).has_value(); } bool SupportCodeManager::redeem_code(const std::string& code) const { const auto payload = decode_payload(code); if (!payload.has_value()) { return false; } return write_state(*payload); } bool SupportCodeManager::is_prompt_permanently_disabled() const { std::ifstream input(storage_path(), std::ios::binary); if (!input) { return false; } std::array blob{}; input.read(reinterpret_cast(blob.data()), static_cast(blob.size())); if (!input || input.gcount() != static_cast(blob.size())) { return false; } const std::uint32_t stored_magic = from_little_endian_u32(blob.data()); const std::uint32_t stored_version = from_little_endian_u32(blob.data() + 4); const QByteArray salt(reinterpret_cast(blob.data() + 8), static_cast(kSaltSize)); const QByteArray payload_hash(reinterpret_cast(blob.data() + 24), static_cast(kHashSize)); const QByteArray machine_hash(reinterpret_cast(blob.data() + 56), static_cast(kHashSize)); const QByteArray checksum(reinterpret_cast(blob.data() + 88), static_cast(kHashSize)); const QByteArray expected_machine_hash = sha256_labeled( "aifs/support/machine/v2", {salt, QByteArray::fromStdString(machine_binding_key())}); if (machine_hash != expected_machine_hash) { return false; } if (stored_magic != (kBlobMagic ^ leading_u32(payload_hash)) || stored_version != (kBlobVersion ^ leading_u32(machine_hash))) { return false; } const QByteArray expected_checksum = sha256_labeled( "aifs/support/blob/v2", {to_byte_array(stored_magic), to_byte_array(stored_version), salt, payload_hash, machine_hash}); return checksum == expected_checksum; } #ifdef AI_FILE_SORTER_TEST_BUILD bool SupportCodeManager::force_disable_prompt_for_testing() const { return write_state(kTestPayload); } #endif std::optional SupportCodeManager::decode_payload(const std::string& code) { const std::string trimmed = trim_ascii(code); if (trimmed.empty() || trimmed.size() > 512) { return std::nullopt; } const std::size_t first_dot = trimmed.find('.'); if (first_dot == std::string::npos || trimmed.substr(0, first_dot) != kCodePrefix) { return std::nullopt; } const std::size_t second_dot = trimmed.find('.', first_dot + 1); if (second_dot == std::string::npos || trimmed.find('.', second_dot + 1) != std::string::npos) { return std::nullopt; } const std::string_view payload_segment(trimmed.data() + first_dot + 1, second_dot - first_dot - 1); const std::string_view signature_segment(trimmed.data() + second_dot + 1, trimmed.size() - second_dot - 1); if (payload_segment.empty() || signature_segment.empty()) { return std::nullopt; } const QByteArray payload = decode_base64url(payload_segment); const QByteArray signature = decode_base64url(signature_segment); if (payload.isEmpty() || signature.size() != static_cast(kSignatureSize) || !is_supported_payload(payload) || !verify_signature(payload, signature)) { return std::nullopt; } return std::string(payload.constData(), static_cast(payload.size())); } std::filesystem::path SupportCodeManager::storage_path() const { return config_dir_ / blob_filename(); } std::string SupportCodeManager::machine_binding_key() const { QByteArray material; auto append = [&material](const QByteArray& value) { if (value.isEmpty()) { return; } if (!material.isEmpty()) { material.push_back('\0'); } material.append(value); }; append(QSysInfo::machineUniqueId()); append(QSysInfo::machineHostName().toUtf8()); append(QSysInfo::currentCpuArchitecture().toUtf8()); append(QSysInfo::buildAbi().toUtf8()); append(QSysInfo::kernelType().toUtf8()); append(QSysInfo::kernelVersion().toUtf8()); append(QSysInfo::prettyProductName().toUtf8()); if (material.isEmpty()) { material = QByteArray::fromStdString(config_dir_.string()); } return std::string(material.constData(), static_cast(material.size())); } bool SupportCodeManager::write_state(const std::string& payload) const { const auto salt = random_salt(); const QByteArray salt_bytes = to_byte_array(salt); const QByteArray payload_hash = sha256_labeled( "aifs/support/payload/v2", {QByteArray::fromStdString(payload)}); const QByteArray machine_hash = sha256_labeled( "aifs/support/machine/v2", {salt_bytes, QByteArray::fromStdString(machine_binding_key())}); const std::uint32_t stored_magic = kBlobMagic ^ leading_u32(payload_hash); const std::uint32_t stored_version = kBlobVersion ^ leading_u32(machine_hash); const QByteArray checksum = sha256_labeled( "aifs/support/blob/v2", {to_byte_array(stored_magic), to_byte_array(stored_version), salt_bytes, payload_hash, machine_hash}); QByteArray blob; blob.reserve(static_cast(kBlobSize)); blob.append(to_byte_array(stored_magic)); blob.append(to_byte_array(stored_version)); blob.append(salt_bytes); blob.append(payload_hash); blob.append(machine_hash); blob.append(checksum); std::error_code ec; std::filesystem::create_directories(config_dir_, ec); if (ec) { return false; } std::ofstream output(storage_path(), std::ios::binary | std::ios::trunc); if (!output) { return false; } output.write(blob.constData(), static_cast(blob.size())); output.close(); if (!output) { return false; } std::filesystem::permissions( storage_path(), std::filesystem::perms::owner_read | std::filesystem::perms::owner_write, std::filesystem::perm_options::replace, ec); return true; } ================================================ FILE: app/lib/TranslationManager.cpp ================================================ #include "TranslationManager.hpp" #include #include #include #include #include namespace { using LanguageInfo = TranslationManager::LanguageInfo; std::vector build_languages() { return { {Language::English, QStringLiteral("en"), QStringLiteral("English"), QString()}, {Language::Dutch, QStringLiteral("nl"), QStringLiteral("Dutch"), QStringLiteral(":/i18n/aifilesorter_nl.qm")}, {Language::French, QStringLiteral("fr"), QStringLiteral("French"), QStringLiteral(":/i18n/aifilesorter_fr.qm")}, {Language::German, QStringLiteral("de"), QStringLiteral("German"), QStringLiteral(":/i18n/aifilesorter_de.qm")}, {Language::Italian, QStringLiteral("it"), QStringLiteral("Italian"), QStringLiteral(":/i18n/aifilesorter_it.qm")}, {Language::Spanish, QStringLiteral("es"), QStringLiteral("Spanish"), QStringLiteral(":/i18n/aifilesorter_es.qm")}, {Language::Turkish, QStringLiteral("tr"), QStringLiteral("Turkish"), QStringLiteral(":/i18n/aifilesorter_tr.qm")}, {Language::Korean, QStringLiteral("ko"), QStringLiteral("Korean"), QStringLiteral(":/i18n/aifilesorter_ko.qm")}, }; } const LanguageInfo* find_language_info(const std::vector& languages, Language language) { const auto it = std::find_if( languages.cbegin(), languages.cend(), [language](const LanguageInfo& info) { return info.id == language; }); if (it == languages.cend()) { return nullptr; } return &(*it); } QStringList translation_search_paths() { QStringList paths; if (QCoreApplication::instance()) { const QDir app_dir(QCoreApplication::applicationDirPath()); paths << app_dir.filePath(QStringLiteral("i18n")); paths << app_dir.filePath(QStringLiteral("../i18n")); #if defined(Q_OS_MACOS) paths << app_dir.filePath(QStringLiteral("../Resources/i18n")); #endif } const QDir cwd(QDir::currentPath()); paths << cwd.filePath(QStringLiteral("app/resources/i18n")); paths << cwd.filePath(QStringLiteral("resources/i18n")); paths.removeDuplicates(); return paths; } } // namespace TranslationManager::TranslationManager() = default; TranslationManager& TranslationManager::instance() { static TranslationManager manager; return manager; } void TranslationManager::initialize(QApplication* app) { app_ = app; if (!translator_) { translator_ = std::make_unique(); } if (languages_.empty()) { languages_ = build_languages(); } } void TranslationManager::initialize_for_app(QApplication* app, Language language) { initialize(app); set_language(language); } void TranslationManager::set_language(Language language) { if (languages_.empty()) { languages_ = build_languages(); } const LanguageInfo* info = find_language_info(languages_, language); if (!info) { language = Language::English; info = find_language_info(languages_, language); } if (!app_) { current_language_ = language; return; } if (translator_) { app_->removeTranslator(translator_.get()); translator_ = std::make_unique(); } if (info && language != Language::English) { if (load_translation(*info)) { app_->installTranslator(translator_.get()); } else { language = Language::English; } } current_language_ = language; } Language TranslationManager::current_language() const { return current_language_; } const std::vector& TranslationManager::available_languages() const { return languages_; } bool TranslationManager::load_translation(const LanguageInfo& info) { if (!translator_) { return false; } if (!info.resource_path.isEmpty() && translator_->load(info.resource_path)) { return true; } const QString file_name = QFileInfo(info.resource_path).fileName(); if (file_name.isEmpty()) { return false; } for (const QString& dir : translation_search_paths()) { const QString candidate = QDir(dir).filePath(file_name); if (QFileInfo::exists(candidate) && translator_->load(candidate)) { return true; } } return false; } ================================================ FILE: app/lib/UiTranslator.cpp ================================================ #include "UiTranslator.hpp" #include "Language.hpp" #include "CategoryLanguage.hpp" #include "Settings.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace { template Widget* raw_ptr(const QPointer& pointer) { return pointer.data(); } } // namespace UiTranslator::UiTranslator(Dependencies deps) : deps_(deps) { if (!deps_.translator) { deps_.translator = [](const char* source) { return QCoreApplication::translate("UiTranslator", source); }; } } void UiTranslator::retranslate_all(const State& state) const { translate_window_title(); translate_primary_controls(state.analysis_in_progress); translate_tree_view_labels(); translate_menus_and_actions(); translate_status_messages(state); update_language_checks(); } void UiTranslator::translate_window_title() const { deps_.window.setWindowTitle(QStringLiteral("AI File Sorter")); } void UiTranslator::translate_primary_controls(bool analysis_in_progress) const { if (auto* label = raw_ptr(deps_.primary.path_label)) { label->setText(tr("Folder:")); } if (auto* button = raw_ptr(deps_.primary.browse_button)) { button->setText(tr("Browse…")); } if (auto* checkbox = raw_ptr(deps_.primary.use_subcategories_checkbox)) { checkbox->setText(tr("Use subcategories")); checkbox->setToolTip(tr("Create subcategory folders within each category.")); } if (auto* heading = raw_ptr(deps_.primary.categorization_style_heading)) { heading->setText(tr("Categorization type")); heading->setToolTip(tr("Choose how strict the category labels should be.")); } if (auto* refined_radio = raw_ptr(deps_.primary.categorization_style_refined_radio)) { refined_radio->setText(tr("More refined")); refined_radio->setToolTip(tr("Favor detailed labels even if similar items vary.")); } if (auto* consistent_radio = raw_ptr(deps_.primary.categorization_style_consistent_radio)) { consistent_radio->setText(tr("More consistent")); consistent_radio->setToolTip(tr("Favor consistent labels across similar items.")); } if (auto* checkbox = raw_ptr(deps_.primary.use_whitelist_checkbox)) { checkbox->setText(tr("Use a whitelist")); checkbox->setToolTip(tr("Restrict categories and subcategories to the selected whitelist.")); } if (auto* selector = raw_ptr(deps_.primary.whitelist_selector)) { selector->setToolTip(tr("Select the whitelist used for this run.")); } if (auto* checkbox = raw_ptr(deps_.primary.categorize_files_checkbox)) { checkbox->setText(tr("Categorize files")); checkbox->setToolTip(tr("Include files in the categorization pass.")); } if (auto* checkbox = raw_ptr(deps_.primary.categorize_directories_checkbox)) { checkbox->setText(tr("Categorize folders")); checkbox->setToolTip(tr("Include directories in the categorization pass.")); } if (auto* checkbox = raw_ptr(deps_.primary.include_subdirectories_checkbox)) { checkbox->setText(tr("Scan subfolders")); checkbox->setToolTip(tr("Scan files inside subfolders and treat them as part of the main folder.")); } if (auto* checkbox = raw_ptr(deps_.primary.analyze_images_checkbox)) { checkbox->setText(tr("Analyze picture files by content (can be slow)")); checkbox->setToolTip(tr("Run the visual LLM on supported picture files.")); } if (auto* checkbox = raw_ptr(deps_.primary.process_images_only_checkbox)) { checkbox->setText(tr("Process picture files only (ignore any other files)")); checkbox->setToolTip(tr("Ignore non-picture files in this run.")); } if (auto* checkbox = raw_ptr(deps_.primary.add_image_date_to_category_checkbox)) { checkbox->setText(tr("Add image creation date (if available) to category name")); checkbox->setToolTip(tr("Append the image creation date from metadata to the category label.")); } if (auto* checkbox = raw_ptr(deps_.primary.add_image_date_place_to_filename_checkbox)) { checkbox->setText(tr("Add photo date and place to filename (if available)")); checkbox->setToolTip(tr("Date comes from photo EXIF metadata. Place names are resolved online from GPS coordinates, so network access is required for place prefixes.")); } if (auto* checkbox = raw_ptr(deps_.primary.add_audio_video_metadata_to_filename_checkbox)) { checkbox->setText(tr("Add audio/video metadata to file name (if available)")); checkbox->setToolTip(tr("Use embedded media tags (for example year, artist, album, title) to build suggested audio/video filenames.")); } if (auto* checkbox = raw_ptr(deps_.primary.offer_rename_images_checkbox)) { checkbox->setText(tr("Offer to rename picture files")); checkbox->setToolTip(tr("Show suggested filenames for picture files.")); } if (auto* checkbox = raw_ptr(deps_.primary.rename_images_only_checkbox)) { checkbox->setText(tr("Do not categorize picture files (only rename)")); checkbox->setToolTip(tr("Skip categorization for picture files and only rename them.")); } if (auto* button = raw_ptr(deps_.primary.image_options_toggle_button)) { button->setToolTip(tr("Show or hide picture analysis options")); } if (auto* checkbox = raw_ptr(deps_.primary.analyze_documents_checkbox)) { checkbox->setText(tr("Analyze document files by content")); checkbox->setToolTip(tr("Summarize document contents with the selected LLM.")); } if (auto* checkbox = raw_ptr(deps_.primary.process_documents_only_checkbox)) { checkbox->setText(tr("Process document files only (ignore any other files)")); checkbox->setToolTip(tr("Ignore non-document files in this run.")); } if (auto* checkbox = raw_ptr(deps_.primary.offer_rename_documents_checkbox)) { checkbox->setText(tr("Offer to rename document files")); checkbox->setToolTip(tr("Show suggested filenames for document files.")); } if (auto* checkbox = raw_ptr(deps_.primary.rename_documents_only_checkbox)) { checkbox->setText(tr("Do not categorize document files (only rename)")); checkbox->setToolTip(tr("Skip categorization for document files and only rename them.")); } if (auto* checkbox = raw_ptr(deps_.primary.add_document_date_to_category_checkbox)) { checkbox->setText(tr("Add document creation date (if available) to category name")); checkbox->setToolTip(tr("Append the document creation date from metadata to the category label.")); } if (auto* button = raw_ptr(deps_.primary.document_options_toggle_button)) { button->setToolTip(tr("Show or hide document analysis options")); } if (auto* button = raw_ptr(deps_.primary.analyze_button)) { button->setText(analysis_in_progress ? tr("Stop analyzing") : tr("Analyze folder")); } } void UiTranslator::translate_tree_view_labels() const { QStandardItemModel* model = raw_ptr(deps_.tree_model); if (!model) { return; } model->setHorizontalHeaderLabels(QStringList{ tr("File"), tr("Type"), tr("Category"), tr("Subcategory"), tr("Status") }); for (int row = 0; row < model->rowCount(); ++row) { if (auto* type_item = model->item(row, 1)) { const QString type_code = type_item->data(Qt::UserRole).toString(); if (type_code == QStringLiteral("D")) { type_item->setText(tr("Directory")); } else if (type_code == QStringLiteral("F")) { type_item->setText(tr("File")); } } if (auto* status_item = model->item(row, 4)) { const QString status_code = status_item->data(Qt::UserRole).toString(); if (status_code == QStringLiteral("ready")) { status_item->setText(tr("Ready")); } } } } void UiTranslator::translate_menus_and_actions() const { struct MenuEntry { QMenu* menu{nullptr}; const char* text{nullptr}; }; const MenuEntry menu_entries[] = { {deps_.menus.file_menu, "&File"}, {deps_.menus.edit_menu, "&Edit"}, {deps_.menus.view_menu, "&View"}, {deps_.menus.settings_menu, "&Settings"}, {deps_.menus.development_menu, "&Development"}, {deps_.menus.development_settings_menu, "&Settings"}, {deps_.menus.language_menu, "Interface &language"}, {deps_.menus.category_language_menu, "Category &language"} }; for (const MenuEntry& entry : menu_entries) { if (entry.menu && entry.text) { entry.menu->setTitle(tr(entry.text)); } } struct ActionEntry { QAction* action{nullptr}; const char* text{nullptr}; }; const ActionEntry action_entries[] = { {deps_.actions.file_quit_action, "&Quit"}, {deps_.actions.run_benchmark_action, "System compatibility check…"}, {deps_.actions.copy_action, "&Copy"}, {deps_.actions.cut_action, "Cu&t"}, {deps_.actions.undo_last_run_action, "Undo last run"}, {deps_.actions.paste_action, "&Paste"}, {deps_.actions.delete_action, "&Delete"}, {deps_.actions.toggle_explorer_action, "File &Explorer"}, {deps_.actions.toggle_llm_action, "Select &LLM…"}, {deps_.actions.manage_whitelists_action, "Manage category whitelists…"}, {deps_.actions.development_prompt_logging_action, "Log prompts and responses to stdout"}, {deps_.actions.consistency_pass_action, "Run &consistency pass"}, {deps_.actions.english_action, "&English"}, {deps_.actions.dutch_action, "&Dutch"}, {deps_.actions.french_action, "&French"}, {deps_.actions.german_action, "&German"}, {deps_.actions.italian_action, "&Italian"}, {deps_.actions.spanish_action, "&Spanish"}, {deps_.actions.turkish_action, "&Turkish"}, {deps_.actions.korean_action, "&Korean"}, {deps_.actions.category_language_dutch, "Dutch"}, {deps_.actions.category_language_english, "English"}, {deps_.actions.category_language_french, "French"}, {deps_.actions.category_language_german, "German"}, {deps_.actions.category_language_italian, "Italian"}, {deps_.actions.category_language_polish, "Polish"}, {deps_.actions.category_language_portuguese, "Portuguese"}, {deps_.actions.category_language_spanish, "Spanish"}, {deps_.actions.category_language_turkish, "Turkish"}, {deps_.actions.about_action, "&About AI File Sorter"}, {deps_.actions.about_qt_action, "About &Qt"}, {deps_.actions.about_agpl_action, "About &AGPL"}, {deps_.actions.support_project_action, "&Support Project"} }; for (const ActionEntry& entry : action_entries) { if (entry.action && entry.text) { entry.action->setText(tr(entry.text)); } } if (auto* menu = deps_.menus.help_menu) { const QString help_title = QString(QChar(0x200B)) + tr("&Help"); menu->setTitle(help_title); if (QAction* help_action = menu->menuAction()) { help_action->setText(help_title); } } if (auto* dock = raw_ptr(deps_.file_explorer_dock)) { dock->setWindowTitle(tr("File Explorer")); } } void UiTranslator::translate_status_messages(const State& state) const { QStatusBar* bar = deps_.window.statusBar(); if (!bar) { return; } if (state.analysis_in_progress) { if (state.stop_analysis_requested) { bar->showMessage(tr("Cancelling analysis…"), 4000); } else { bar->showMessage(tr("Analyzing…")); } } else if (state.status_is_ready) { bar->showMessage(tr("Ready")); } } void UiTranslator::update_language_checks() const { Language configured = deps_.settings.get_language(); update_language_group_checks(configured); CategoryLanguage cat_lang = deps_.settings.get_category_language(); update_category_language_checks(cat_lang); } void UiTranslator::update_language_group_checks(Language configured) const { if (!deps_.language.language_group) { return; } QSignalBlocker blocker(deps_.language.language_group); if (deps_.language.english_action) { deps_.language.english_action->setChecked(configured == Language::English); } if (deps_.language.dutch_action) { deps_.language.dutch_action->setChecked(configured == Language::Dutch); } if (deps_.language.french_action) { deps_.language.french_action->setChecked(configured == Language::French); } if (deps_.language.german_action) { deps_.language.german_action->setChecked(configured == Language::German); } if (deps_.language.italian_action) { deps_.language.italian_action->setChecked(configured == Language::Italian); } if (deps_.language.spanish_action) { deps_.language.spanish_action->setChecked(configured == Language::Spanish); } if (deps_.language.turkish_action) { deps_.language.turkish_action->setChecked(configured == Language::Turkish); } if (deps_.language.korean_action) { deps_.language.korean_action->setChecked(configured == Language::Korean); } } void UiTranslator::update_category_language_checks(CategoryLanguage configured) const { if (!deps_.category_language.category_language_group) { return; } QSignalBlocker blocker_cat(deps_.category_language.category_language_group); if (deps_.category_language.dutch) { deps_.category_language.dutch->setChecked(configured == CategoryLanguage::Dutch); } if (deps_.category_language.english) { deps_.category_language.english->setChecked(configured == CategoryLanguage::English); } if (deps_.category_language.french) { deps_.category_language.french->setChecked(configured == CategoryLanguage::French); } if (deps_.category_language.german) { deps_.category_language.german->setChecked(configured == CategoryLanguage::German); } if (deps_.category_language.italian) { deps_.category_language.italian->setChecked(configured == CategoryLanguage::Italian); } if (deps_.category_language.polish) { deps_.category_language.polish->setChecked(configured == CategoryLanguage::Polish); } if (deps_.category_language.portuguese) { deps_.category_language.portuguese->setChecked(configured == CategoryLanguage::Portuguese); } if (deps_.category_language.spanish) { deps_.category_language.spanish->setChecked(configured == CategoryLanguage::Spanish); } if (deps_.category_language.turkish) { deps_.category_language.turkish->setChecked(configured == CategoryLanguage::Turkish); } } QString UiTranslator::tr(const char* source) const { if (deps_.translator) { return deps_.translator(source); } return QCoreApplication::translate("UiTranslator", source); } ================================================ FILE: app/lib/UndoManager.cpp ================================================ #include "UndoManager.hpp" #include #include #include #include #include #include #include #include #include #include UndoManager::UndoManager(std::string undo_dir) : undo_dir_(std::move(undo_dir)) {} bool UndoManager::save_plan(const std::string& run_base_dir, const std::vector& entries, const std::shared_ptr& logger) const { if (undo_dir_.empty() || entries.empty()) { return false; } QDir dir(QString::fromStdString(undo_dir_)); if (!dir.exists()) { dir.mkpath(QStringLiteral(".")); } QJsonArray arr; for (const auto& entry : entries) { QJsonObject obj; obj["source"] = QString::fromStdString(entry.source); obj["destination"] = QString::fromStdString(entry.destination); obj["size"] = static_cast(entry.size_bytes); obj["mtime"] = static_cast(entry.mtime); arr.push_back(obj); } QJsonObject root; root["version"] = 1; root["base_dir"] = QString::fromStdString(run_base_dir); root["created_at_utc"] = QDateTime::currentDateTimeUtc().toString(Qt::ISODateWithMs); root["entries"] = arr; const QString filename = QStringLiteral("undo_plan_%1.json") .arg(QDateTime::currentDateTimeUtc().toString("yyyyMMdd_hhmmsszzz")); QFile file(dir.filePath(filename)); if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) { if (logger) { logger->error("Failed to write undo plan '{}': {}", filename.toStdString(), file.errorString().toStdString()); } return false; } file.write(QJsonDocument(root).toJson(QJsonDocument::Indented)); file.close(); if (logger) { logger->info("Saved undo plan to '{}'", file.fileName().toStdString()); } return true; } std::optional UndoManager::latest_plan_path() const { if (undo_dir_.empty()) { return std::nullopt; } QDir dir(QString::fromStdString(undo_dir_)); if (!dir.exists()) { return std::nullopt; } const auto files = dir.entryInfoList(QStringList() << "undo_plan_*.json", QDir::Files, QDir::Time | QDir::Reversed); if (files.isEmpty()) { return std::nullopt; } return files.back().filePath(); } UndoManager::UndoResult UndoManager::undo_plan(const QString& plan_path) const { UndoResult result; QFile file(plan_path); if (!file.open(QIODevice::ReadOnly)) { result.details << QString("Failed to open plan: %1").arg(plan_path); result.skipped++; return result; } const auto doc = QJsonDocument::fromJson(file.readAll()); if (!doc.isObject()) { result.details << QString("Invalid plan: %1").arg(plan_path); result.skipped++; return result; } const QJsonArray entries = doc.object().value("entries").toArray(); for (const auto& val : entries) { if (!val.isObject()) { result.skipped++; continue; } const QJsonObject obj = val.toObject(); const QString source = obj.value("source").toString(); const QString destination = obj.value("destination").toString(); const qint64 expected_size = obj.value("size").toInteger(0); const qint64 expected_mtime = obj.value("mtime").toInteger(0); QFileInfo dest_info(destination); if (!dest_info.exists()) { result.details << QString("Missing destination: %1").arg(destination); result.skipped++; continue; } QFileInfo src_info(source); if (src_info.exists()) { result.details << QString("Source already exists, skipping: %1").arg(source); result.skipped++; continue; } if (expected_size > 0 && dest_info.size() != expected_size) { result.details << QString("Size mismatch for %1").arg(destination); result.skipped++; continue; } if (expected_mtime > 0) { const auto mtime = dest_info.lastModified().toSecsSinceEpoch(); if (mtime != expected_mtime) { result.details << QString("Timestamp mismatch for %1").arg(destination); result.skipped++; continue; } } QDir().mkpath(src_info.path()); if (QFile::rename(destination, source)) { result.restored++; } else { result.details << QString("Failed to move %1 back to %2").arg(destination, source); result.skipped++; } } return result; } ================================================ FILE: app/lib/UpdateArchiveExtractor.cpp ================================================ #include "UpdateArchiveExtractor.hpp" #include #include #include #include #include #include #include #include #include #include #include namespace { std::string ascii_lower_copy(std::string value) { std::transform(value.begin(), value.end(), value.begin(), [](unsigned char ch) { return static_cast(std::tolower(ch)); }); return value; } bool is_directory_entry(const std::string& entry_name) { return !entry_name.empty() && entry_name.back() == '/'; } bool is_installer_entry(const std::string& entry_name) { const std::string extension = ascii_lower_copy(std::filesystem::path(entry_name).extension().string()); return extension == ".exe" || extension == ".msi"; } std::optional sanitize_archive_path(const std::string& entry_name) { const std::filesystem::path normalized = std::filesystem::path(entry_name).lexically_normal(); if (normalized.empty() || normalized.has_root_name() || normalized.has_root_directory()) { return std::nullopt; } std::filesystem::path sanitized; for (const auto& component : normalized) { if (component == "." || component.empty()) { continue; } if (component == "..") { return std::nullopt; } sanitized /= component; } if (sanitized.empty()) { return std::nullopt; } return sanitized; } std::string archive_error_message(zip_t* archive) { const char* message = zip_strerror(archive); return message ? std::string(message) : std::string("Unknown ZIP archive error."); } UpdateArchiveExtractor::ExtractionResult extract_entry(zip_t* archive, zip_uint64_t index, const std::filesystem::path& destination_root, const std::filesystem::path& relative_path) { const auto destination_path = destination_root / relative_path; const auto partial_path = std::filesystem::path(destination_path.string() + ".part"); std::error_code ec; std::filesystem::create_directories(destination_path.parent_path(), ec); if (ec) { return UpdateArchiveExtractor::ExtractionResult::failure( "Failed to create archive extraction directory: " + ec.message()); } zip_file_t* file = zip_fopen_index(archive, index, 0); if (!file) { return UpdateArchiveExtractor::ExtractionResult::failure( "Failed to open installer inside the ZIP archive."); } std::ofstream out(partial_path, std::ios::binary | std::ios::trunc); if (!out) { zip_fclose(file); return UpdateArchiveExtractor::ExtractionResult::failure( "Failed to create the extracted installer file."); } std::array buffer{}; while (true) { const zip_int64_t read = zip_fread(file, buffer.data(), buffer.size()); if (read < 0) { out.close(); zip_fclose(file); std::filesystem::remove(partial_path, ec); return UpdateArchiveExtractor::ExtractionResult::failure(archive_error_message(archive)); } if (read == 0) { break; } out.write(buffer.data(), static_cast(read)); if (!out) { out.close(); zip_fclose(file); std::filesystem::remove(partial_path, ec); return UpdateArchiveExtractor::ExtractionResult::failure( "Failed while writing the extracted installer."); } } out.close(); zip_fclose(file); std::filesystem::remove(destination_path, ec); ec.clear(); std::filesystem::rename(partial_path, destination_path, ec); if (ec) { std::filesystem::remove(partial_path, ec); return UpdateArchiveExtractor::ExtractionResult::failure( "Failed to finalize the extracted installer: " + ec.message()); } return UpdateArchiveExtractor::ExtractionResult::success(destination_path); } } // namespace bool UpdateArchiveExtractor::supports_archive(const std::filesystem::path& package_path) { return ascii_lower_copy(package_path.extension().string()) == ".zip"; } UpdateArchiveExtractor::ExtractionResult UpdateArchiveExtractor::extract_installer( const std::filesystem::path& archive_path, const std::filesystem::path& destination_root) { if (!supports_archive(archive_path)) { return ExtractionResult::failure("Only ZIP update packages are supported."); } int error_code = 0; zip_t* archive = zip_open(archive_path.string().c_str(), ZIP_RDONLY, &error_code); if (!archive) { zip_error_t error; zip_error_init_with_code(&error, error_code); const char* message = zip_error_strerror(&error); const std::string error_message = message ? std::string(message) : std::string("Failed to open ZIP archive."); zip_error_fini(&error); return ExtractionResult::failure(error_message); } std::vector> installer_candidates; const zip_int64_t entry_count = zip_get_num_entries(archive, 0); if (entry_count < 0) { const std::string error_message = archive_error_message(archive); zip_close(archive); return ExtractionResult::failure(error_message); } for (zip_uint64_t index = 0; index < static_cast(entry_count); ++index) { const char* raw_name = zip_get_name(archive, index, 0); if (!raw_name) { continue; } const std::string entry_name(raw_name); if (is_directory_entry(entry_name) || !is_installer_entry(entry_name)) { continue; } const auto sanitized = sanitize_archive_path(entry_name); if (!sanitized) { zip_close(archive); return ExtractionResult::failure("The ZIP archive contains an unsafe installer path."); } installer_candidates.emplace_back(index, *sanitized); } if (installer_candidates.empty()) { zip_close(archive); return ExtractionResult::failure( "The ZIP archive does not contain an installer (.exe or .msi)."); } if (installer_candidates.size() > 1) { zip_close(archive); return ExtractionResult::failure( "The ZIP archive contains multiple installer candidates. Keep only one .exe or .msi file in the package."); } const auto [index, relative_path] = installer_candidates.front(); auto result = extract_entry(archive, index, destination_root, relative_path); zip_close(archive); return result; } ================================================ FILE: app/lib/UpdateFeed.cpp ================================================ #include "UpdateFeed.hpp" #include #include #include #include #if __has_include() #include #elif __has_include() #include #else #error "jsoncpp headers not found. Install jsoncpp development files." #endif namespace { std::string trim_copy(const std::string& value) { auto trimmed = value; auto not_space = [](unsigned char ch) { return !std::isspace(ch); }; trimmed.erase(trimmed.begin(), std::find_if(trimmed.begin(), trimmed.end(), not_space)); trimmed.erase(std::find_if(trimmed.rbegin(), trimmed.rend(), not_space).base(), trimmed.end()); return trimmed; } std::string normalized_sha256(std::string value) { value = trim_copy(value); std::transform(value.begin(), value.end(), value.begin(), [](unsigned char ch) { return static_cast(std::tolower(ch)); }); return value; } const char* platform_key(UpdateFeed::Platform platform) { switch (platform) { case UpdateFeed::Platform::Windows: return "windows"; case UpdateFeed::Platform::MacOS: return "macos"; case UpdateFeed::Platform::Linux: return "linux"; } return "linux"; } bool has_platform_streams(const Json::Value& update) { return (update.isMember("windows") && update["windows"].isObject()) || (update.isMember("macos") && update["macos"].isObject()) || (update.isMember("linux") && update["linux"].isObject()); } const Json::Value* resolve_stream_root(const Json::Value& update, UpdateFeed::Platform platform) { const char* key = platform_key(platform); if (update.isMember("streams") && update["streams"].isObject()) { const Json::Value& streams = update["streams"]; if (streams.isMember(key) && streams[key].isObject()) { return &streams[key]; } if (has_platform_streams(streams)) { return nullptr; } } if (update.isMember(key) && update[key].isObject()) { return &update[key]; } if (has_platform_streams(update)) { return nullptr; } if (update.isObject()) { return &update; } return nullptr; } std::string string_member(const Json::Value& object, const char* key) { if (object.isMember(key) && object[key].isString()) { return trim_copy(object[key].asString()); } return {}; } } // namespace UpdateFeed::Platform UpdateFeed::current_platform() { #if defined(_WIN32) return Platform::Windows; #elif defined(__APPLE__) return Platform::MacOS; #else return Platform::Linux; #endif } std::optional UpdateFeed::parse_for_current_platform(const std::string& update_json) { return parse_for_platform(update_json, current_platform()); } std::optional UpdateFeed::parse_for_platform(const std::string& update_json, Platform platform) { Json::CharReaderBuilder reader_builder; Json::Value root; std::string errors; std::unique_ptr reader(reader_builder.newCharReader()); if (!reader->parse(update_json.c_str(), update_json.c_str() + update_json.length(), &root, &errors)) { throw std::runtime_error("JSON Parse Error: " + errors); } if (!root.isMember("update") || !root["update"].isObject()) { return std::nullopt; } const Json::Value& update = root["update"]; const Json::Value* stream = resolve_stream_root(update, platform); if (!stream || !stream->isObject()) { return std::nullopt; } UpdateInfo info; info.current_version = string_member(*stream, "current_version"); info.min_version = string_member(*stream, "min_version"); info.download_url = string_member(*stream, "download_url"); info.release_notes_url = string_member(*stream, "release_notes_url"); info.installer_url = string_member(*stream, "installer_url"); info.installer_sha256 = normalized_sha256(string_member(*stream, "installer_sha256")); if (info.min_version.empty()) { info.min_version = "0.0.0"; } if (info.download_url.empty() && !info.installer_url.empty()) { info.download_url = info.installer_url; } if (info.current_version.empty() || !info.has_download_target()) { return std::nullopt; } return info; } ================================================ FILE: app/lib/UpdateInstaller.cpp ================================================ #include "UpdateInstaller.hpp" #include "UpdateArchiveExtractor.hpp" #include "Logger.hpp" #include "Utils.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef AI_FILE_SORTER_TEST_BUILD #include "UpdateInstallerTestAccess.hpp" #endif #ifdef _WIN32 #include #endif namespace { template void update_installer_log(spdlog::level::level_enum level, const char* fmt, Args&&... args) { auto message = fmt::format(fmt::runtime(fmt), std::forward(args)...); if (auto logger = Logger::get_logger("core_logger")) { logger->log(level, "{}", message); } else { std::fprintf(stderr, "%s\n", message.c_str()); } } std::string ascii_lower_copy(std::string value) { std::transform(value.begin(), value.end(), value.begin(), [](unsigned char ch) { return static_cast(std::tolower(ch)); }); return value; } void configure_tls(CURL* curl) { #if defined(_WIN32) const auto cert_path = Utils::ensure_ca_bundle(); curl_easy_setopt(curl, CURLOPT_CAINFO, cert_path.string().c_str()); #else (void)curl; #endif } std::string normalize_sha256(std::string value) { value.erase(std::remove_if(value.begin(), value.end(), [](unsigned char ch) { return std::isspace(ch) != 0; }), value.end()); std::transform(value.begin(), value.end(), value.begin(), [](unsigned char ch) { return static_cast(std::tolower(ch)); }); return value; } std::string safe_version_fragment(std::string version) { std::transform(version.begin(), version.end(), version.begin(), [](unsigned char ch) { if (std::isalnum(ch) || ch == '.' || ch == '_' || ch == '-') { return static_cast(ch); } return '_'; }); return version; } std::string installer_file_name_from_url(const std::string& url) { const QUrl parsed = QUrl::fromUserInput(QString::fromStdString(url)); QString file_name = QFileInfo(parsed.path()).fileName(); if (file_name.isEmpty()) { file_name = QStringLiteral("aifs-update-installer"); } return file_name.toStdString(); } bool is_archive_package(const std::filesystem::path& path) { return UpdateArchiveExtractor::supports_archive(path); } bool replace_file(const std::filesystem::path& source, const std::filesystem::path& target, std::string& error) { #ifdef _WIN32 if (MoveFileExW(source.c_str(), target.c_str(), MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH)) { return true; } error = std::system_category().message(static_cast(GetLastError())); return false; #else std::error_code ec; std::filesystem::rename(source, target, ec); if (!ec) { return true; } error = ec.message(); return false; #endif } FILE* open_binary_file_for_write(const std::filesystem::path& path) { #ifdef _WIN32 return _wfopen(path.c_str(), L"wb"); #else return std::fopen(path.c_str(), "wb"); #endif } size_t write_data(void* ptr, size_t size, size_t nmemb, FILE* stream) { return std::fwrite(ptr, size, nmemb, stream); } struct DownloadContext { UpdateInstaller::ProgressCallback progress_cb; UpdateInstaller::CancelCheck cancel_check; }; int progress_callback(void* clientp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t, curl_off_t) { auto* context = static_cast(clientp); if (context->cancel_check && context->cancel_check()) { return 1; } if (context->progress_cb) { const double progress = dltotal > 0 ? static_cast(dlnow) / static_cast(dltotal) : 0.0; const std::string message = dltotal > 0 ? fmt::format("Downloaded {} / {}", Utils::format_size(dlnow), Utils::format_size(dltotal)) : fmt::format("Downloaded {}", Utils::format_size(dlnow)); context->progress_cb(progress, message); } return 0; } } // namespace UpdateInstaller::UpdateInstaller(Settings& settings, DownloadFunction download_fn, LaunchFunction launch_fn) : settings_(settings), download_fn_(download_fn ? std::move(download_fn) : UpdateInstaller::default_download), launch_fn_(launch_fn ? std::move(launch_fn) : UpdateInstaller::default_launch) { } UpdateInstaller::DownloadCanceledError::DownloadCanceledError() : std::runtime_error("Download cancelled") { } bool UpdateInstaller::supports_auto_install(const UpdateInfo& info) const { #if defined(_WIN32) return !info.installer_url.empty() && !info.installer_sha256.empty(); #else (void)info; return false; #endif } UpdatePreparationResult UpdateInstaller::prepare(const UpdateInfo& info, ProgressCallback progress_cb, CancelCheck cancel_check) const { if (info.installer_url.empty()) { return UpdatePreparationResult::failed("No installer URL is available for this update."); } if (info.installer_sha256.empty()) { return UpdatePreparationResult::failed("No installer SHA-256 is available for this update."); } const auto package_path = package_path_for(info); const auto partial_path = std::filesystem::path(package_path.string() + ".part"); const auto extracted_root = extracted_installer_root_for(package_path); std::error_code ec; std::filesystem::create_directories(package_path.parent_path(), ec); if (ec) { return UpdatePreparationResult::failed("Failed to create updater cache directory: " + ec.message()); } const auto finalize_prepared_package = [&]() -> UpdatePreparationResult { if (!is_archive_package(package_path)) { return UpdatePreparationResult::ready(package_path); } std::filesystem::remove_all(extracted_root, ec); ec.clear(); if (progress_cb) { progress_cb(1.0, "Extracting installer from update package"); } const auto extraction = UpdateArchiveExtractor::extract_installer(package_path, extracted_root); if (!extraction.ok()) { return UpdatePreparationResult::failed(extraction.message); } return UpdatePreparationResult::ready(extraction.installer_path); }; if (progress_cb) { progress_cb(0.0, "Checking cached installer"); } if (verify_file(package_path, info.installer_sha256)) { return finalize_prepared_package(); } std::filesystem::remove(package_path, ec); ec.clear(); std::filesystem::remove(partial_path, ec); ec.clear(); std::filesystem::remove_all(extracted_root, ec); try { download_fn_(info.installer_url, partial_path, progress_cb, cancel_check); if (progress_cb) { progress_cb(1.0, "Verifying installer"); } if (!verify_file(partial_path, info.installer_sha256)) { std::filesystem::remove(partial_path, ec); return UpdatePreparationResult::failed("The downloaded installer failed SHA-256 verification."); } std::string replace_error; if (!replace_file(partial_path, package_path, replace_error)) { std::filesystem::remove(partial_path, ec); return UpdatePreparationResult::failed("Failed to finalize installer download: " + replace_error); } return finalize_prepared_package(); } catch (const DownloadCanceledError&) { std::filesystem::remove(partial_path, ec); return UpdatePreparationResult::canceled("Download cancelled"); } catch (const std::exception& ex) { std::filesystem::remove(partial_path, ec); return UpdatePreparationResult::failed(ex.what()); } } bool UpdateInstaller::launch(const std::filesystem::path& installer_path) const { return launch_fn_(installer_path); } std::filesystem::path UpdateInstaller::updates_dir() const { return Utils::utf8_to_path(settings_.get_config_dir()) / "updates"; } std::filesystem::path UpdateInstaller::package_path_for(const UpdateInfo& info) const { const std::string file_name = installer_file_name_from_url(info.installer_url); const std::string version_prefix = "v" + safe_version_fragment(info.current_version) + "-"; return updates_dir() / (version_prefix + file_name); } std::filesystem::path UpdateInstaller::extracted_installer_root_for(const std::filesystem::path& package_path) const { return package_path.parent_path() / (package_path.filename().string() + ".contents"); } std::string UpdateInstaller::compute_sha256(const std::filesystem::path& path) const { QFile file(QString::fromStdString(Utils::path_to_utf8(path))); if (!file.open(QIODevice::ReadOnly)) { throw std::runtime_error("Failed to open installer for SHA-256 verification."); } QCryptographicHash hash(QCryptographicHash::Sha256); while (!file.atEnd()) { const QByteArray chunk = file.read(1 << 20); if (chunk.isEmpty() && file.error() != QFile::NoError) { throw std::runtime_error("Failed while reading installer for SHA-256 verification."); } hash.addData(chunk); } return hash.result().toHex().toStdString(); } bool UpdateInstaller::verify_file(const std::filesystem::path& path, const std::string& expected_sha256) const { if (expected_sha256.empty()) { return false; } std::error_code ec; if (!std::filesystem::exists(path, ec) || ec) { return false; } try { return compute_sha256(path) == normalize_sha256(expected_sha256); } catch (const std::exception& ex) { update_installer_log(spdlog::level::warn, "Failed to verify installer '{}': {}", path.string(), ex.what()); return false; } } UpdateInstaller::LaunchRequest UpdateInstaller::build_launch_request(const std::filesystem::path& installer_path) { const std::string installer = Utils::path_to_utf8(installer_path); if (ascii_lower_copy(installer_path.extension().string()) == ".msi") { return LaunchRequest{ "msiexec.exe", {"/i", installer} }; } return LaunchRequest{installer, {}}; } void UpdateInstaller::default_download(const std::string& url, const std::filesystem::path& destination_path, ProgressCallback progress_cb, CancelCheck cancel_check) { CURL* curl = curl_easy_init(); if (!curl) { throw std::runtime_error("Failed to initialize cURL for installer download."); } FILE* file = open_binary_file_for_write(destination_path); if (!file) { curl_easy_cleanup(curl); throw std::runtime_error("Failed to open the installer destination for writing."); } DownloadContext context{ std::move(progress_cb), std::move(cancel_check) }; try { configure_tls(curl); } catch (const std::exception& ex) { std::fclose(file); curl_easy_cleanup(curl); throw std::runtime_error(std::string("Failed to stage CA bundle: ") + ex.what()); } curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L); curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10L); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &write_data); curl_easy_setopt(curl, CURLOPT_WRITEDATA, file); curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L); curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, &progress_callback); curl_easy_setopt(curl, CURLOPT_XFERINFODATA, &context); const CURLcode res = curl_easy_perform(curl); std::fclose(file); curl_easy_cleanup(curl); if (res == CURLE_ABORTED_BY_CALLBACK) { throw DownloadCanceledError(); } if (res != CURLE_OK) { throw std::runtime_error(std::string("Installer download failed: ") + curl_easy_strerror(res)); } } bool UpdateInstaller::default_launch(const std::filesystem::path& installer_path) { #if defined(_WIN32) const auto request = build_launch_request(installer_path); QStringList arguments; arguments.reserve(static_cast(request.arguments.size())); for (const auto& argument : request.arguments) { arguments.push_back(QString::fromStdString(argument)); } return QProcess::startDetached(QString::fromStdString(request.program), arguments); #else (void)installer_path; return false; #endif } #ifdef AI_FILE_SORTER_TEST_BUILD UpdateInstaller::LaunchRequest UpdateInstallerTestAccess::build_launch_request(const std::filesystem::path& installer_path) { return UpdateInstaller::build_launch_request(installer_path); } #endif ================================================ FILE: app/lib/Updater.cpp ================================================ #include "Updater.hpp" #include "Logger.hpp" #include "UpdaterBuildConfig.hpp" #include "UpdaterLaunchOptions.hpp" #include "Utils.hpp" #include "app_version.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef AI_FILE_SORTER_TEST_BUILD #include "UpdaterTestAccess.hpp" #endif namespace { template void updater_log(spdlog::level::level_enum level, const char* fmt, Args&&... args) { auto message = fmt::format(fmt::runtime(fmt), std::forward(args)...); if (auto logger = Logger::get_logger("core_logger")) { logger->log(level, "{}", message); } else { std::fprintf(stderr, "%s\n", message.c_str()); } } std::string trim_copy(const std::string& value) { auto trimmed = value; auto not_space = [](unsigned char ch) { return !std::isspace(ch); }; trimmed.erase(trimmed.begin(), std::find_if(trimmed.begin(), trimmed.end(), not_space)); trimmed.erase(std::find_if(trimmed.rbegin(), trimmed.rend(), not_space).base(), trimmed.end()); return trimmed; } std::optional env_string(const char* key) { const char* value = std::getenv(key); if (!value || value[0] == '\0') { return std::nullopt; } const std::string trimmed = trim_copy(value); if (trimmed.empty()) { return std::nullopt; } return trimmed; } bool env_flag_enabled(const char* key) { const auto value = env_string(key); if (!value) { return false; } std::string lowered = *value; std::transform(lowered.begin(), lowered.end(), lowered.begin(), [](unsigned char ch) { return static_cast(std::tolower(ch)); }); return lowered == "1" || lowered == "true" || lowered == "yes" || lowered == "on"; } std::string normalized_sha256_copy(std::string value) { value.erase(std::remove_if(value.begin(), value.end(), [](unsigned char ch) { return std::isspace(ch) != 0; }), value.end()); std::transform(value.begin(), value.end(), value.begin(), [](unsigned char ch) { return static_cast(std::tolower(ch)); }); return value; } void throw_for_http_status(long http_code) { if (http_code == 401) { throw std::runtime_error("Authentication Error: Invalid or missing API key."); } if (http_code == 403) { throw std::runtime_error("Authorization Error: API key does not have sufficient permissions."); } if (http_code >= 500) { throw std::runtime_error("Server Error: The server returned an error. Status code: " + std::to_string(http_code)); } if (http_code >= 400) { throw std::runtime_error("Client Error: The server returned an error. Status code: " + std::to_string(http_code)); } } void configure_tls(CURL* curl) { #if defined(_WIN32) const auto cert_path = Utils::ensure_ca_bundle(); curl_easy_setopt(curl, CURLOPT_CAINFO, cert_path.string().c_str()); #else (void)curl; #endif } void open_download_url(const std::string& url) { const QUrl qurl(QString::fromStdString(url)); if (!QDesktopServices::openUrl(qurl)) { updater_log(spdlog::level::err, "Failed to open URL: {}", url); } } } Updater::Updater(Settings& settings) : settings(settings), installer(settings), update_spec_file_url_(env_string("UPDATE_SPEC_FILE_URL")), open_download_url_fn_([](const std::string& url) { open_download_url(url); }), quit_fn_([]() { QApplication::quit(); }) {} void Updater::check_updates() { if (auto live_test = resolve_live_test_update()) { update_info = std::move(live_test); } else { std::string update_json = fetch_update_metadata(); update_info = UpdateFeed::parse_for_current_platform(update_json); } if (!update_info) { update_info.reset(); return; } if (APP_VERSION >= string_to_Version(update_info->current_version)) { update_info.reset(); } } std::optional Updater::resolve_live_test_update() const { #if !defined(_WIN32) return std::nullopt; #else if (!env_flag_enabled(UpdaterLaunchOptions::kLiveTestModeEnv)) { return std::nullopt; } const auto installer_url = env_string(UpdaterLaunchOptions::kLiveTestUrlEnv); if (!installer_url) { throw std::runtime_error( "Updater live test mode requires an installer URL via " "--updater-live-test-url or AI_FILE_SORTER_UPDATER_TEST_URL."); } const auto installer_sha256 = env_string(UpdaterLaunchOptions::kLiveTestSha256Env); if (!installer_sha256) { throw std::runtime_error( "Updater live test mode requires an archive SHA-256 via " "--updater-live-test-sha256 or AI_FILE_SORTER_UPDATER_TEST_SHA256."); } UpdateInfo info; info.current_version = env_string(UpdaterLaunchOptions::kLiveTestVersionEnv) .value_or(APP_VERSION.to_string() + ".1"); info.min_version = env_string(UpdaterLaunchOptions::kLiveTestMinVersionEnv) .value_or("0.0.0"); info.download_url = *installer_url; info.installer_url = *installer_url; info.installer_sha256 = normalized_sha256_copy(*installer_sha256); updater_log(spdlog::level::info, "Updater live test mode enabled for package '{}'", info.installer_url); return info; #endif } bool Updater::is_update_available() { check_updates(); return update_info.has_value(); } bool Updater::is_update_required() { return string_to_Version(update_info.value_or(UpdateInfo()).min_version) > APP_VERSION; } void Updater::begin() { if (!UpdaterBuildConfig::update_checks_enabled()) { updater_log(spdlog::level::info, "Updater checks disabled for this build."); return; } this->update_future = std::async(std::launch::async, [this]() { try { if (is_update_available()) { QMetaObject::invokeMethod(QApplication::instance(), [this]() { if (is_update_required()) { display_update_dialog(true); } else if (!is_update_skipped()) { display_update_dialog(false); } }, Qt::QueuedConnection); } else { QMetaObject::invokeMethod(QApplication::instance(), []() { std::cout << "No updates available.\n"; }, Qt::QueuedConnection); } } catch (const std::exception &e) { QMetaObject::invokeMethod(QApplication::instance(), [msg = std::string(e.what())]() { updater_log(spdlog::level::err, "Updater encountered an error: {}", msg); }, Qt::QueuedConnection); } }); } bool Updater::is_update_skipped() { if (!update_info) { return false; } Version skipped_version = string_to_Version(settings.get_skipped_version()); return string_to_Version(update_info->current_version) <= skipped_version; } void Updater::display_update_dialog(bool is_required) { if (!update_info) { updater_log(spdlog::level::warn, "No update information available."); return; } QWidget* parent = QApplication::activeWindow(); const auto& info = update_info.value(); if (is_required) { show_required_update_dialog(info, parent); return; } show_optional_update_dialog(info, parent); } void Updater::show_required_update_dialog(const UpdateInfo& info, QWidget* parent) { while (true) { QMessageBox box(parent); box.setIcon(QMessageBox::Warning); box.setWindowTitle(QObject::tr("Required Update Available")); box.setText(QObject::tr("A required update is available. Please update to continue.\nIf you choose to quit, the application will close.")); QPushButton* update_now = box.addButton(QObject::tr("Update Now"), QMessageBox::AcceptRole); QPushButton* quit_button = box.addButton(QObject::tr("Quit"), QMessageBox::RejectRole); box.setDefaultButton(update_now); box.exec(); if (box.clickedButton() == update_now) { if (trigger_update_action(info, parent, true)) { return; } continue; } if (box.clickedButton() == quit_button) { quit_fn_(); return; } } } void Updater::show_optional_update_dialog(const UpdateInfo& info, QWidget* parent) { QMessageBox box(parent); box.setIcon(QMessageBox::Information); box.setWindowTitle(QObject::tr("Optional Update Available")); box.setText(QObject::tr("An optional update is available. Would you like to update now?")); QPushButton* update_now = box.addButton(QObject::tr("Update Now"), QMessageBox::AcceptRole); QPushButton* skip_button = box.addButton(QObject::tr("Skip This Version"), QMessageBox::RejectRole); QPushButton* cancel_button = box.addButton(QObject::tr("Cancel"), QMessageBox::DestructiveRole); box.setDefaultButton(update_now); box.exec(); if (box.clickedButton() == update_now) { trigger_update_action(info, parent, false); } else if (box.clickedButton() == skip_button) { settings.set_skipped_version(info.current_version); if (!settings.save()) { updater_log(spdlog::level::err, "Failed to save skipped version to settings."); } else { std::cout << "User chose to skip version " << info.current_version << "." << std::endl; } } else if (box.clickedButton() == cancel_button) { // No action needed; user dismissed the dialog. } } UpdatePreparationResult Updater::prepare_installer_update(const UpdateInfo& info, QWidget* parent) { QProgressDialog progress(parent); progress.setWindowTitle(QObject::tr("Downloading Update")); progress.setLabelText(QObject::tr("Downloading the update installer...")); progress.setCancelButtonText(QObject::tr("Cancel")); progress.setRange(0, 100); progress.setValue(0); progress.setMinimumDuration(0); progress.setWindowModality(Qt::ApplicationModal); progress.show(); QApplication::processEvents(); auto result = installer.prepare( info, [&](double value, const std::string& status) { const double clamped = std::clamp(value, 0.0, 1.0); progress.setValue(static_cast(clamped * 100.0)); if (!status.empty()) { progress.setLabelText(QString::fromStdString(status)); } QApplication::processEvents(); }, [&]() { QApplication::processEvents(); return progress.wasCanceled(); }); progress.setValue(result.status == UpdatePreparationResult::Status::Ready ? 100 : progress.value()); return result; } bool Updater::trigger_update_action(const UpdateInfo& info, QWidget* parent, bool quit_after_open) { #if defined(_WIN32) if (UpdaterBuildConfig::auto_install_enabled() && installer.supports_auto_install(info)) { const auto prepared = prepare_installer_update(info, parent); if (prepared.status == UpdatePreparationResult::Status::Canceled) { return false; } if (prepared.status == UpdatePreparationResult::Status::Failed) { return handle_update_error(info, QObject::tr("Failed to prepare the update installer.\n%1") .arg(QString::fromStdString(prepared.message)), parent, quit_after_open); } QMessageBox confirm(parent); confirm.setIcon(QMessageBox::Question); confirm.setWindowTitle(QObject::tr("Installer Ready")); confirm.setText(QObject::tr("Quit the app and launch the installer to update")); QPushButton* launch_button = confirm.addButton(QObject::tr("Quit and Launch Installer"), QMessageBox::AcceptRole); QPushButton* cancel_button = confirm.addButton(QObject::tr("Cancel"), QMessageBox::RejectRole); confirm.setDefaultButton(launch_button); confirm.exec(); if (confirm.clickedButton() != launch_button) { return false; } if (!installer.launch(prepared.installer_path)) { return handle_update_error(info, QObject::tr("The installer could not be launched."), parent, quit_after_open); } quit_fn_(); return true; } #endif if (info.download_url.empty()) { return handle_update_error(info, QObject::tr("No download target is available for this update."), parent, quit_after_open); } open_download_url_fn_(info.download_url); if (quit_after_open) { quit_fn_(); } return true; } bool Updater::handle_update_error(const UpdateInfo& info, const QString& message, QWidget* parent, bool quit_after_open) { QMessageBox box(parent); box.setIcon(QMessageBox::Critical); box.setWindowTitle(QObject::tr("Update Failed")); box.setText(message); QPushButton* ok_button = box.addButton(QMessageBox::Ok); QPushButton* manual_button = nullptr; if (!info.download_url.empty()) { manual_button = box.addButton(QObject::tr("Update manually"), QMessageBox::ActionRole); } box.setDefaultButton(ok_button); box.exec(); if (box.clickedButton() != manual_button) { return false; } open_download_url_fn_(info.download_url); if (quit_after_open) { quit_fn_(); } return true; } size_t WriteCallback(void* contents, size_t size, size_t nmemb, void* userp) { const auto total = size * nmemb; auto* buffer = static_cast(userp); buffer->append(static_cast(contents), total); return total; } std::string Updater::fetch_update_metadata() const { if (!update_spec_file_url_) { throw std::runtime_error("Environment variable UPDATE_SPEC_FILE_URL is not set"); } CURL *curl = curl_easy_init(); if (!curl) { throw std::runtime_error("Initialization Error: Failed to initialize cURL."); } CURLcode res; std::string response_string; try { configure_tls(curl); } catch (const std::exception& ex) { curl_easy_cleanup(curl); throw std::runtime_error(std::string("Failed to stage CA bundle: ") + ex.what()); } curl_easy_setopt(curl, CURLOPT_URL, update_spec_file_url_->c_str()); curl_easy_setopt(curl, CURLOPT_TIMEOUT, 5L); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_string); struct curl_slist *headers = NULL; headers = curl_slist_append(headers, "Content-Type: application/json"); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); // Perform the request res = curl_easy_perform(curl); // Handle errors if (res != CURLE_OK) { curl_slist_free_all(headers); curl_easy_cleanup(curl); throw std::runtime_error("Network Error: " + std::string(curl_easy_strerror(res))); } // Check HTTP response code long http_code = 0; curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code); curl_slist_free_all(headers); curl_easy_cleanup(curl); throw_for_http_status(http_code); return response_string; } Version Updater::string_to_Version(const std::string& version_str) { if (version_str.empty()) { return Version{0, 0, 0}; } std::vector digits; std::istringstream stream(version_str); std::string segment; while (std::getline(stream, segment, '.')) { if (segment.empty()) { throw std::runtime_error("Invalid version string: " + version_str); } digits.push_back(std::stoi(segment)); } if (digits.empty()) { return Version{0, 0, 0}; } return Version{digits}; } Updater::~Updater() = default; #ifdef AI_FILE_SORTER_TEST_BUILD bool UpdaterTestAccess::is_update_available(Updater& updater) { return updater.is_update_available(); } std::optional UpdaterTestAccess::current_update_info(const Updater& updater) { return updater.update_info; } bool UpdaterTestAccess::has_update_task(const Updater& updater) { return updater.update_future.valid(); } void UpdaterTestAccess::wait_for_update_task(Updater& updater) { if (updater.update_future.valid()) { updater.update_future.wait(); } } void UpdaterTestAccess::set_open_download_url_handler(Updater& updater, std::function handler) { updater.open_download_url_fn_ = std::move(handler); } void UpdaterTestAccess::set_quit_handler(Updater& updater, std::function handler) { updater.quit_fn_ = std::move(handler); } bool UpdaterTestAccess::trigger_update_action(Updater& updater, const UpdateInfo& info, QWidget* parent, bool quit_after_open) { return updater.trigger_update_action(info, parent, quit_after_open); } bool UpdaterTestAccess::handle_update_error(Updater& updater, const UpdateInfo& info, const QString& message, QWidget* parent, bool quit_after_open) { return updater.handle_update_error(info, message, parent, quit_after_open); } #endif ================================================ FILE: app/lib/UpdaterLiveTestConfig.cpp ================================================ #include "UpdaterLiveTestConfig.hpp" #include "IniConfig.hpp" #include "Utils.hpp" #include #include #include #include namespace { std::string trim_copy(const std::string& value) { const auto begin = value.find_first_not_of(" \t\r\n"); if (begin == std::string::npos) { return {}; } const auto end = value.find_last_not_of(" \t\r\n"); return value.substr(begin, end - begin + 1); } std::optional read_ini_value(const IniConfig& config, const std::string& section, const std::initializer_list& keys) { for (const char* key : keys) { if (!config.hasValue(section, key)) { continue; } const std::string value = trim_copy(config.getValue(section, key)); if (!value.empty()) { return value; } } return std::nullopt; } std::optional read_live_test_value(const IniConfig& config, const std::initializer_list& keys) { if (auto value = read_ini_value(config, "LiveTest", keys)) { return value; } return read_ini_value(config, "", keys); } } // namespace std::optional find_updater_live_test_ini(const std::filesystem::path& executable_path) { std::filesystem::path base_dir = executable_path; if (!base_dir.empty()) { if (!base_dir.has_filename() || base_dir.extension().empty()) { // Treat an extensionless path as a directory candidate. } else { base_dir = base_dir.parent_path(); } } if (base_dir.empty()) { return std::nullopt; } const auto candidate = base_dir / "live-test.ini"; std::error_code ec; if (std::filesystem::exists(candidate, ec) && !ec) { return candidate; } return std::nullopt; } std::optional load_missing_values_from_live_test_ini( UpdaterLiveTestConfig& config, const std::filesystem::path& executable_path) { if (!config.enabled) { return std::nullopt; } const auto ini_path = find_updater_live_test_ini(executable_path); if (!ini_path) { return std::nullopt; } IniConfig ini; if (!ini.load(Utils::path_to_utf8(*ini_path))) { throw std::runtime_error("Failed to load updater live test file: " + Utils::path_to_utf8(*ini_path)); } if (!config.installer_url) { config.installer_url = read_live_test_value(ini, {"download_url", "installer_url", "url"}); } if (!config.installer_sha256) { config.installer_sha256 = read_live_test_value(ini, {"sha256", "installer_sha256"}); } if (!config.current_version) { config.current_version = read_live_test_value(ini, {"current_version"}); } if (!config.min_version) { config.min_version = read_live_test_value(ini, {"min_version"}); } return ini_path; } ================================================ FILE: app/lib/Utils.cpp ================================================ #include "Utils.hpp" #include "Logger.hpp" #include "TestHooks.hpp" #include #include #include // for memset #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace { template void log_core(spdlog::level::level_enum level, const char* fmt, Args&&... args) { auto message = fmt::format(fmt::runtime(fmt), std::forward(args)...); if (auto logger = Logger::get_logger("core_logger")) { logger->log(level, "{}", message); } else { std::fprintf(stderr, "%s\n", message.c_str()); } } std::string to_forward_slashes(std::string value) { std::replace(value.begin(), value.end(), '\\', '/'); return value; } std::string trim_leading_separators(std::string value) { auto is_separator = [](char ch) { return ch == '/' || ch == '\\'; }; value.erase(value.begin(), std::find_if(value.begin(), value.end(), [&](char ch) { return !is_separator(ch); })); return value; } std::optional try_utf8_to_path(const std::string& value) { try { return Utils::utf8_to_path(value); } catch (const std::exception&) { return std::nullopt; } } std::vector collect_user_prefixes() { std::vector prefixes; auto append = [&](const char* candidate) { if (!candidate || *candidate == '\0') { return; } const std::string raw(candidate); if (auto converted = try_utf8_to_path(raw)) { prefixes.push_back(to_forward_slashes(Utils::path_to_utf8(*converted))); } else { prefixes.push_back(to_forward_slashes(raw)); } }; append(std::getenv("HOME")); append(std::getenv("USERPROFILE")); if (prefixes.empty() && Utils::is_os_windows()) { if (const char* username = std::getenv("USERNAME")) { prefixes.emplace_back(std::string("C:/Users/") + username); } } return prefixes; } std::function& cuda_availability_probe() { static std::function probe; return probe; } std::function()>& cuda_memory_probe() { static std::function()> probe; return probe; } std::optional strip_prefix(const std::string& path, const std::vector& prefixes) { for (const auto& original_prefix : prefixes) { if (original_prefix.empty()) { continue; } std::string prefix = original_prefix; if (prefix.back() != '/') { prefix.push_back('/'); } if (path.size() < prefix.size()) { continue; } if (!std::equal(prefix.begin(), prefix.end(), path.begin())) { continue; } std::string trimmed = trim_leading_separators(path.substr(prefix.size())); if (!trimmed.empty()) { return trimmed; } } return std::nullopt; } } #ifdef _WIN32 #include #include #elif __linux__ #include #include #include #include #include #elif __APPLE__ #include #include #include #include #include #endif #include #include #include #include #ifdef _WIN32 #include #include #endif // Shortcuts for loading libraries on different OSes #ifdef _WIN32 using LibraryHandle = HMODULE; LibraryHandle loadLibrary(const char* name) { return LoadLibraryA(name); } void* getSymbol(LibraryHandle lib, const char* symbol) { return reinterpret_cast(GetProcAddress(lib, symbol)); } void closeLibrary(LibraryHandle lib) { FreeLibrary(lib); } #else using LibraryHandle = void*; LibraryHandle loadLibrary(const char* name) { return dlopen(name, RTLD_LAZY); } void* getSymbol(LibraryHandle lib, const char* symbol) { return dlsym(lib, symbol); } void closeLibrary(LibraryHandle lib) { dlclose(lib); } #endif bool Utils::is_network_available() { #ifdef _WIN32 DWORD flags; return InternetGetConnectedState(&flags, 0); #else addrinfo hints{}; hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; addrinfo* result = nullptr; const int rc = getaddrinfo("www.google.com", "80", &hints, &result); if (result) { freeaddrinfo(result); } return rc == 0; #endif } std::string Utils::get_executable_path() { #ifdef _WIN32 char result[MAX_PATH]; GetModuleFileNameA(NULL, result, MAX_PATH); return std::string(result); #elif __linux__ char result[PATH_MAX]; ssize_t count = readlink("/proc/self/exe", result, PATH_MAX); return (count != -1) ? std::string(result, count) : ""; #elif __APPLE__ char result[PATH_MAX]; uint32_t size = sizeof(result); if (_NSGetExecutablePath(result, &size) == 0) { return std::string(result); } else { throw std::runtime_error("Path buffer too small"); } #else throw std::runtime_error("Unsupported platform"); #endif } std::filesystem::path Utils::ensure_ca_bundle() { static std::once_flag init_flag; static std::filesystem::path cached_path; static std::exception_ptr init_error; std::call_once(init_flag, []() { try { std::filesystem::path exe_path = std::filesystem::path(get_executable_path()); std::filesystem::path cert_dir = exe_path.parent_path() / "certs"; std::filesystem::path cert_file = cert_dir / "cacert.pem"; bool needs_write = true; if (std::filesystem::exists(cert_file)) { std::error_code ec; auto size = std::filesystem::file_size(cert_file, ec); needs_write = ec ? true : (size == 0); } if (needs_write) { ensure_directory_exists(cert_dir.string()); QFile resource(QStringLiteral(":/net/quicknode/AIFileSorter/certs/cacert.pem")); if (!resource.open(QIODevice::ReadOnly)) { throw std::runtime_error("Failed to open embedded CA bundle resource"); } const QByteArray data = resource.readAll(); resource.close(); QFile output(QString::fromStdString(cert_file.string())); if (!output.open(QIODevice::WriteOnly | QIODevice::Truncate)) { throw std::runtime_error("Failed to create CA bundle file at " + cert_file.string()); } if (output.write(data) != data.size()) { output.close(); throw std::runtime_error("Failed to write CA bundle file at " + cert_file.string()); } output.close(); } cached_path = cert_file; } catch (...) { init_error = std::current_exception(); } }); if (init_error) { std::rethrow_exception(init_error); } return cached_path; } std::string Utils::path_to_utf8(const std::filesystem::path& path) { #ifdef _WIN32 if (path.empty()) { return {}; } const std::wstring native = path.native(); if (native.empty()) { return {}; } const int required = WideCharToMultiByte( CP_UTF8, 0, native.c_str(), -1, nullptr, 0, nullptr, nullptr); if (required <= 0) { throw std::system_error( std::error_code(GetLastError(), std::system_category()), "WideCharToMultiByte failed while converting path to UTF-8"); } std::string buffer(static_cast(required - 1), '\0'); const int written = WideCharToMultiByte( CP_UTF8, 0, native.c_str(), -1, buffer.data(), required, nullptr, nullptr); if (written <= 0) { throw std::system_error( std::error_code(GetLastError(), std::system_category()), "WideCharToMultiByte failed while converting path to UTF-8"); } buffer.resize(static_cast(written - 1)); return buffer; #else return path.generic_string(); #endif } std::filesystem::path Utils::utf8_to_path(const std::string& utf8_path) { #ifdef _WIN32 if (utf8_path.empty()) { return {}; } const int required = MultiByteToWideChar( CP_UTF8, MB_ERR_INVALID_CHARS, utf8_path.c_str(), -1, nullptr, 0); if (required <= 0) { throw std::system_error( std::error_code(GetLastError(), std::system_category()), "MultiByteToWideChar failed while converting UTF-8 to path"); } std::wstring buffer(static_cast(required - 1), L'\0'); const int written = MultiByteToWideChar( CP_UTF8, MB_ERR_INVALID_CHARS, utf8_path.c_str(), -1, buffer.data(), required); if (written <= 0) { throw std::system_error( std::error_code(GetLastError(), std::system_category()), "MultiByteToWideChar failed while converting UTF-8 to path"); } buffer.resize(static_cast(written - 1)); return std::filesystem::path(buffer); #else return std::filesystem::path(utf8_path); #endif } bool Utils::is_valid_directory(const char *path) { if (!path || *path == '\0') { return false; } #ifdef _WIN32 std::filesystem::path fs_path; try { fs_path = utf8_to_path(path); } catch (const std::exception&) { return false; } #else std::filesystem::path fs_path(path); #endif std::error_code ec; return std::filesystem::is_directory(fs_path, ec); } namespace { int hex_char_value(char c) { if (c >= '0' && c <= '9') { return c - '0'; } if (c >= 'a' && c <= 'f') { return 10 + (c - 'a'); } if (c >= 'A' && c <= 'F') { return 10 + (c - 'A'); } return -1; } unsigned char combine_hex_pair(char high, char low) { const int hi = hex_char_value(high); const int lo = hex_char_value(low); if (hi < 0 || lo < 0) { throw std::invalid_argument("Hex string contains invalid characters"); } return static_cast((hi << 4) | lo); } } std::vector Utils::hex_to_vector(const std::string& hex) { if (hex.size() % 2 != 0) { throw std::invalid_argument("Hex string must have even length"); } std::vector data; data.reserve(hex.size() / 2); for (std::size_t i = 0; i < hex.size(); i += 2) { data.push_back(combine_hex_pair(hex[i], hex[i + 1])); } return data; } const char* Utils::to_cstr(const std::u8string& u8str) { return reinterpret_cast(u8str.c_str()); } void Utils::ensure_directory_exists(const std::string &dir) { try { if (!std::filesystem::exists(dir)) { std::filesystem::create_directories(dir); } } catch (const std::exception &e) { log_core(spdlog::level::err, "Error creating log directory: {}", e.what()); throw; } } bool Utils::is_os_windows() { #if defined(_WIN32) return true; #else return false; #endif } bool Utils::is_os_macos() { #if defined(__APPLE__) return true; #else return false; #endif } bool Utils::is_os_linux() { #if defined(__linux__) return true; #else return false; #endif } std::string Utils::format_size(curl_off_t bytes) { char buffer[64]; if (bytes >= (1LL << 30)) snprintf(buffer, sizeof(buffer), "%.2f GB", bytes / (double)(1LL << 30)); else if (bytes >= (1LL << 20)) snprintf(buffer, sizeof(buffer), "%.2f MB", bytes / (double)(1LL << 20)); else if (bytes >= (1LL << 10)) snprintf(buffer, sizeof(buffer), "%.2f KB", bytes / (double)(1LL << 10)); else snprintf(buffer, sizeof(buffer), "%.2f B", bytes / (double)(1LL << 10)); return buffer; } int Utils::get_ngl(int vram_mb) { if (vram_mb < 2048) return 0; int step = (vram_mb - 2048) / 512; return std::min(14 + step * 2, 32); } std::optional Utils::query_cuda_memory() { if (auto& probe = cuda_memory_probe()) { return probe(); } #ifdef _WIN32 std::string dllName = get_cudart_dll_name(); LibraryHandle lib = loadLibrary(dllName.c_str()); #else LibraryHandle lib = loadLibrary("libcudart.so"); if (!lib) { lib = loadLibrary("libcudart.so.12"); } #endif if (!lib) { log_core(spdlog::level::err, "Failed to load CUDA runtime library."); return std::nullopt; } using cudaMemGetInfo_t = int (*)(size_t*, size_t*); using cudaGetDeviceProperties_t = int (*)(void*, int); auto cudaMemGetInfo = reinterpret_cast(getSymbol(lib, "cudaMemGetInfo")); auto cudaGetDeviceProperties = reinterpret_cast(getSymbol(lib, "cudaGetDeviceProperties")); if (!cudaMemGetInfo) { log_core(spdlog::level::err, "Failed to resolve required CUDA runtime symbols."); closeLibrary(lib); return std::nullopt; } size_t free_bytes = 0; size_t total_bytes = 0; size_t device_total_bytes = 0; if (cudaMemGetInfo(&free_bytes, &total_bytes) != 0) { log_core(spdlog::level::warn, "Warning: cudaMemGetInfo failed"); free_bytes = 0; total_bytes = 0; } if (cudaGetDeviceProperties) { // Query total device memory from cudaGetDeviceProperties for reference. constexpr size_t cudaDevicePropSize = 2560; alignas(std::max_align_t) uint8_t prop_buffer[cudaDevicePropSize]; std::memset(prop_buffer, 0, sizeof(prop_buffer)); if (cudaGetDeviceProperties(prop_buffer, 0) == 0) { struct DevicePropShim { char name[256]; size_t totalGlobalMem; }; auto *prop = reinterpret_cast(prop_buffer); device_total_bytes = prop->totalGlobalMem; constexpr size_t kMinReasonableBytes = 64ULL * 1024ULL * 1024ULL; constexpr size_t kMaxReasonableBytes = 1ULL << 50; // 1 PiB if (device_total_bytes < kMinReasonableBytes || device_total_bytes > kMaxReasonableBytes) { device_total_bytes = 0; } } } if (total_bytes == 0 && device_total_bytes != 0) { total_bytes = device_total_bytes; } closeLibrary(lib); if (free_bytes == 0 && total_bytes == 0) { log_core(spdlog::level::warn, "CUDA memory metrics unavailable (both free and total bytes are zero)."); return std::nullopt; } CudaMemoryInfo info; info.free_bytes = free_bytes; info.total_bytes = total_bytes; info.device_total_bytes = device_total_bytes; return info; } int Utils::compute_ngl_from_cuda_memory(const CudaMemoryInfo& info) { size_t usable_bytes = (info.free_bytes > 0) ? info.free_bytes : info.total_bytes; if (usable_bytes == 0) { return 0; } int vram_mb = static_cast(usable_bytes / (1024 * 1024)); return get_ngl(vram_mb); } int Utils::determine_ngl_cuda() { auto info = query_cuda_memory(); if (!info.has_value()) { return 0; } return compute_ngl_from_cuda_memory(*info); } #ifdef _WIN32 std::optional packaged_llm_path() { // Detect MSIX/packaged context and build LocalCache path that is removed on uninstall. UINT32 length = 0; LONG rc = GetCurrentPackageFamilyName(&length, nullptr); if (rc == APPMODEL_ERROR_NO_PACKAGE) { return std::nullopt; // not packaged } if (rc != ERROR_INSUFFICIENT_BUFFER) { return std::nullopt; } std::wstring family; family.resize(length); rc = GetCurrentPackageFamilyName(&length, family.data()); if (rc != ERROR_SUCCESS) { return std::nullopt; } if (length > 0 && family[length - 1] == L'\0') { family.resize(length - 1); } const wchar_t* localAppData = _wgetenv(L"LOCALAPPDATA"); if (!localAppData || *localAppData == L'\0') { return std::nullopt; } std::filesystem::path base(localAppData); return base / L"Packages" / std::filesystem::path(family) / L"LocalCache" / L"aifilesorter" / L"llms"; } #endif template void Utils::run_on_main_thread(Func&& func) { auto task = std::make_shared>(std::forward(func)); if (auto* app = QCoreApplication::instance()) { QMetaObject::invokeMethod(app, [task]() { (*task)(); }, Qt::QueuedConnection); } else { (*task)(); } } std::string Utils::get_default_llm_destination() { const char* home = std::getenv("HOME"); if (Utils::is_os_windows()) { const char* appdata = std::getenv("APPDATA"); if (!appdata) throw std::runtime_error("APPDATA not set"); std::filesystem::path legacy = std::filesystem::path(appdata) / "aifilesorter" / "llms"; #ifdef _WIN32 if (auto packaged = packaged_llm_path()) { // Prefer the packaged LocalCache path; fall back to legacy if it already exists (backward compatibility). if (std::filesystem::exists(legacy)) { return legacy.string(); } return packaged->string(); } #endif return legacy.string(); } if (!home) throw std::runtime_error("HOME not set"); if (Utils::is_os_macos()) { return (std::filesystem::path(home) / "Library" / "Application Support" / "aifilesorter" / "llms").string(); } return (std::filesystem::path(home) / ".local" / "share" / "aifilesorter" / "llms").string(); } std::string Utils::get_file_name_from_url(std::string url) { auto last_slash = url.find_last_of('/'); if (last_slash == std::string::npos || last_slash == url.length() - 1) { throw std::runtime_error("Invalid download URL: can't extract filename"); } std::string filename = url.substr(last_slash + 1); return filename; } std::string Utils::make_default_path_to_file_from_download_url(std::string url) { std::string filename = get_file_name_from_url(url); std::string path_to_file = (std::filesystem::path(get_default_llm_destination()) / filename).string(); return path_to_file; } namespace { using cudaGetDeviceCount_t = int (*)(int*); using cudaSetDevice_t = int (*)(int); using cudaMemGetInfo_t = int (*)(size_t*, size_t*); LibraryHandle open_cuda_runtime() { #ifdef _WIN32 std::string dllName = Utils::get_cudart_dll_name(); if (dllName.empty()) { log_core(spdlog::level::warn, "[CUDA] DLL name is empty — likely failed to get CUDA version."); return nullptr; } LibraryHandle handle = loadLibrary(dllName.c_str()); log_core(spdlog::level::info, "[CUDA] Trying to load: {} => {}", dllName, handle ? "Success" : "Failure"); return handle; #else return loadLibrary("libcudart.so"); #endif } bool resolve_cuda_symbols(LibraryHandle handle, cudaGetDeviceCount_t& get_device_count, cudaSetDevice_t& set_device, cudaMemGetInfo_t& mem_get_info) { get_device_count = reinterpret_cast(getSymbol(handle, "cudaGetDeviceCount")); set_device = reinterpret_cast(getSymbol(handle, "cudaSetDevice")); mem_get_info = reinterpret_cast(getSymbol(handle, "cudaMemGetInfo")); log_core(spdlog::level::info, "[CUDA] Lookup cudaGetDeviceCount symbol: {}", get_device_count ? "Found" : "Not Found"); return get_device_count && set_device && mem_get_info; } } // namespace bool Utils::is_cuda_available() { log_core(spdlog::level::info, "[CUDA] Checking CUDA availability..."); if (auto& probe = cuda_availability_probe()) { return probe(); } LibraryHandle handle = open_cuda_runtime(); if (!handle) { log_core(spdlog::level::warn, "[CUDA] Failed to load CUDA runtime library."); return false; } cudaGetDeviceCount_t cudaGetDeviceCount = nullptr; cudaSetDevice_t cudaSetDevice = nullptr; cudaMemGetInfo_t cudaMemGetInfo = nullptr; if (!resolve_cuda_symbols(handle, cudaGetDeviceCount, cudaSetDevice, cudaMemGetInfo)) { closeLibrary(handle); return false; } int count = 0; int status = cudaGetDeviceCount(&count); log_core(spdlog::level::info, "[CUDA] cudaGetDeviceCount returned status: {}, device count: {}", status, count); if (status != 0 || count == 0) { log_core(spdlog::level::warn, status != 0 ? "[CUDA] CUDA error: {} from cudaGetDeviceCount" : "[CUDA] No CUDA devices found", status); closeLibrary(handle); return false; } if (int set_status = cudaSetDevice(0); set_status != 0) { log_core(spdlog::level::warn, "[CUDA] Failed to set CUDA device 0 (error {})", set_status); closeLibrary(handle); return false; } size_t free_bytes = 0; size_t total_bytes = 0; if (int mem_status = cudaMemGetInfo(&free_bytes, &total_bytes); mem_status != 0) { log_core(spdlog::level::warn, "[CUDA] cudaMemGetInfo failed (error {})", mem_status); closeLibrary(handle); return false; } log_core(spdlog::level::info, "[CUDA] CUDA is available and {} device(s) found.", count); closeLibrary(handle); return true; } namespace TestHooks { void set_cuda_availability_probe(CudaAvailabilityProbe probe) { cuda_availability_probe() = std::move(probe); } void reset_cuda_availability_probe() { cuda_availability_probe() = CudaAvailabilityProbe{}; } void set_cuda_memory_probe(CudaMemoryProbe probe) { cuda_memory_probe() = std::move(probe); } void reset_cuda_memory_probe() { cuda_memory_probe() = CudaMemoryProbe{}; } } // namespace TestHooks #ifdef _WIN32 int Utils::get_installed_cuda_runtime_version() { HMODULE hCuda = LoadLibraryA("nvcuda.dll"); if (!hCuda) { log_core(spdlog::level::warn, "Failed to load nvcuda.dll"); return 0; } using cudaDriverGetVersion_t = int(__cdecl *)(int*); auto cudaDriverGetVersion = reinterpret_cast( GetProcAddress(hCuda, "cuDriverGetVersion") ); if (!cudaDriverGetVersion) { log_core(spdlog::level::warn, "Failed to get cuDriverGetVersion symbol"); FreeLibrary(hCuda); return 0; } int version = 0; if (cudaDriverGetVersion(&version) != 0) { log_core(spdlog::level::warn, "cuDriverGetVersion call failed"); FreeLibrary(hCuda); return 0; } log_core(spdlog::level::info, "[CUDA] Detected CUDA driver version: {}", version); FreeLibrary(hCuda); return version; } #endif #ifdef _WIN32 std::string Utils::get_cudart_dll_name() { int version = get_installed_cuda_runtime_version(); std::vector candidates; if (version > 0) { int suggested = version / 1000; if (suggested > 0) { candidates.push_back(suggested); } } // probe the most common recent runtimes (highest first) for (int v = 15; v >= 10; --v) { if (std::find(candidates.begin(), candidates.end(), v) == candidates.end()) { candidates.push_back(v); } } for (int major : candidates) { char buffer[32]; std::snprintf(buffer, sizeof(buffer), "cudart64_%d.dll", major); HMODULE h = LoadLibraryA(buffer); if (h) { FreeLibrary(h); log_core(spdlog::level::info, "[CUDA] Selected runtime DLL: {}", buffer); return buffer; } } log_core(spdlog::level::warn, "[CUDA] Unable to locate a compatible cudart64_XX.dll"); return ""; } #endif std::string Utils::abbreviate_user_path(const std::string& path) { if (path.empty()) { return ""; } const auto fs_path = try_utf8_to_path(path); if (!fs_path) { return trim_leading_separators(to_forward_slashes(path)); } const std::filesystem::path normalized = fs_path->lexically_normal(); const std::string generic_path = to_forward_slashes(Utils::path_to_utf8(normalized)); const std::vector prefixes = collect_user_prefixes(); if (auto trimmed = strip_prefix(generic_path, prefixes)) { return *trimmed; } const std::string sanitized = trim_leading_separators(generic_path); if (!sanitized.empty()) { return sanitized; } return to_forward_slashes(Utils::path_to_utf8(normalized.filename())); } namespace { std::string trim_ws(const std::string& value) { const char* whitespace = " \t\n\r\f\v"; const auto start = value.find_first_not_of(whitespace); const auto end = value.find_last_not_of(whitespace); if (start == std::string::npos || end == std::string::npos) { return std::string(); } return value.substr(start, end - start + 1); } } std::string Utils::sanitize_path_label(const std::string& value) { const std::string invalid = R"(<>:"/\|?*)"; QString normalized = QString::fromUtf8(value.c_str()); normalized.remove(QChar::ReplacementCharacter); const QByteArray normalized_utf8 = normalized.normalized(QString::NormalizationForm_C).toUtf8(); const std::string utf8_value(normalized_utf8.constData(), static_cast(normalized_utf8.size())); std::string cleaned; cleaned.reserve(utf8_value.size()); // Replace invalid path characters and control chars with spaces. for (unsigned char ch : utf8_value) { if (std::iscntrl(ch)) { continue; } if (invalid.find(static_cast(ch)) != std::string::npos) { cleaned.push_back(' '); } else { cleaned.push_back(static_cast(ch)); } } // Collapse multiple spaces. std::string collapsed; collapsed.reserve(cleaned.size()); bool prev_space = false; for (char ch : cleaned) { const bool is_space = std::isspace(static_cast(ch)); if (is_space) { if (!prev_space) { collapsed.push_back(' '); } } else { collapsed.push_back(ch); } prev_space = is_space; } // Trim and drop trailing dots/spaces (Windows safety). std::string trimmed = trim_ws(collapsed); while (!trimmed.empty() && (trimmed.back() == '.' || std::isspace(static_cast(trimmed.back())))) { trimmed.pop_back(); } return trim_ws(trimmed); } ================================================ FILE: app/lib/Version.cpp ================================================ #include "Version.hpp" #include #include #include Version::Version(std::initializer_list version_digits) : digits(version_digits) {} Version::Version(const std::vector& version_digits) : digits(version_digits) {} bool Version::operator>=(const Version& other) const { for (size_t i = 0; i < std::max(digits.size(), other.digits.size()); ++i) { int lhs = (i < digits.size()) ? digits[i] : 0; int rhs = (i < other.digits.size()) ? other.digits[i] : 0; if (lhs > rhs) return true; if (lhs < rhs) return false; } return true; } bool Version::operator>(const Version& other) const { for (size_t i = 0; i < std::max(digits.size(), other.digits.size()); ++i) { int lhs = (i < digits.size()) ? digits[i] : 0; int rhs = (i < other.digits.size()) ? other.digits[i] : 0; if (lhs > rhs) return true; if (lhs < rhs) return false; } return false; } bool Version::operator<=(const Version& other) const { for (size_t i = 0; i < std::max(digits.size(), other.digits.size()); ++i) { int lhs = (i < digits.size()) ? digits[i] : 0; int rhs = (i < other.digits.size()) ? other.digits[i] : 0; if (lhs > rhs) return false; if (lhs < rhs) return true; } return true; } std::string Version::to_string() const { if (digits.empty()) return "0"; std::ostringstream oss; for (size_t i = 0; i < digits.size(); ++i) { if (i > 0) oss << '.'; oss << digits[i]; } return oss.str(); } ================================================ FILE: app/lib/WhitelistManagerDialog.cpp ================================================ #include "WhitelistManagerDialog.hpp" #include #include #include #include #include #include #include #include #include #include #include namespace { QString join_lines(const std::vector& items) { QStringList list; for (const auto& i : items) { list << QString::fromStdString(i); } return list.join(", "); } std::vector split_lines(const QString& text) { std::vector items; for (const auto& part : text.split(",")) { const QString trimmed = part.trimmed(); if (!trimmed.isEmpty()) { items.emplace_back(trimmed.toStdString()); } } return items; } struct EditDialogResult { QString name; std::vector categories; std::vector subcategories; }; std::optional show_edit_dialog(QWidget* parent, const QString& initial_name, const WhitelistEntry& entry) { QDialog dialog(parent); dialog.setWindowTitle(QObject::tr("Edit whitelist")); auto* layout = new QVBoxLayout(&dialog); auto* name_edit = new QLineEdit(&dialog); name_edit->setText(initial_name); layout->addWidget(new QLabel(QObject::tr("Name:"), &dialog)); layout->addWidget(name_edit); auto* cats_edit = new QTextEdit(&dialog); cats_edit->setPlainText(join_lines(entry.categories)); layout->addWidget(new QLabel(QObject::tr("Categories (comma separated):"), &dialog)); layout->addWidget(cats_edit); auto* subs_edit = new QTextEdit(&dialog); subs_edit->setPlainText(join_lines(entry.subcategories)); layout->addWidget(new QLabel(QObject::tr("Subcategories (comma separated):"), &dialog)); layout->addWidget(subs_edit); auto* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, &dialog); layout->addWidget(buttons); QObject::connect(buttons, &QDialogButtonBox::accepted, &dialog, &QDialog::accept); QObject::connect(buttons, &QDialogButtonBox::rejected, &dialog, &QDialog::reject); if (dialog.exec() != QDialog::Accepted) { return std::nullopt; } EditDialogResult result; result.name = name_edit->text().trimmed(); if (result.name.isEmpty()) { return std::nullopt; } result.categories = split_lines(cats_edit->toPlainText()); result.subcategories = split_lines(subs_edit->toPlainText()); return result; } } WhitelistManagerDialog::WhitelistManagerDialog(WhitelistStore& store, QWidget* parent) : QDialog(parent), store_(store) { setWindowTitle(tr("Category whitelists")); auto* layout = new QVBoxLayout(this); list_widget_ = new QListWidget(this); layout->addWidget(list_widget_); auto* button_row = new QHBoxLayout(); add_button_ = new QPushButton(tr("Add"), this); edit_button_ = new QPushButton(tr("Edit"), this); remove_button_ = new QPushButton(tr("Remove"), this); button_row->addWidget(add_button_); button_row->addWidget(edit_button_); button_row->addWidget(remove_button_); button_row->addStretch(); layout->addLayout(button_row); auto* close_box = new QDialogButtonBox(QDialogButtonBox::Close, this); layout->addWidget(close_box); connect(add_button_, &QPushButton::clicked, this, [this]() { on_add_clicked(); }); connect(edit_button_, &QPushButton::clicked, this, [this]() { on_edit_clicked(); }); connect(remove_button_, &QPushButton::clicked, this, [this]() { on_remove_clicked(); }); connect(list_widget_, &QListWidget::currentRowChanged, this, [this](int row) { on_selection_changed(row); }); connect(close_box, &QDialogButtonBox::rejected, this, &QDialog::reject); refresh_list(); } void WhitelistManagerDialog::refresh_list() { if (!list_widget_) return; if (store_.empty()) { store_.ensure_default_from_legacy({}, {}); store_.save(); } list_widget_->clear(); for (const auto& name : store_.list_names()) { auto* item = new QListWidgetItem(QString::fromStdString(name)); item->setData(Qt::UserRole, QString::fromStdString(name)); list_widget_->addItem(item); } on_selection_changed(list_widget_->currentRow()); } bool WhitelistManagerDialog::edit_entry(const QString& name, WhitelistEntry& entry) { auto result = show_edit_dialog(this, name, entry); if (!result.has_value()) { return false; } store_.remove(name.toStdString()); store_.set(result->name.toStdString(), WhitelistEntry{result->categories, result->subcategories}); store_.save(); refresh_list(); notify_changed(); return true; } void WhitelistManagerDialog::on_add_clicked() { WhitelistEntry entry; edit_entry(QString(), entry); } void WhitelistManagerDialog::on_edit_clicked() { if (!list_widget_) return; auto* item = list_widget_->currentItem(); if (!item) return; const QString name = item->text(); if (auto existing = store_.get(name.toStdString())) { edit_entry(name, *existing); } } void WhitelistManagerDialog::on_remove_clicked() { if (!list_widget_) return; auto* item = list_widget_->currentItem(); if (!item) return; const QString name = item->text(); if (name == QString::fromStdString(store_.default_name())) { QMessageBox::warning(this, tr("Cannot remove"), tr("The default list cannot be removed.")); return; } store_.remove(name.toStdString()); store_.save(); refresh_list(); notify_changed(); } void WhitelistManagerDialog::on_selection_changed(int row) { const bool has_selection = row >= 0; edit_button_->setEnabled(has_selection); remove_button_->setEnabled(has_selection); } void WhitelistManagerDialog::notify_changed() { if (on_lists_changed_) { on_lists_changed_(); } } ================================================ FILE: app/lib/WhitelistStore.cpp ================================================ #include "WhitelistStore.hpp" #include "Logger.hpp" #include "Settings.hpp" #include #include namespace { std::vector split_csv(const QString& value) { std::vector out; const auto parts = value.split(","); for (const auto& part : parts) { QString trimmed = part.trimmed(); if (!trimmed.isEmpty()) { out.emplace_back(trimmed.toStdString()); } } return out; } QString join_csv(const std::vector& values) { QStringList list; for (const auto& v : values) { list << QString::fromStdString(v); } return list.join(", "); } } WhitelistStore::WhitelistStore(std::string config_dir) : file_path_(std::move(config_dir) + "/whitelists.ini") {} bool WhitelistStore::load() { entries_.clear(); QSettings settings(QString::fromStdString(file_path_), QSettings::IniFormat); const QStringList groups = settings.childGroups(); for (const auto& group : groups) { settings.beginGroup(group); const auto cats = split_csv(settings.value("Categories").toString()); const auto subs = split_csv(settings.value("Subcategories").toString()); settings.endGroup(); if (!cats.empty() || !subs.empty()) { entries_[group.toStdString()] = WhitelistEntry{cats, subs}; } } if (entries_.empty()) { ensure_default_from_legacy({}, {}); save(); } return true; } bool WhitelistStore::save() const { QSettings settings(QString::fromStdString(file_path_), QSettings::IniFormat); settings.clear(); for (const auto& pair : entries_) { settings.beginGroup(QString::fromStdString(pair.first)); settings.setValue("Categories", join_csv(pair.second.categories)); settings.setValue("Subcategories", join_csv(pair.second.subcategories)); settings.endGroup(); } settings.sync(); return settings.status() == QSettings::NoError; } std::vector WhitelistStore::list_names() const { std::vector names; names.reserve(entries_.size()); for (const auto& entry : entries_) { names.push_back(entry.first); } std::sort(names.begin(), names.end()); return names; } std::optional WhitelistStore::get(const std::string& name) const { if (auto it = entries_.find(name); it != entries_.end()) { return it->second; } return std::nullopt; } void WhitelistStore::set(const std::string& name, WhitelistEntry entry) { entries_[name] = std::move(entry); } void WhitelistStore::remove(const std::string& name) { entries_.erase(name); } void WhitelistStore::ensure_default_from_legacy(const std::vector& cats, const std::vector& subs) { if (!entries_.empty()) { return; } std::vector use_cats = cats; std::vector use_subs = subs; if (use_cats.empty()) { use_cats = { "Archives", "Backups", "Books", "Configs", "Data Exports", "Development", "Documents", "Drivers", "Ebooks", "Firmware", "Guides", "Images", "Installers", "Licenses", "Manuals", "Music", "Operating Systems", "Presentations", "Software", "Spreadsheets", "System", "Temporary", "Videos" }; } if (use_subs.empty()) { use_subs = {}; } entries_[default_name_] = WhitelistEntry{use_cats, use_subs}; } void WhitelistStore::initialize_from_settings(Settings& settings) { load(); ensure_default_from_legacy(settings.get_allowed_categories(), settings.get_allowed_subcategories()); save(); if (settings.get_active_whitelist().empty()) { settings.set_active_whitelist(default_name_); } auto active = settings.get_active_whitelist(); if (auto entry = get(active)) { settings.set_allowed_categories(entry->categories); settings.set_allowed_subcategories(entry->subcategories); } } ================================================ FILE: app/main.cpp ================================================ #include "AppInfo.hpp" #include "EmbeddedEnv.hpp" #include "GgmlRuntimePaths.hpp" #include "Logger.hpp" #include "MainApp.hpp" #include "UpdaterBuildConfig.hpp" #include "UpdaterLaunchOptions.hpp" #include "UpdaterLiveTestConfig.hpp" #include "Utils.hpp" #include "LLMSelectionDialog.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef _WIN32 #include #ifndef DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 #define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 ((HANDLE)-4) #endif using SetProcessDpiAwarenessContextFn = BOOL (WINAPI *)(HANDLE); using SetProcessDpiAwarenessFn = HRESULT (WINAPI *)(int); // 2 = PROCESS_PER_MONITOR_DPI_AWARE #endif bool initialize_loggers() { try { Logger::setup_loggers(); return true; } catch (const std::exception &e) { if (auto logger = Logger::get_logger("core_logger")) { logger->critical("Failed to initialize loggers: {}", e.what()); } else { std::fprintf(stderr, "Failed to initialize loggers: %s\n", e.what()); } return false; } } namespace { struct ParsedArguments { bool development_mode{false}; bool console_log{false}; bool force_direct_run{false}; UpdaterLiveTestConfig updater_live_test; std::vector qt_args; }; bool consume_prefixed_value(const char* argument, const char* prefix, std::optional& target) { const std::size_t prefix_length = std::strlen(prefix); if (std::strncmp(argument, prefix, prefix_length) != 0) { return false; } target = std::string(argument + prefix_length); return true; } bool env_has_value(const char* key) { const char* value = std::getenv(key); return value && value[0] != '\0'; } void set_process_env(const char* key, const std::string& value) { #ifdef _WIN32 _putenv_s(key, value.c_str()); #else setenv(key, value.c_str(), 1); #endif } void apply_updater_live_test_environment(const UpdaterLiveTestConfig& args) { if (!args.enabled) { return; } set_process_env(UpdaterLaunchOptions::kLiveTestModeEnv, "1"); if (args.installer_url) { set_process_env(UpdaterLaunchOptions::kLiveTestUrlEnv, *args.installer_url); } if (args.installer_sha256) { set_process_env(UpdaterLaunchOptions::kLiveTestSha256Env, *args.installer_sha256); } if (args.current_version) { set_process_env(UpdaterLaunchOptions::kLiveTestVersionEnv, *args.current_version); } else if (!env_has_value(UpdaterLaunchOptions::kLiveTestVersionEnv)) { set_process_env(UpdaterLaunchOptions::kLiveTestVersionEnv, APP_VERSION.to_string() + ".1"); } if (args.min_version) { set_process_env(UpdaterLaunchOptions::kLiveTestMinVersionEnv, *args.min_version); } if (!env_has_value(UpdaterLaunchOptions::kLiveTestUrlEnv)) { throw std::runtime_error( "--updater-live-test requires --updater-live-test-url or AI_FILE_SORTER_UPDATER_TEST_URL."); } if (!env_has_value(UpdaterLaunchOptions::kLiveTestSha256Env)) { throw std::runtime_error( "--updater-live-test requires --updater-live-test-sha256 or AI_FILE_SORTER_UPDATER_TEST_SHA256."); } } ParsedArguments parse_command_line(int argc, char** argv) { ParsedArguments parsed; parsed.qt_args.reserve(static_cast(argc) + 1); for (int i = 0; i < argc; ++i) { const bool is_flag = (i > 0); if (is_flag && std::strcmp(argv[i], "--development") == 0) { parsed.development_mode = true; continue; } if (is_flag && std::strcmp(argv[i], "--allow-direct-launch") == 0) { continue; } if (is_flag && std::strcmp(argv[i], "--console-log") == 0) { parsed.console_log = true; continue; } if (is_flag && std::strcmp(argv[i], "--force-direct-run") == 0) { parsed.force_direct_run = true; continue; } if (is_flag && std::strcmp(argv[i], UpdaterLaunchOptions::kLiveTestFlag) == 0) { parsed.updater_live_test.enabled = true; continue; } if (is_flag && consume_prefixed_value(argv[i], UpdaterLaunchOptions::kLiveTestUrlFlag, parsed.updater_live_test.installer_url)) { continue; } if (is_flag && consume_prefixed_value(argv[i], UpdaterLaunchOptions::kLiveTestSha256Flag, parsed.updater_live_test.installer_sha256)) { continue; } if (is_flag && consume_prefixed_value(argv[i], UpdaterLaunchOptions::kLiveTestVersionFlag, parsed.updater_live_test.current_version)) { continue; } if (is_flag && consume_prefixed_value(argv[i], UpdaterLaunchOptions::kLiveTestMinVersionFlag, parsed.updater_live_test.min_version)) { continue; } parsed.qt_args.push_back(argv[i]); } parsed.qt_args.push_back(nullptr); return parsed; } #if defined(__APPLE__) #ifndef AI_FILE_SORTER_GGML_SUBDIR #define AI_FILE_SORTER_GGML_SUBDIR "precompiled" #endif void ensure_ggml_backend_dir() { std::optional current_dir; const char* current = std::getenv("AI_FILE_SORTER_GGML_DIR"); if (current && current[0] != '\0') { current_dir = std::filesystem::path(current); } std::filesystem::path exe_path; try { exe_path = Utils::get_executable_path(); } catch (const std::exception&) { return; } if (exe_path.empty()) { return; } const auto resolved = GgmlRuntimePaths::resolve_macos_backend_dir( current_dir, exe_path, AI_FILE_SORTER_GGML_SUBDIR); if (!resolved) { return; } setenv("AI_FILE_SORTER_GGML_DIR", resolved->string().c_str(), 1); } #endif #ifdef _WIN32 bool allow_direct_launch(int argc, char** argv) { for (int i = 1; i < argc; ++i) { if (std::strcmp(argv[i], "--force-direct-run") == 0) { return true; } } for (int i = 1; i < argc; ++i) { if (std::strcmp(argv[i], "--allow-direct-launch") == 0) { return true; } } return false; } void enable_per_monitor_dpi_awareness() { HMODULE user32 = GetModuleHandleW(L"user32.dll"); if (user32) { const auto set_ctx = reinterpret_cast( GetProcAddress(user32, "SetProcessDpiAwarenessContext")); if (set_ctx && set_ctx(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2)) { return; } } HMODULE shcore = LoadLibraryW(L"Shcore.dll"); if (shcore) { const auto set_awareness = reinterpret_cast( GetProcAddress(shcore, "SetProcessDpiAwareness")); if (set_awareness) { // 2 == PROCESS_PER_MONITOR_DPI_AWARE set_awareness(2); } FreeLibrary(shcore); } } void attach_console_if_requested(bool enable) { if (!enable) { return; } if (AttachConsole(ATTACH_PARENT_PROCESS)) { FILE* f = nullptr; freopen_s(&f, "CONOUT$", "w", stdout); freopen_s(&f, "CONOUT$", "w", stderr); freopen_s(&f, "CONIN$", "r", stdin); } } #endif [[maybe_unused]] QPixmap build_splash_pixmap() { QPixmap splash_pix(QStringLiteral(":/net/quicknode/AIFileSorter/images/icon_512x512.png")); if (splash_pix.isNull()) { splash_pix = QPixmap(256, 256); splash_pix.fill(Qt::black); } const QSize base_size(320, 320); const QSize padded_size(static_cast(base_size.width() * 1.2), static_cast(base_size.height() * 1.1)); QPixmap scaled_splash = splash_pix.scaled(base_size, Qt::KeepAspectRatio, Qt::SmoothTransformation); QPixmap splash_canvas(padded_size); splash_canvas.fill(QColor(QStringLiteral("#f5e6d3"))); QPainter painter(&splash_canvas); painter.setRenderHint(QPainter::SmoothPixmapTransform, true); const QPoint centered_icon((padded_size.width() - scaled_splash.width()) / 2, (padded_size.height() - scaled_splash.height()) / 2 - 10); painter.drawPixmap(centered_icon, scaled_splash); painter.end(); return splash_canvas; } class SplashController { public: explicit SplashController(QApplication& app) : app_(app) { Q_UNUSED(app_); } void set_target(QWidget* target) { target_ = target; } void keep_visible_for(int minimum_duration_ms) { Q_UNUSED(minimum_duration_ms); } void finish() { finished_ = true; } private: QApplication& app_; bool finished_{false}; QWidget* target_{nullptr}; }; bool file_exists(const std::string& path) { if (path.empty()) { return false; } std::error_code ec; return std::filesystem::exists(std::filesystem::path(path), ec); } bool has_local_model_for_env(const char* env_key) { if (!env_key) { return false; } const char* url = std::getenv(env_key); if (!url || *url == '\0') { return false; } try { const std::string path = Utils::make_default_path_to_file_from_download_url(url); return file_exists(path); } catch (...) { return false; } } bool llm_choice_is_ready(const Settings& settings) { const LLMChoice choice = settings.get_llm_choice(); if (choice == LLMChoice::Unset) { return false; } if (choice == LLMChoice::Remote_OpenAI) { return !settings.get_openai_api_key().empty() && !settings.get_openai_model().empty(); } if (choice == LLMChoice::Remote_Gemini) { return !settings.get_gemini_api_key().empty() && !settings.get_gemini_model().empty(); } if (choice == LLMChoice::Remote_Custom) { const auto id = settings.get_active_custom_api_id(); if (id.empty()) { return false; } const CustomApiEndpoint endpoint = settings.find_custom_api_endpoint(id); return !endpoint.id.empty() && !endpoint.base_url.empty() && !endpoint.model.empty(); } if (choice == LLMChoice::Custom) { const auto id = settings.get_active_custom_llm_id(); if (id.empty()) { return false; } const CustomLLM custom = settings.find_custom_llm(id); return !custom.id.empty() && !custom.path.empty() && file_exists(custom.path); } const char* env_var = nullptr; switch (choice) { case LLMChoice::Local_3b: env_var = "LOCAL_LLM_3B_DOWNLOAD_URL"; break; case LLMChoice::Local_3b_legacy: env_var = "LOCAL_LLM_3B_LEGACY_DOWNLOAD_URL"; break; case LLMChoice::Local_7b: env_var = "LOCAL_LLM_7B_DOWNLOAD_URL"; break; default: break; } return has_local_model_for_env(env_var); } bool ensure_llm_choice(Settings& settings, const std::function& finish_splash) { if (llm_choice_is_ready(settings)) { return true; } LLMSelectionDialog llm_dialog(settings); if (llm_dialog.exec() != QDialog::Accepted) { if (finish_splash) { finish_splash(); } return false; } settings.set_openai_api_key(llm_dialog.get_openai_api_key()); settings.set_openai_model(llm_dialog.get_openai_model()); settings.set_gemini_api_key(llm_dialog.get_gemini_api_key()); settings.set_gemini_model(llm_dialog.get_gemini_model()); settings.set_llm_choice(llm_dialog.get_selected_llm_choice()); settings.set_llm_downloads_expanded(llm_dialog.get_llm_downloads_expanded()); if (llm_dialog.get_selected_llm_choice() == LLMChoice::Custom) { settings.set_active_custom_llm_id(llm_dialog.get_selected_custom_llm_id()); } else { settings.set_active_custom_llm_id(""); } if (llm_dialog.get_selected_llm_choice() == LLMChoice::Remote_Custom) { settings.set_active_custom_api_id(llm_dialog.get_selected_custom_api_id()); } else { settings.set_active_custom_api_id(""); } settings.save(); return true; } int run_application(const ParsedArguments& parsed_args) { EmbeddedEnv env_loader(":/net/quicknode/AIFileSorter/.env"); env_loader.load_env(); auto updater_live_test = parsed_args.updater_live_test; if (UpdaterBuildConfig::update_checks_enabled()) { load_missing_values_from_live_test_ini( updater_live_test, Utils::utf8_to_path(Utils::get_executable_path())); apply_updater_live_test_environment(updater_live_test); } #if defined(__APPLE__) ensure_ggml_backend_dir(); #endif setlocale(LC_ALL, ""); const std::string locale_path = Utils::get_executable_path() + "/locale"; bindtextdomain("net.quicknode.AIFileSorter", locale_path.c_str()); const QString display_name = app_display_name(); QCoreApplication::setApplicationName(display_name); QGuiApplication::setApplicationDisplayName(display_name); int qt_argc = static_cast(parsed_args.qt_args.size()) - 1; char** qt_argv = const_cast(parsed_args.qt_args.data()); QApplication app(qt_argc, qt_argv); Settings settings; settings.load(); const auto finish_splash = [&]() {}; if (!ensure_llm_choice(settings, finish_splash)) { return EXIT_SUCCESS; } MainApp main_app(settings, parsed_args.development_mode); main_app.run(); const int result = app.exec(); main_app.shutdown(); return result; } } // namespace int main(int argc, char **argv) { ParsedArguments parsed = parse_command_line(argc, argv); #ifdef _WIN32 enable_per_monitor_dpi_awareness(); attach_console_if_requested(parsed.console_log); #endif if (!initialize_loggers()) { return EXIT_FAILURE; } curl_global_init(CURL_GLOBAL_DEFAULT); struct CurlCleanup { ~CurlCleanup() { curl_global_cleanup(); } } curl_cleanup; #ifdef _WIN32 _putenv("GSETTINGS_SCHEMA_DIR=schemas"); #endif try { return run_application(parsed); } catch (const std::exception& ex) { if (auto logger = Logger::get_logger("core_logger")) { logger->critical("Error: {}", ex.what()); } else { std::fprintf(stderr, "Error: %s\n", ex.what()); } return EXIT_FAILURE; } } ================================================ FILE: app/resources/app.qrc ================================================ images/logo.png images/qn_logo.png images/app_icon_128.png images/icon_512x512.png .env certs/cacert.pem ================================================ FILE: app/resources/certs/cacert.pem ================================================ ## ## Bundle of CA Root Certificates ## ## Certificate data from Mozilla as of: Tue Sep 9 03:12:01 2025 GMT ## ## Find updated versions here: https://curl.se/docs/caextract.html ## ## This is a bundle of X.509 certificates of public Certificate Authorities ## (CA). These were automatically extracted from Mozilla's root certificates ## file (certdata.txt). This file can be found in the mozilla source tree: ## https://raw.githubusercontent.com/mozilla-firefox/firefox/refs/heads/release/security/nss/lib/ckfw/builtins/certdata.txt ## ## It contains the certificates in PEM format and therefore ## can be directly used with curl / libcurl / php_curl, or with ## an Apache+mod_ssl webserver for SSL client authentication. ## Just configure this file as the SSLCACertificateFile. ## ## Conversion done with mk-ca-bundle.pl version 1.29. ## SHA256: 0078e6bdd280fd89e1b883174387aae84b3eae2ee263416a5f8a14ee7f179ae9 ## Entrust Root Certification Authority ==================================== -----BEGIN CERTIFICATE----- MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMCVVMxFjAUBgNV BAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0Lm5ldC9DUFMgaXMgaW5jb3Jw b3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMWKGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsG A1UEAxMkRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0 MloXDTI2MTEyNzIwNTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMu MTkwNwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSByZWZlcmVu Y2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNVBAMTJEVudHJ1c3QgUm9v dCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB ALaVtkNC+sZtKm9I35RMOVcF7sN5EUFoNu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYsz A9u3g3s+IIRe7bJWKKf44LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOww Cj0Yzfv9KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGIrb68 j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi94DkZfs0Nw4pgHBN rziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOBsDCBrTAOBgNVHQ8BAf8EBAMCAQYw DwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAigA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1 MzQyWjAfBgNVHSMEGDAWgBRokORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DH hmak8fdLQ/uEvW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9tO1KzKtvn1ISM Y/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6ZuaAGAT/3B+XxFNSRuzFVJ7yVTa v52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTS W3iDVuycNsMm4hH2Z0kdkquM++v/eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0 tHuu2guQOHXvgR1m0vdXcDazv/wor3ElhVsT/h5/WrQ8 -----END CERTIFICATE----- QuoVadis Root CA 2 ================== -----BEGIN CERTIFICATE----- MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoT EFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMjAeFw0wNjExMjQx ODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM aW1pdGVkMRswGQYDVQQDExJRdW9WYWRpcyBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4IC DwAwggIKAoICAQCaGMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4GtMh6QRr+jhiYaHv5+HBg6 XJxgFyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst/ek+7wrGsxDp3MJGF/hd/aTa/55JWpzmM+Yk lvc/ulsrHHo1wtZn/qtmUIttKGAr79dgw8eTvI02kfN/+NsRE8Scd3bBrrcCaoF6qUWD4gXmuVbB lDePSHFjIuwXZQeVikvfj8ZaCuWw419eaxGrDPmF60Tp+ARz8un+XJiM9XOva7R+zdRcAitMOeGy lZUtQofX1bOQQ7dsE/He3fbE+Ik/0XX1ksOR1YqI0JDs3G3eicJlcZaLDQP9nL9bFqyS2+r+eXyt 66/3FsvbzSUr5R/7mp/iUcw6UwxI5g69ybR2BlLmEROFcmMDBOAENisgGQLodKcftslWZvB1Jdxn wQ5hYIizPtGo/KPaHbDRsSNU30R2be1B2MGyIrZTHN81Hdyhdyox5C315eXbyOD/5YDXC2Og/zOh D7osFRXql7PSorW+8oyWHhqPHWykYTe5hnMz15eWniN9gqRMgeKh0bpnX5UHoycR7hYQe7xFSkyy BNKr79X9DFHOUGoIMfmR2gyPZFwDwzqLID9ujWc9Otb+fVuIyV77zGHcizN300QyNQliBJIWENie J0f7OyHj+OsdWwIDAQABo4GwMIGtMA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1Ud DgQWBBQahGK8SEwzJQTU7tD2A8QZRtGUazBuBgNVHSMEZzBlgBQahGK8SEwzJQTU7tD2A8QZRtGU a6FJpEcwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMT ElF1b1ZhZGlzIFJvb3QgQ0EgMoICBQkwDQYJKoZIhvcNAQEFBQADggIBAD4KFk2fBluornFdLwUv Z+YTRYPENvbzwCYMDbVHZF34tHLJRqUDGCdViXh9duqWNIAXINzng/iN/Ae42l9NLmeyhP3ZRPx3 UIHmfLTJDQtyU/h2BwdBR5YM++CCJpNVjP4iH2BlfF/nJrP3MpCYUNQ3cVX2kiF495V5+vgtJodm VjB3pjd4M1IQWK4/YY7yarHvGH5KWWPKjaJW1acvvFYfzznB4vsKqBUsfU16Y8Zsl0Q80m/DShcK +JDSV6IZUaUtl0HaB0+pUNqQjZRG4T7wlP0QADj1O+hA4bRuVhogzG9Yje0uRY/W6ZM/57Es3zrW IozchLsib9D45MY56QSIPMO661V6bYCZJPVsAfv4l7CUW+v90m/xd2gNNWQjrLhVoQPRTUIZ3Ph1 WVaj+ahJefivDrkRoHy3au000LYmYjgahwz46P0u05B/B5EqHdZ+XIWDmbA4CD/pXvk1B+TJYm5X f6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0ZohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II 4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8 VCLAAVBpQ570su9t+Oza8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u -----END CERTIFICATE----- QuoVadis Root CA 3 ================== -----BEGIN CERTIFICATE----- MIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoT EFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMzAeFw0wNjExMjQx OTExMjNaFw0zMTExMjQxOTA2NDRaMEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM aW1pdGVkMRswGQYDVQQDExJRdW9WYWRpcyBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4IC DwAwggIKAoICAQDMV0IWVJzmmNPTTe7+7cefQzlKZbPoFog02w1ZkXTPkrgEQK0CSzGrvI2RaNgg DhoB4hp7Thdd4oq3P5kazethq8Jlph+3t723j/z9cI8LoGe+AaJZz3HmDyl2/7FWeUUrH556VOij KTVopAFPD6QuN+8bv+OPEKhyq1hX51SGyMnzW9os2l2ObjyjPtr7guXd8lyyBTNvijbO0BNO/79K DDRMpsMhvVAEVeuxu537RR5kFd5VAYwCdrXLoT9CabwvvWhDFlaJKjdhkf2mrk7AyxRllDdLkgbv BNDInIjbC3uBr7E9KsRlOni27tyAsdLTmZw67mtaa7ONt9XOnMK+pUsvFrGeaDsGb659n/je7Mwp p5ijJUMv7/FfJuGITfhebtfZFG4ZM2mnO4SJk8RTVROhUXhA+LjJou57ulJCg54U7QVSWllWp5f8 nT8KKdjcT5EOE7zelaTfi5m+rJsziO+1ga8bxiJTyPbH7pcUsMV8eFLI8M5ud2CEpukqdiDtWAEX MJPpGovgc2PZapKUSU60rUqFxKMiMPwJ7Wgic6aIDFUhWMXhOp8q3crhkODZc6tsgLjoC2SToJyM Gf+z0gzskSaHirOi4XCPLArlzW1oUevaPwV/izLmE1xr/l9A4iLItLRkT9a6fUg+qGkM17uGcclz uD87nSVL2v9A6wIDAQABo4IBlTCCAZEwDwYDVR0TAQH/BAUwAwEB/zCB4QYDVR0gBIHZMIHWMIHT BgkrBgEEAb5YAAMwgcUwgZMGCCsGAQUFBwICMIGGGoGDQW55IHVzZSBvZiB0aGlzIENlcnRpZmlj YXRlIGNvbnN0aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFF1b1ZhZGlzIFJvb3QgQ0EgMyBDZXJ0 aWZpY2F0ZSBQb2xpY3kgLyBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVudC4wLQYIKwYB BQUHAgEWIWh0dHA6Ly93d3cucXVvdmFkaXNnbG9iYWwuY29tL2NwczALBgNVHQ8EBAMCAQYwHQYD VR0OBBYEFPLAE+CCQz777i9nMpY1XNu4ywLQMG4GA1UdIwRnMGWAFPLAE+CCQz777i9nMpY1XNu4 ywLQoUmkRzBFMQswCQYDVQQGEwJCTTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDEbMBkGA1UE AxMSUXVvVmFkaXMgUm9vdCBDQSAzggIFxjANBgkqhkiG9w0BAQUFAAOCAgEAT62gLEz6wPJv92ZV qyM07ucp2sNbtrCD2dDQ4iH782CnO11gUyeim/YIIirnv6By5ZwkajGxkHon24QRiSemd1o417+s hvzuXYO8BsbRd2sPbSQvS3pspweWyuOEn62Iix2rFo1bZhfZFvSLgNLd+LJ2w/w4E6oM3kJpK27z POuAJ9v1pkQNn1pVWQvVDVJIxa6f8i+AxeoyUDUSly7B4f/xI4hROJ/yZlZ25w9Rl6VSDE1JUZU2 Pb+iSwwQHYaZTKrzchGT5Or2m9qoXadNt54CrnMAyNojA+j56hl0YgCUyyIgvpSnWbWCar6ZeXqp 8kokUvd0/bpO5qgdAm6xDYBEwa7TIzdfu4V8K5Iu6H6li92Z4b8nby1dqnuH/grdS/yO9SbkbnBC bjPsMZ57k8HkyWkaPcBrTiJt7qtYTcbQQcEr6k8Sh17rRdhs9ZgC06DYVYoGmRmioHfRMJ6szHXu g/WwYjnPbFfiTNKRCw51KBuav/0aQ/HKd/s7j2G4aSgWQgRecCocIdiP4b0jWy10QJLZYxkNc91p vGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeTmJlglFwjz1onl14LBQaTNx47aTbr qZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK4SVhM7JZG+Ju1zdXtg2pEto= -----END CERTIFICATE----- DigiCert Assured ID Root CA =========================== -----BEGIN CERTIFICATE----- MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQG EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQw IgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzEx MTEwMDAwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQL ExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0Ew ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7cJpSIqvTO 9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYPmDI2dsze3Tyoou9q+yHy UmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW /lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpy oeb6pNnVFzF1roV9Iq4/AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whf GHdPAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRF 66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYunpyGd823IDzANBgkq hkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRCdWKuh+vy1dneVrOfzM4UKLkNl2Bc EkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTffwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38Fn SbNd67IJKusm7Xi+fT8r87cmNW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i 8b5QZ7dsvfPxH2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe +o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g== -----END CERTIFICATE----- DigiCert Global Root CA ======================= -----BEGIN CERTIFICATE----- MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBhMQswCQYDVQQG EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAw HgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBDQTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAw MDAwMDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3 dy5kaWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkq hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsBCSDMAZOn TjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97nh6Vfe63SKMI2tavegw5 BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt43C/dxC//AH2hdmoRBBYMql1GNXRor5H 4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7PT19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y 7vrTC0LUq7dBMtoM1O/4gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQAB o2MwYTAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbRTLtm 8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDQYJKoZIhvcNAQEF BQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/EsrhMAtudXH/vTBH1jLuG2cenTnmCmr EbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIt tep3Sp+dWOIrWcBAI+0tKIJFPnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886 UAb3LujEV0lsYSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= -----END CERTIFICATE----- DigiCert High Assurance EV Root CA ================================== -----BEGIN CERTIFICATE----- MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBsMQswCQYDVQQG EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSsw KQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5jZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAw MFoXDTMxMTExMDAwMDAwMFowbDELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZ MBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFu Y2UgRVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm+9S75S0t Mqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTWPNt0OKRKzE0lgvdKpVMS OO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEMxChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3 MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFBIk5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQ NAQTXKFx01p8VdteZOE3hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUe h10aUAsgEsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMB Af8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaAFLE+w2kD+L9HAdSY JhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3NecnzyIZgYIVyHbIUf4KmeqvxgydkAQ V8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6zeM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFp myPInngiK3BD41VHMWEZ71jFhS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkK mNEVX58Svnw2Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep+OkuE6N36B9K -----END CERTIFICATE----- SwissSign Gold CA - G2 ====================== -----BEGIN CERTIFICATE----- MIIFujCCA6KgAwIBAgIJALtAHEP1Xk+wMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkNIMRUw EwYDVQQKEwxTd2lzc1NpZ24gQUcxHzAdBgNVBAMTFlN3aXNzU2lnbiBHb2xkIENBIC0gRzIwHhcN MDYxMDI1MDgzMDM1WhcNMzYxMDI1MDgzMDM1WjBFMQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dp c3NTaWduIEFHMR8wHQYDVQQDExZTd2lzc1NpZ24gR29sZCBDQSAtIEcyMIICIjANBgkqhkiG9w0B AQEFAAOCAg8AMIICCgKCAgEAr+TufoskDhJuqVAtFkQ7kpJcyrhdhJJCEyq8ZVeCQD5XJM1QiyUq t2/876LQwB8CJEoTlo8jE+YoWACjR8cGp4QjK7u9lit/VcyLwVcfDmJlD909Vopz2q5+bbqBHH5C jCA12UNNhPqE21Is8w4ndwtrvxEvcnifLtg+5hg3Wipy+dpikJKVyh+c6bM8K8vzARO/Ws/BtQpg vd21mWRTuKCWs2/iJneRjOBiEAKfNA+k1ZIzUd6+jbqEemA8atufK+ze3gE/bk3lUIbLtK/tREDF ylqM2tIrfKjuvqblCqoOpd8FUrdVxyJdMmqXl2MT28nbeTZ7hTpKxVKJ+STnnXepgv9VHKVxaSvR AiTysybUa9oEVeXBCsdtMDeQKuSeFDNeFhdVxVu1yzSJkvGdJo+hB9TGsnhQ2wwMC3wLjEHXuend jIj3o02yMszYF9rNt85mndT9Xv+9lz4pded+p2JYryU0pUHHPbwNUMoDAw8IWh+Vc3hiv69yFGkO peUDDniOJihC8AcLYiAQZzlG+qkDzAQ4embvIIO1jEpWjpEA/I5cgt6IoMPiaG59je883WX0XaxR 7ySArqpWl2/5rX3aYT+YdzylkbYcjCbaZaIJbcHiVOO5ykxMgI93e2CaHt+28kgeDrpOVG2Y4OGi GqJ3UM/EY5LsRxmd6+ZrzsECAwEAAaOBrDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUw AwEB/zAdBgNVHQ4EFgQUWyV7lqRlUX64OfPAeGZe6Drn8O4wHwYDVR0jBBgwFoAUWyV7lqRlUX64 OfPAeGZe6Drn8O4wRgYDVR0gBD8wPTA7BglghXQBWQECAQEwLjAsBggrBgEFBQcCARYgaHR0cDov L3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBACe645R88a7A3hfm 5djV9VSwg/S7zV4Fe0+fdWavPOhWfvxyeDgD2StiGwC5+OlgzczOUYrHUDFu4Up+GC9pWbY9ZIEr 44OE5iKHjn3g7gKZYbge9LgriBIWhMIxkziWMaa5O1M/wySTVltpkuzFwbs4AOPsF6m43Md8AYOf Mke6UiI0HTJ6CVanfCU2qT1L2sCCbwq7EsiHSycR+R4tx5M/nttfJmtS2S6K8RTGRI0Vqbe/vd6m Gu6uLftIdxf+u+yvGPUqUfA5hJeVbG4bwyvEdGB5JbAKJ9/fXtI5z0V9QkvfsywexcZdylU6oJxp mo/a77KwPJ+HbBIrZXAVUjEaJM9vMSNQH4xPjyPDdEFjHFWoFN0+4FFQz/EbMFYOkrCChdiDyyJk vC24JdVUorgG6q2SpCSgwYa1ShNqR88uC1aVVMvOmttqtKay20EIhid392qgQmwLOM7XdVAyksLf KzAiSNDVQTglXaTpXZ/GlHXQRf0wl0OPkKsKx4ZzYEppLd6leNcG2mqeSz53OiATIgHQv2ieY2Br NU0LbbqhPcCT4H8js1WtciVORvnSFu+wZMEBnunKoGqYDs/YYPIvSbjkQuE4NRb0yG5P94FW6Lqj viOvrv1vA+ACOzB2+httQc8Bsem4yWb02ybzOqR08kkkW8mw0FfB+j564ZfJ -----END CERTIFICATE----- SecureTrust CA ============== -----BEGIN CERTIFICATE----- MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBIMQswCQYDVQQG EwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xFzAVBgNVBAMTDlNlY3VyZVRy dXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIzMTE5NDA1NVowSDELMAkGA1UEBhMCVVMxIDAe BgNVBAoTF1NlY3VyZVRydXN0IENvcnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmVUcnVzdCBDQTCC ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7CT8rU4niVWJxB4Q2ZQCQX OZEzZum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/jep4G6pkjGnx29vo6pQT64lO0pGtSO0gMdA+9t DWccV9cGrcrI9f4Or2YlSASWC12juhbDCE/RRvgUXPLIXgGZbf2IzIaowW8xQmxSPmjL8xk037uH GFaAJsTQ3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj7DaUaHp3pLHnDi+BeuK1cobvomuL8A/b 01k/unK8RCSc43Oz969XL0Imnal0ugBS8kvNU3xHCzaFDmapCJcWNFfBZveA4+1wVMeT4C4oFVmH ursCAwEAAaOBnTCBmjATBgkrBgEEAYI3FAIEBh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/ BAUwAwEB/zAdBgNVHQ4EFgQUQjK2FvoE/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCegJYYj aHR0cDovL2NybC5zZWN1cmV0cnVzdC5jb20vU1RDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQAwDQYJ KoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt36Z3q059c4EVlew3KW+JwULKUBRSu SceNQQcSc5R+DCMh/bwQf2AQWnL1mA6s7Ll/3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHf mbx8IVQr5Fiiu1cprp6poxkmD5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZ nMUFdAvnZyPSCPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR 3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE= -----END CERTIFICATE----- Secure Global CA ================ -----BEGIN CERTIFICATE----- MIIDvDCCAqSgAwIBAgIQB1YipOjUiolN9BPI8PjqpTANBgkqhkiG9w0BAQUFADBKMQswCQYDVQQG EwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBH bG9iYWwgQ0EwHhcNMDYxMTA3MTk0MjI4WhcNMjkxMjMxMTk1MjA2WjBKMQswCQYDVQQGEwJVUzEg MB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwg Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvNS7YrGxVaQZx5RNoJLNP2MwhR/jx YDiJiQPpvepeRlMJ3Fz1Wuj3RSoC6zFh1ykzTM7HfAo3fg+6MpjhHZevj8fcyTiW89sa/FHtaMbQ bqR8JNGuQsiWUGMu4P51/pinX0kuleM5M2SOHqRfkNJnPLLZ/kG5VacJjnIFHovdRIWCQtBJwB1g 8NEXLJXr9qXBkqPFwqcIYA1gBBCWeZ4WNOaptvolRTnIHmX5k/Wq8VLcmZg9pYYaDDUz+kulBAYV HDGA76oYa8J719rO+TMg1fW9ajMtgQT7sFzUnKPiXB3jqUJ1XnvUd+85VLrJChgbEplJL4hL/VBi 0XPnj3pDAgMBAAGjgZ0wgZowEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1Ud EwEB/wQFMAMBAf8wHQYDVR0OBBYEFK9EBMJBfkiD2045AuzshHrmzsmkMDQGA1UdHwQtMCswKaAn oCWGI2h0dHA6Ly9jcmwuc2VjdXJldHJ1c3QuY29tL1NHQ0EuY3JsMBAGCSsGAQQBgjcVAQQDAgEA MA0GCSqGSIb3DQEBBQUAA4IBAQBjGghAfaReUw132HquHw0LURYD7xh8yOOvaliTFGCRsoTciE6+ OYo68+aCiV0BN7OrJKQVDpI1WkpEXk5X+nXOH0jOZvQ8QCaSmGwb7iRGDBezUqXbpZGRzzfTb+cn CDpOGR86p1hcF895P4vkp9MmI50mD1hp/Ed+stCNi5O/KU9DaXR2Z0vPB4zmAve14bRDtUstFJ/5 3CYNv6ZHdAbYiNE6KTCEztI5gGIbqMdXSbxqVVFnFUq+NQfk1XWYN3kwFNspnWzFacxHVaIw98xc f8LDmBxrThaA63p4ZUWiABqvDA1VZDRIuJK58bRQKfJPIx/abKwfROHdI3hRW8cW -----END CERTIFICATE----- COMODO Certification Authority ============================== -----BEGIN CERTIFICATE----- MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCBgTELMAkGA1UE BhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgG A1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNVBAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1 dGhvcml0eTAeFw0wNjEyMDEwMDAwMDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEb MBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFD T01PRE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0aG9yaXR5 MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3UcEbVASY06m/weaKXTuH +7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI2GqGd0S7WWaXUF601CxwRM/aN5VCaTww xHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV 4EajcNxo2f8ESIl33rXp+2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA 1KGzqSX+DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5OnKVI rLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW/zAOBgNVHQ8BAf8E BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6gPKA6hjhodHRwOi8vY3JsLmNvbW9k b2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOC AQEAPpiem/Yb6dc5t3iuHXIYSdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CP OGEIqB6BCsAvIC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/ RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4zJVSk/BwJVmc IGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5ddBA6+C4OmF4O5MBKgxTMVBbkN +8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IBZQ== -----END CERTIFICATE----- COMODO ECC Certification Authority ================================== -----BEGIN CERTIFICATE----- MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTELMAkGA1UEBhMC R0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UE ChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBB dXRob3JpdHkwHhcNMDgwMzA2MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0Ix GzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR Q09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRo b3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSRFtSrYpn1PlILBs5BAH+X 4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0JcfRK9ChQtP6IHG4/bC8vCVlbpVsLM5ni wz2J+Wos77LTBumjQjBAMB0GA1UdDgQWBBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8E BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VG FAkK+qDmfQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdvGDeA U/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY= -----END CERTIFICATE----- Certigna ======== -----BEGIN CERTIFICATE----- MIIDqDCCApCgAwIBAgIJAP7c4wEPyUj/MA0GCSqGSIb3DQEBBQUAMDQxCzAJBgNVBAYTAkZSMRIw EAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hMB4XDTA3MDYyOTE1MTMwNVoXDTI3 MDYyOTE1MTMwNVowNDELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczERMA8GA1UEAwwI Q2VydGlnbmEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDIaPHJ1tazNHUmgh7stL7q XOEm7RFHYeGifBZ4QCHkYJ5ayGPhxLGWkv8YbWkj4Sti993iNi+RB7lIzw7sebYs5zRLcAglozyH GxnygQcPOJAZ0xH+hrTy0V4eHpbNgGzOOzGTtvKg0KmVEn2lmsxryIRWijOp5yIVUxbwzBfsV1/p ogqYCd7jX5xv3EjjhQsVWqa6n6xI4wmy9/Qy3l40vhx4XUJbzg4ij02Q130yGLMLLGq/jj8UEYkg DncUtT2UCIf3JR7VsmAA7G8qKCVuKj4YYxclPz5EIBb2JsglrgVKtOdjLPOMFlN+XPsRGgjBRmKf Irjxwo1p3Po6WAbfAgMBAAGjgbwwgbkwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUGu3+QTmQ tCRZvgHyUtVF9lo53BEwZAYDVR0jBF0wW4AUGu3+QTmQtCRZvgHyUtVF9lo53BGhOKQ2MDQxCzAJ BgNVBAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hggkA/tzjAQ/J SP8wDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzANBgkqhkiG9w0BAQUFAAOCAQEA hQMeknH2Qq/ho2Ge6/PAD/Kl1NqV5ta+aDY9fm4fTIrv0Q8hbV6lUmPOEvjvKtpv6zf+EwLHyzs+ ImvaYS5/1HI93TDhHkxAGYwP15zRgzB7mFncfca5DClMoTOi62c6ZYTTluLtdkVwj7Ur3vkj1klu PBS1xp81HlDQwY9qcEQCYsuuHWhBp6pX6FOqB9IG9tUUBguRA3UsbHK1YZWaDYu5Def131TN3ubY 1gkIl2PlwS6wt0QmwCbAr1UwnjvVNioZBPRcHv/PLLf/0P2HQBHVESO7SMAhqaQoLf0V+LBOK/Qw WyH8EZE0vkHve52Xdf+XlcCWWC/qu0bXu+TZLg== -----END CERTIFICATE----- ePKI Root Certification Authority ================================= -----BEGIN CERTIFICATE----- MIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQG EwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0ZC4xKjAoBgNVBAsMIWVQS0kg Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNDEyMjAwMjMxMjdaFw0zNDEyMjAwMjMx MjdaMF4xCzAJBgNVBAYTAlRXMSMwIQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEq MCgGA1UECwwhZVBLSSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0B AQEFAAOCAg8AMIICCgKCAgEA4SUP7o3biDN1Z82tH306Tm2d0y8U82N0ywEhajfqhFAHSyZbCUNs IZ5qyNUD9WBpj8zwIuQf5/dqIjG3LBXy4P4AakP/h2XGtRrBp0xtInAhijHyl3SJCRImHJ7K2RKi lTza6We/CKBk49ZCt0Xvl/T29de1ShUCWH2YWEtgvM3XDZoTM1PRYfl61dd4s5oz9wCGzh1NlDiv qOx4UXCKXBCDUSH3ET00hl7lSM2XgYI1TBnsZfZrxQWh7kcT1rMhJ5QQCtkkO7q+RBNGMD+XPNjX 12ruOzjjK9SXDrkb5wdJfzcq+Xd4z1TtW0ado4AOkUPB1ltfFLqfpo0kR0BZv3I4sjZsN/+Z0V0O WQqraffAsgRFelQArr5T9rXn4fg8ozHSqf4hUmTFpmfwdQcGlBSBVcYn5AGPF8Fqcde+S/uUWH1+ ETOxQvdibBjWzwloPn9s9h6PYq2lY9sJpx8iQkEeb5mKPtf5P0B6ebClAZLSnT0IFaUQAS2zMnao lQ2zepr7BxB4EW/hj8e6DyUadCrlHJhBmd8hh+iVBmoKs2pHdmX2Os+PYhcZewoozRrSgx4hxyy/ vv9haLdnG7t4TY3OZ+XkwY63I2binZB1NJipNiuKmpS5nezMirH4JYlcWrYvjB9teSSnUmjDhDXi Zo1jDiVN1Rmy5nk3pyKdVDECAwEAAaNqMGgwHQYDVR0OBBYEFB4M97Zn8uGSJglFwFU5Lnc/Qkqi MAwGA1UdEwQFMAMBAf8wOQYEZyoHAAQxMC8wLQIBADAJBgUrDgMCGgUAMAcGBWcqAwAABBRFsMLH ClZ87lt4DJX5GFPBphzYEDANBgkqhkiG9w0BAQUFAAOCAgEACbODU1kBPpVJufGBuvl2ICO1J2B0 1GqZNF5sAFPZn/KmsSQHRGoqxqWOeBLoR9lYGxMqXnmbnwoqZ6YlPwZpVnPDimZI+ymBV3QGypzq KOg4ZyYr8dW1P2WT+DZdjo2NQCCHGervJ8A9tDkPJXtoUHRVnAxZfVo9QZQlUgjgRywVMRnVvwdV xrsStZf0X4OFunHB2WyBEXYKCrC/gpf36j36+uwtqSiUO1bd0lEursC9CBWMd1I0ltabrNMdjmEP NXubrjlpC2JgQCA2j6/7Nu4tCEoduL+bXPjqpRugc6bY+G7gMwRfaKonh+3ZwZCc7b3jajWvY9+r GNm65ulK6lCKD2GTHuItGeIwlDWSXQ62B68ZgI9HkFFLLk3dheLSClIKF5r8GrBQAuUBo2M3IUxE xJtRmREOc5wGj1QupyheRDmHVi03vYVElOEMSyycw5KFNGHLD7ibSkNS/jQ6fbjpKdx2qcgw+BRx gMYeNkh0IkFch4LoGHGLQYlE535YW6i4jRPpp2zDR+2zGp1iro2C6pSe3VkQw63d4k3jMdXH7Ojy sP6SHhYKGvzZ8/gntsm+HbRsZJB/9OTEW9c3rkIO3aQab3yIVMUWbuF6aC74Or8NpDyJO3inTmOD BCEIZ43ygknQW/2xzQ+DhNQ+IIX3Sj0rnP0qCglN6oH4EZw= -----END CERTIFICATE----- certSIGN ROOT CA ================ -----BEGIN CERTIFICATE----- MIIDODCCAiCgAwIBAgIGIAYFFnACMA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNVBAYTAlJPMREwDwYD VQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBDQTAeFw0wNjA3MDQxNzIwMDRa Fw0zMTA3MDQxNzIwMDRaMDsxCzAJBgNVBAYTAlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UE CxMQY2VydFNJR04gUk9PVCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALczuX7I JUqOtdu0KBuqV5Do0SLTZLrTk+jUrIZhQGpgV2hUhE28alQCBf/fm5oqrl0Hj0rDKH/v+yv6efHH rfAQUySQi2bJqIirr1qjAOm+ukbuW3N7LBeCgV5iLKECZbO9xSsAfsT8AzNXDe3i+s5dRdY4zTW2 ssHQnIFKquSyAVwdj1+ZxLGt24gh65AIgoDzMKND5pCCrlUoSe1b16kQOA7+j0xbm0bqQfWwCHTD 0IgztnzXdN/chNFDDnU5oSVAKOp4yw4sLjmdjItuFhwvJoIQ4uNllAoEwF73XVv4EOLQunpL+943 AAAaWyjj0pxzPjKHmKHJUS/X3qwzs08CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B Af8EBAMCAcYwHQYDVR0OBBYEFOCMm9slSbPxfIbWskKHC9BroNnkMA0GCSqGSIb3DQEBBQUAA4IB AQA+0hyJLjX8+HXd5n9liPRyTMks1zJO890ZeUe9jjtbkw9QSSQTaxQGcu8J06Gh40CEyecYMnQ8 SG4Pn0vU9x7Tk4ZkVJdjclDVVc/6IJMCopvDI5NOFlV2oHB5bc0hH88vLbwZ44gx+FkagQnIl6Z0 x2DEW8xXjrJ1/RsCCdtZb3KTafcxQdaIOL+Hsr0Wefmq5L6IJd1hJyMctTEHBDa0GpC9oHRxUIlt vBTjD4au8as+x6AJzKNI0eDbZOeStc+vckNwi/nDhDwTqn6Sm1dTk/pwwpEOMfmbZ13pljheX7Nz TogVZ96edhBiIL5VaZVDADlN9u6wWk5JRFRYX0KD -----END CERTIFICATE----- NetLock Arany (Class Gold) Főtanúsítvány ======================================== -----BEGIN CERTIFICATE----- MIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQGEwJIVTERMA8G A1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3MDUGA1UECwwuVGFuw7pzw610 dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNlcnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBB cmFueSAoQ2xhc3MgR29sZCkgRsWRdGFuw7pzw610dsOhbnkwHhcNMDgxMjExMTUwODIxWhcNMjgx MjA2MTUwODIxWjCBpzELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRUwEwYDVQQKDAxO ZXRMb2NrIEtmdC4xNzA1BgNVBAsMLlRhbsO6c8OtdHbDoW55a2lhZMOzayAoQ2VydGlmaWNhdGlv biBTZXJ2aWNlcykxNTAzBgNVBAMMLE5ldExvY2sgQXJhbnkgKENsYXNzIEdvbGQpIEbFkXRhbsO6 c8OtdHbDoW55MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxCRec75LbRTDofTjl5Bu 0jBFHjzuZ9lk4BqKf8owyoPjIMHj9DrTlF8afFttvzBPhCf2nx9JvMaZCpDyD/V/Q4Q3Y1GLeqVw /HpYzY6b7cNGbIRwXdrzAZAj/E4wqX7hJ2Pn7WQ8oLjJM2P+FpD/sLj916jAwJRDC7bVWaaeVtAk H3B5r9s5VA1lddkVQZQBr17s9o3x/61k/iCa11zr/qYfCGSji3ZVrR47KGAuhyXoqq8fxmRGILdw fzzeSNuWU7c5d+Qa4scWhHaXWy+7GRWF+GmF9ZmnqfI0p6m2pgP8b4Y9VHx2BJtr+UBdADTHLpl1 neWIA6pN+APSQnbAGwIDAKiLo0UwQzASBgNVHRMBAf8ECDAGAQH/AgEEMA4GA1UdDwEB/wQEAwIB BjAdBgNVHQ4EFgQUzPpnk/C2uNClwB7zU/2MU9+D15YwDQYJKoZIhvcNAQELBQADggEBAKt/7hwW qZw8UQCgwBEIBaeZ5m8BiFRhbvG5GK1Krf6BQCOUL/t1fC8oS2IkgYIL9WHxHG64YTjrgfpioTta YtOUZcTh5m2C+C8lcLIhJsFyUR+MLMOEkMNaj7rP9KdlpeuY0fsFskZ1FSNqb4VjMIDw1Z4fKRzC bLBQWV2QWzuoDTDPv31/zvGdg73JRm4gpvlhUbohL3u+pRVjodSVh/GeufOJ8z2FuLjbvrW5Kfna NwUASZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2XjG4Kvte9nHfRCaexOYNkbQu dZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E= -----END CERTIFICATE----- Microsec e-Szigno Root CA 2009 ============================== -----BEGIN CERTIFICATE----- MIIECjCCAvKgAwIBAgIJAMJ+QwRORz8ZMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYDVQQGEwJIVTER MA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jv c2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5o dTAeFw0wOTA2MTYxMTMwMThaFw0yOTEyMzAxMTMwMThaMIGCMQswCQYDVQQGEwJIVTERMA8GA1UE BwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUt U3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5odTCCASIw DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOn4j/NjrdqG2KfgQvvPkd6mJviZpWNwrZuuyjNA fW2WbqEORO7hE52UQlKavXWFdCyoDh2Tthi3jCyoz/tccbna7P7ofo/kLx2yqHWH2Leh5TvPmUpG 0IMZfcChEhyVbUr02MelTTMuhTlAdX4UfIASmFDHQWe4oIBhVKZsTh/gnQ4H6cm6M+f+wFUoLAKA pxn1ntxVUwOXewdI/5n7N4okxFnMUBBjjqqpGrCEGob5X7uxUG6k0QrM1XF+H6cbfPVTbiJfyyvm 1HxdrtbCxkzlBQHZ7Vf8wSN5/PrIJIOV87VqUQHQd9bpEqH5GoP7ghu5sJf0dgYzQ0mg/wu1+rUC AwEAAaOBgDB+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTLD8bf QkPMPcu1SCOhGnqmKrs0aDAfBgNVHSMEGDAWgBTLD8bfQkPMPcu1SCOhGnqmKrs0aDAbBgNVHREE FDASgRBpbmZvQGUtc3ppZ25vLmh1MA0GCSqGSIb3DQEBCwUAA4IBAQDJ0Q5eLtXMs3w+y/w9/w0o lZMEyL/azXm4Q5DwpL7v8u8hmLzU1F0G9u5C7DBsoKqpyvGvivo/C3NqPuouQH4frlRheesuCDfX I/OMn74dseGkddug4lQUsbocKaQY9hK6ohQU4zE1yED/t+AFdlfBHFny+L/k7SViXITwfn4fs775 tyERzAMBVnCnEJIeGzSBHq2cGsMEPO0CYdYeBvNfOofyK/FFh+U9rNHHV4S9a67c2Pm2G2JwCz02 yULyMtd6YebS2z3PyKnJm9zbWETXbzivf3jTo60adbocwTZ8jx5tHMN1Rq41Bab2XD0h7lbwyYIi LXpUq3DDfSJlgnCW -----END CERTIFICATE----- GlobalSign Root CA - R3 ======================= -----BEGIN CERTIFICATE----- MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4GA1UECxMXR2xv YmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2Jh bFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxT aWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2ln bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWt iHL8RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsTgHeMCOFJ 0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmmKPZpO/bLyCiR5Z2KYVc3 rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zdQQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjl OCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZXriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2 xmmFghcCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE FI/wS3+oLkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZURUm7 lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMpjjM5RcOO5LlXbKr8 EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK6fBdRoyV3XpYKBovHd7NADdBj+1E bddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQXmcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18 YIvDQVETI53O9zJrlAGomecsMx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7r kpeDMdmztcpHWD9f -----END CERTIFICATE----- Izenpe.com ========== -----BEGIN CERTIFICATE----- MIIF8TCCA9mgAwIBAgIQALC3WhZIX7/hy/WL1xnmfTANBgkqhkiG9w0BAQsFADA4MQswCQYDVQQG EwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6ZW5wZS5jb20wHhcNMDcxMjEz MTMwODI4WhcNMzcxMjEzMDgyNzI1WjA4MQswCQYDVQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMu QS4xEzARBgNVBAMMCkl6ZW5wZS5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDJ 03rKDx6sp4boFmVqscIbRTJxldn+EFvMr+eleQGPicPK8lVx93e+d5TzcqQsRNiekpsUOqHnJJAK ClaOxdgmlOHZSOEtPtoKct2jmRXagaKH9HtuJneJWK3W6wyyQXpzbm3benhB6QiIEn6HLmYRY2xU +zydcsC8Lv/Ct90NduM61/e0aL6i9eOBbsFGb12N4E3GVFWJGjMxCrFXuaOKmMPsOzTFlUFpfnXC PCDFYbpRR6AgkJOhkEvzTnyFRVSa0QUmQbC1TR0zvsQDyCV8wXDbO/QJLVQnSKwv4cSsPsjLkkxT OTcj7NMB+eAJRE1NZMDhDVqHIrytG6P+JrUV86f8hBnp7KGItERphIPzidF0BqnMC9bC3ieFUCbK F7jJeodWLBoBHmy+E60QrLUk9TiRodZL2vG70t5HtfG8gfZZa88ZU+mNFctKy6lvROUbQc/hhqfK 0GqfvEyNBjNaooXlkDWgYlwWTvDjovoDGrQscbNYLN57C9saD+veIR8GdwYDsMnvmfzAuU8Lhij+ 0rnq49qlw0dpEuDb8PYZi+17cNcC1u2HGCgsBCRMd+RIihrGO5rUD8r6ddIBQFqNeb+Lz0vPqhbB leStTIo+F5HUsWLlguWABKQDfo2/2n+iD5dPDNMN+9fR5XJ+HMh3/1uaD7euBUbl8agW7EekFwID AQABo4H2MIHzMIGwBgNVHREEgagwgaWBD2luZm9AaXplbnBlLmNvbaSBkTCBjjFHMEUGA1UECgw+ SVpFTlBFIFMuQS4gLSBDSUYgQTAxMzM3MjYwLVJNZXJjLlZpdG9yaWEtR2FzdGVpeiBUMTA1NSBG NjIgUzgxQzBBBgNVBAkMOkF2ZGEgZGVsIE1lZGl0ZXJyYW5lbyBFdG9yYmlkZWEgMTQgLSAwMTAx MCBWaXRvcmlhLUdhc3RlaXowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0O BBYEFB0cZQ6o8iV7tJHP5LGx5r1VdGwFMA0GCSqGSIb3DQEBCwUAA4ICAQB4pgwWSp9MiDrAyw6l Fn2fuUhfGI8NYjb2zRlrrKvV9pF9rnHzP7MOeIWblaQnIUdCSnxIOvVFfLMMjlF4rJUT3sb9fbga kEyrkgPH7UIBzg/YsfqikuFgba56awmqxinuaElnMIAkejEWOVt+8Rwu3WwJrfIxwYJOubv5vr8q hT/AQKM6WfxZSzwoJNu0FXWuDYi6LnPAvViH5ULy617uHjAimcs30cQhbIHsvm0m5hzkQiCeR7Cs g1lwLDXWrzY0tM07+DKo7+N4ifuNRSzanLh+QBxh5z6ikixL8s36mLYp//Pye6kfLqCTVyvehQP5 aTfLnnhqBbTFMXiJ7HqnheG5ezzevh55hM6fcA5ZwjUukCox2eRFekGkLhObNA5me0mrZJfQRsN5 nXJQY6aYWwa9SG3YOYNw6DXwBdGqvOPbyALqfP2C2sJbUjWumDqtujWTI6cfSN01RpiyEGjkpTHC ClguGYEQyVB1/OpaFs4R1+7vUIgtYf8/QnMFlEPVjjxOAToZpR9GTnfQXeWBIiGH/pR9hNiTrdZo Q0iy2+tzJOeRf1SktoA+naM8THLCV8Sg1Mw4J87VBp6iSNnpn86CcDaTmjvfliHjWbcM2pE38P1Z WrOZyGlsQyYBNWNgVYkDOnXYukrZVP/u3oDYLdE41V4tC5h9Pmzb/CaIxw== -----END CERTIFICATE----- Go Daddy Root Certificate Authority - G2 ======================================== -----BEGIN CERTIFICATE----- MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoTEUdvRGFkZHkuY29tLCBJbmMu MTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5 MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6 b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8G A1UEAxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI hvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKDE6bFIEMBO4Tx5oVJnyfq 9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD +qK+ihVqf94Lw7YZFAXK6sOoBJQ7RnwyDfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutd fMh8+7ArU6SSYmlRJQVhGkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMl NAJWJwGRtDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEAAaNC MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFDqahQcQZyi27/a9 BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmXWWcDYfF+OwYxdS2hII5PZYe096ac vNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r 5N9ss4UXnT3ZJE95kTXWXwTrgIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYV N8Gb5DKj7Tjo2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI4uJEvlz36hz1 -----END CERTIFICATE----- Starfield Root Certificate Authority - G2 ========================================= -----BEGIN CERTIFICATE----- MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9s b2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVsZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0 eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAw DgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQg VGVjaG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZpY2F0ZSBB dXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL3twQP89o/8ArFv W59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMgnLRJdzIpVv257IzdIvpy3Cdhl+72WoTs bhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNk N3mSwOxGXn/hbVNMYq/NHwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7Nf ZTD4p7dNdloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0HZbU JtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC AQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0GCSqGSIb3DQEBCwUAA4IBAQARWfol TwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjUsHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx 4mcujJUDJi5DnUox9g61DLu34jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUw F5okxBDgBPfg8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1mMpYjn0q7pBZ c2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0 -----END CERTIFICATE----- Starfield Services Root Certificate Authority - G2 ================================================== -----BEGIN CERTIFICATE----- MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMxEDAOBgNVBAgT B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9s b2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVsZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRl IEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNV BAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxT dGFyZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2VydmljZXMg Um9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC AQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20pOsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2 h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm28xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4Pa hHQUw2eeBGg6345AWh1KTs9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLP LJGmpufehRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk6mFB rMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAwDwYDVR0TAQH/BAUw AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+qAdcwKziIorhtSpzyEZGDMA0GCSqG SIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMIbw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPP E95Dz+I0swSdHynVv/heyNXBve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTy xQGjhdByPq1zqwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn0q23KXB56jza YyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCNsSi6 -----END CERTIFICATE----- AffirmTrust Commercial ====================== -----BEGIN CERTIFICATE----- MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UEBhMCVVMxFDAS BgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBDb21tZXJjaWFsMB4XDTEw MDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmly bVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBDb21tZXJjaWFsMIIBIjANBgkqhkiG9w0BAQEF AAOCAQ8AMIIBCgKCAQEA9htPZwcroRX1BiLLHwGy43NFBkRJLLtJJRTWzsO3qyxPxkEylFf6Eqdb DuKPHx6GGaeqtS25Xw2Kwq+FNXkyLbscYjfysVtKPcrNcV/pQr6U6Mje+SJIZMblq8Yrba0F8PrV C8+a5fBQpIs7R6UjW3p6+DM/uO+Zl+MgwdYoic+U+7lF7eNAFxHUdPALMeIrJmqbTFeurCA+ukV6 BfO9m2kVrn1OIGPENXY6BwLJN/3HR+7o8XYdcxXyl6S1yHp52UKqK39c/s4mT6NmgTWvRLpUHhww MmWd5jyTXlBOeuM61G7MGvv50jeuJCqrVwMiKA1JdX+3KNp1v47j3A55MQIDAQABo0IwQDAdBgNV HQ4EFgQUnZPGU4teyq8/nx4P5ZmVvCT2lI8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC AQYwDQYJKoZIhvcNAQELBQADggEBAFis9AQOzcAN/wr91LoWXym9e2iZWEnStB03TX8nfUYGXUPG hi4+c7ImfU+TqbbEKpqrIZcUsd6M06uJFdhrJNTxFq7YpFzUf1GO7RgBsZNjvbz4YYCanrHOQnDi qX0GJX0nof5v7LMeJNrjS1UaADs1tDvZ110w/YETifLCBivtZ8SOyUOyXGsViQK8YvxO8rUzqrJv 0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9gN53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0kh sUlHRUe072o0EclNmsxZt9YCnlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8= -----END CERTIFICATE----- AffirmTrust Networking ====================== -----BEGIN CERTIFICATE----- MIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UEBhMCVVMxFDAS BgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBOZXR3b3JraW5nMB4XDTEw MDEyOTE0MDgyNFoXDTMwMTIzMTE0MDgyNFowRDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmly bVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBOZXR3b3JraW5nMIIBIjANBgkqhkiG9w0BAQEF AAOCAQ8AMIIBCgKCAQEAtITMMxcua5Rsa2FSoOujz3mUTOWUgJnLVWREZY9nZOIG41w3SfYvm4SE Hi3yYJ0wTsyEheIszx6e/jarM3c1RNg1lho9Nuh6DtjVR6FqaYvZ/Ls6rnla1fTWcbuakCNrmreI dIcMHl+5ni36q1Mr3Lt2PpNMCAiMHqIjHNRqrSK6mQEubWXLviRmVSRLQESxG9fhwoXA3hA/Pe24 /PHxI1Pcv2WXb9n5QHGNfb2V1M6+oF4nI979ptAmDgAp6zxG8D1gvz9Q0twmQVGeFDdCBKNwV6gb h+0t+nvujArjqWaJGctB+d1ENmHP4ndGyH329JKBNv3bNPFyfvMMFr20FQIDAQABo0IwQDAdBgNV HQ4EFgQUBx/S55zawm6iQLSwelAQUHTEyL0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC AQYwDQYJKoZIhvcNAQEFBQADggEBAIlXshZ6qML91tmbmzTCnLQyFE2npN/svqe++EPbkTfOtDIu UFUaNU52Q3Eg75N3ThVwLofDwR1t3Mu1J9QsVtFSUzpE0nPIxBsFZVpikpzuQY0x2+c06lkh1QF6 12S4ZDnNye2v7UsDSKegmQGA3GWjNq5lWUhPgkvIZfFXHeVZLgo/bNjR9eUJtGxUAArgFU2HdW23 WJZa3W3SAKD0m0i+wzekujbgfIeFlxoVot4uolu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9 /ZFvgrG+CJPbFEfxojfHRZ48x3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s= -----END CERTIFICATE----- AffirmTrust Premium =================== -----BEGIN CERTIFICATE----- MIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UEBhMCVVMxFDAS BgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVzdCBQcmVtaXVtMB4XDTEwMDEy OTE0MTAzNloXDTQwMTIzMTE0MTAzNlowQTELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRy dXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVzdCBQcmVtaXVtMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A MIICCgKCAgEAxBLfqV/+Qd3d9Z+K4/as4Tx4mrzY8H96oDMq3I0gW64tb+eT2TZwamjPjlGjhVtn BKAQJG9dKILBl1fYSCkTtuG+kU3fhQxTGJoeJKJPj/CihQvL9Cl/0qRY7iZNyaqoe5rZ+jjeRFcV 5fiMyNlI4g0WJx0eyIOFJbe6qlVBzAMiSy2RjYvmia9mx+n/K+k8rNrSs8PhaJyJ+HoAVt70VZVs +7pk3WKL3wt3MutizCaam7uqYoNMtAZ6MMgpv+0GTZe5HMQxK9VfvFMSF5yZVylmd2EhMQcuJUmd GPLu8ytxjLW6OQdJd/zvLpKQBY0tL3d770O/Nbua2Plzpyzy0FfuKE4mX4+QaAkvuPjcBukumj5R p9EixAqnOEhss/n/fauGV+O61oV4d7pD6kh/9ti+I20ev9E2bFhc8e6kGVQa9QPSdubhjL08s9NI S+LI+H+SqHZGnEJlPqQewQcDWkYtuJfzt9WyVSHvutxMAJf7FJUnM7/oQ0dG0giZFmA7mn7S5u04 6uwBHjxIVkkJx0w3AJ6IDsBz4W9m6XJHMD4Q5QsDyZpCAGzFlH5hxIrff4IaC1nEWTJ3s7xgaVY5 /bQGeyzWZDbZvUjthB9+pSKPKrhC9IK31FOQeE4tGv2Bb0TXOwF0lkLgAOIua+rF7nKsu7/+6qqo +Nz2snmKtmcCAwEAAaNCMEAwHQYDVR0OBBYEFJ3AZ6YMItkm9UWrpmVSESfYRaxjMA8GA1UdEwEB /wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBDAUAA4ICAQCzV00QYk465KzquByv MiPIs0laUZx2KI15qldGF9X1Uva3ROgIRL8YhNILgM3FEv0AVQVhh0HctSSePMTYyPtwni94loMg Nt58D2kTiKV1NpgIpsbfrM7jWNa3Pt668+s0QNiigfV4Py/VpfzZotReBA4Xrf5B8OWycvpEgjNC 6C1Y91aMYj+6QrCcDFx+LmUmXFNPALJ4fqENmS2NuB2OosSw/WDQMKSOyARiqcTtNd56l+0OOF6S L5Nwpamcb6d9Ex1+xghIsV5n61EIJenmJWtSKZGc0jlzCFfemQa0W50QBuHCAKi4HEoCChTQwUHK +4w1IX2COPKpVJEZNZOUbWo6xbLQu4mGk+ibyQ86p3q4ofB4Rvr8Ny/lioTz3/4E2aFooC8k4gmV BtWVyuEklut89pMFu+1z6S3RdTnX5yTb2E5fQ4+e0BQ5v1VwSJlXMbSc7kqYA5YwH2AG7hsj/oFg IxpHYoWlzBk0gG+zrBrjn/B7SK3VAdlntqlyk+otZrWyuOQ9PLLvTIzq6we/qzWaVYa8GKa1qF60 g2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaORtGdFNrHF+QFlozEJLUb zxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6eKeC2uAloGRwYQw== -----END CERTIFICATE----- AffirmTrust Premium ECC ======================= -----BEGIN CERTIFICATE----- MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMCVVMxFDASBgNV BAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQcmVtaXVtIEVDQzAeFw0xMDAx MjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJBgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1U cnVzdDEgMB4GA1UEAwwXQWZmaXJtVHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQA IgNiAAQNMF4bFZ0D0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQ N8O9ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0GA1UdDgQW BBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAK BggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/VsaobgxCd05DhT1wV/GzTjxi+zygk8N53X 57hG8f2h4nECMEJZh0PUUd+60wkyWs6Iflc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKM eQ== -----END CERTIFICATE----- Certum Trusted Network CA ========================= -----BEGIN CERTIFICATE----- MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBMMSIwIAYDVQQK ExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlv biBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBUcnVzdGVkIE5ldHdvcmsgQ0EwHhcNMDgxMDIy MTIwNzM3WhcNMjkxMjMxMTIwNzM3WjB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBU ZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5 MSIwIAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMIIBIjANBgkqhkiG9w0BAQEFAAOC AQ8AMIIBCgKCAQEA4/t9o3K6wvDJFIf1awFO4W5AB7ptJ11/91sts1rHUV+rpDKmYYe2bg+G0jAC l/jXaVehGDldamR5xgFZrDwxSjh80gTSSyjoIF87B6LMTXPb865Px1bVWqeWifrzq2jUI4ZZJ88J J7ysbnKDHDBy3+Ci6dLhdHUZvSqeexVUBBvXQzmtVSjF4hq79MDkrjhJM8x2hZ85RdKknvISjFH4 fOQtf/WsX+sWn7Et0brMkUJ3TCXJkDhv2/DM+44el1k+1WBO5gUo7Ul5E0u6SNsv+XLTOcr+H9g0 cvW0QM8xAcPs3hEtF10fuFDRXhmnad4HMyjKUJX5p1TLVIZQRan5SQIDAQABo0IwQDAPBgNVHRMB Af8EBTADAQH/MB0GA1UdDgQWBBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNVHQ8BAf8EBAMCAQYw DQYJKoZIhvcNAQEFBQADggEBAKaorSLOAT2mo/9i0Eidi15ysHhE49wcrwn9I0j6vSrEuVUEtRCj jSfeC4Jj0O7eDDd5QVsisrCaQVymcODU0HfLI9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1 mS1FhIrlQgnXdAIv94nYmem8J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5aj Zt3hrvJBW8qYVoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI 03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw= -----END CERTIFICATE----- TWCA Root Certification Authority ================================= -----BEGIN CERTIFICATE----- MIIDezCCAmOgAwIBAgIBATANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJUVzESMBAGA1UECgwJ VEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NBIFJvb3QgQ2VydGlmaWNh dGlvbiBBdXRob3JpdHkwHhcNMDgwODI4MDcyNDMzWhcNMzAxMjMxMTU1OTU5WjBfMQswCQYDVQQG EwJUVzESMBAGA1UECgwJVEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NB IFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK AoIBAQCwfnK4pAOU5qfeCTiRShFAh6d8WWQUe7UREN3+v9XAu1bihSX0NXIP+FPQQeFEAcK0HMMx QhZHhTMidrIKbw/lJVBPhYa+v5guEGcevhEFhgWQxFnQfHgQsIBct+HHK3XLfJ+utdGdIzdjp9xC oi2SBBtQwXu4PhvJVgSLL1KbralW6cH/ralYhzC2gfeXRfwZVzsrb+RH9JlF/h3x+JejiB03HFyP 4HYlmlD4oFT/RJB2I9IyxsOrBr/8+7/zrX2SYgJbKdM1o5OaQ2RgXbL6Mv87BK9NQGr5x+PvI/1r y+UPizgN7gr8/g+YnzAx3WxSZfmLgb4i4RxYA7qRG4kHAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIB BjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqOFsmjd6LWvJPelSDGRjjCDWmujANBgkqhkiG 9w0BAQUFAAOCAQEAPNV3PdrfibqHDAhUaiBQkr6wQT25JmSDCi/oQMCXKCeCMErJk/9q56YAf4lC mtYR5VPOL8zy2gXE/uJQxDqGfczafhAJO5I1KlOy/usrBdlsXebQ79NqZp4VKIV66IIArB6nCWlW QtNoURi+VJq/REG6Sb4gumlc7rh3zc5sH62Dlhh9DrUUOYTxKOkto557HnpyWoOzeW/vtPzQCqVY T0bf+215WfKEIlKuD8z7fDvnaspHYcN6+NOSBB+4IIThNlQWx0DeO4pz3N/GCUzf7Nr/1FNCocny Yh0igzyXxfkZYiesZSLX0zzG5Y6yU8xJzrww/nsOM5D77dIUkR8Hrw== -----END CERTIFICATE----- Security Communication RootCA2 ============================== -----BEGIN CERTIFICATE----- MIIDdzCCAl+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJKUDElMCMGA1UEChMc U0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UECxMeU2VjdXJpdHkgQ29tbXVuaWNh dGlvbiBSb290Q0EyMB4XDTA5MDUyOTA1MDAzOVoXDTI5MDUyOTA1MDAzOVowXTELMAkGA1UEBhMC SlAxJTAjBgNVBAoTHFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xJzAlBgNVBAsTHlNlY3Vy aXR5IENvbW11bmljYXRpb24gUm9vdENBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB ANAVOVKxUrO6xVmCxF1SrjpDZYBLx/KWvNs2l9amZIyoXvDjChz335c9S672XewhtUGrzbl+dp++ +T42NKA7wfYxEUV0kz1XgMX5iZnK5atq1LXaQZAQwdbWQonCv/Q4EpVMVAX3NuRFg3sUZdbcDE3R 3n4MqzvEFb46VqZab3ZpUql6ucjrappdUtAtCms1FgkQhNBqyjoGADdH5H5XTz+L62e4iKrFvlNV spHEfbmwhRkGeC7bYRr6hfVKkaHnFtWOojnflLhwHyg/i/xAXmODPIMqGplrz95Zajv8bxbXH/1K EOtOghY6rCcMU/Gt1SSwawNQwS08Ft1ENCcadfsCAwEAAaNCMEAwHQYDVR0OBBYEFAqFqXdlBZh8 QIH4D5csOPEK7DzPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEB CwUAA4IBAQBMOqNErLlFsceTfsgLCkLfZOoc7llsCLqJX2rKSpWeeo8HxdpFcoJxDjrSzG+ntKEj u/Ykn8sX/oymzsLS28yN/HH8AynBbF0zX2S2ZTuJbxh2ePXcokgfGT+Ok+vx+hfuzU7jBBJV1uXk 3fs+BXziHV7Gp7yXT2g69ekuCkO2r1dcYmh8t/2jioSgrGK+KwmHNPBqAbubKVY8/gA3zyNs8U6q tnRGEmyR7jTV7JqR50S+kDFy1UkC9gLl9B/rfNmWVan/7Ir5mUf/NVoCqgTLiluHcSmRvaS0eg29 mvVXIwAHIRc/SjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03 -----END CERTIFICATE----- Actalis Authentication Root CA ============================== -----BEGIN CERTIFICATE----- MIIFuzCCA6OgAwIBAgIIVwoRl0LE48wwDQYJKoZIhvcNAQELBQAwazELMAkGA1UEBhMCSVQxDjAM BgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8wMzM1ODUyMDk2NzEnMCUGA1UE AwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290IENBMB4XDTExMDkyMjExMjIwMloXDTMwMDky MjExMjIwMlowazELMAkGA1UEBhMCSVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlz IFMucC5BLi8wMzM1ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290 IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAp8bEpSmkLO/lGMWwUKNvUTufClrJ wkg4CsIcoBh/kbWHuUA/3R1oHwiD1S0eiKD4j1aPbZkCkpAW1V8IbInX4ay8IMKx4INRimlNAJZa by/ARH6jDuSRzVju3PvHHkVH3Se5CAGfpiEd9UEtL0z9KK3giq0itFZljoZUj5NDKd45RnijMCO6 zfB9E1fAXdKDa0hMxKufgFpbOr3JpyI/gCczWw63igxdBzcIy2zSekciRDXFzMwujt0q7bd9Zg1f YVEiVRvjRuPjPdA1YprbrxTIW6HMiRvhMCb8oJsfgadHHwTrozmSBp+Z07/T6k9QnBn+locePGX2 oxgkg4YQ51Q+qDp2JE+BIcXjDwL4k5RHILv+1A7TaLndxHqEguNTVHnd25zS8gebLra8Pu2Fbe8l EfKXGkJh90qX6IuxEAf6ZYGyojnP9zz/GPvG8VqLWeICrHuS0E4UT1lF9gxeKF+w6D9Fz8+vm2/7 hNN3WpVvrJSEnu68wEqPSpP4RCHiMUVhUE4Q2OM1fEwZtN4Fv6MGn8i1zeQf1xcGDXqVdFUNaBr8 EBtiZJ1t4JWgw5QHVw0U5r0F+7if5t+L4sbnfpb2U8WANFAoWPASUHEXMLrmeGO89LKtmyuy/uE5 jF66CyCU3nuDuP/jVo23Eek7jPKxwV2dpAtMK9myGPW1n0sCAwEAAaNjMGEwHQYDVR0OBBYEFFLY iDrIn3hm7YnzezhwlMkCAjbQMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUUtiIOsifeGbt ifN7OHCUyQICNtAwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQALe3KHwGCmSUyI WOYdiPcUZEim2FgKDk8TNd81HdTtBjHIgT5q1d07GjLukD0R0i70jsNjLiNmsGe+b7bAEzlgqqI0 JZN1Ut6nna0Oh4lScWoWPBkdg/iaKWW+9D+a2fDzWochcYBNy+A4mz+7+uAwTc+G02UQGRjRlwKx K3JCaKygvU5a2hi/a5iB0P2avl4VSM0RFbnAKVy06Ij3Pjaut2L9HmLecHgQHEhb2rykOLpn7VU+ Xlff1ANATIGk0k9jpwlCCRT8AKnCgHNPLsBA2RF7SOp6AsDT6ygBJlh0wcBzIm2Tlf05fbsq4/aC 4yyXX04fkZT6/iyj2HYauE2yOE+b+h1IYHkm4vP9qdCa6HCPSXrW5b0KDtst842/6+OkfcvHlXHo 2qN8xcL4dJIEG4aspCJTQLas/kx2z/uUMsA1n3Y/buWQbqCmJqK4LL7RK4X9p2jIugErsWx0Hbhz lefut8cl8ABMALJ+tguLHPPAUJ4lueAI3jZm/zel0btUZCzJJ7VLkn5l/9Mt4blOvH+kQSGQQXem OR/qnuOf0GZvBeyqdn6/axag67XH/JJULysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9 vwGYT7JZVEc+NHt4bVaTLnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg== -----END CERTIFICATE----- Buypass Class 2 Root CA ======================= -----BEGIN CERTIFICATE----- MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU QnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3MgQ2xhc3MgMiBSb290IENBMB4X DTEwMTAyNjA4MzgwM1oXDTQwMTAyNjA4MzgwM1owTjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1 eXBhc3MgQVMtOTgzMTYzMzI3MSAwHgYDVQQDDBdCdXlwYXNzIENsYXNzIDIgUm9vdCBDQTCCAiIw DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANfHXvfBB9R3+0Mh9PT1aeTuMgHbo4Yf5FkNuud1 g1Lr6hxhFUi7HQfKjK6w3Jad6sNgkoaCKHOcVgb/S2TwDCo3SbXlzwx87vFKu3MwZfPVL4O2fuPn 9Z6rYPnT8Z2SdIrkHJasW4DptfQxh6NR/Md+oW+OU3fUl8FVM5I+GC911K2GScuVr1QGbNgGE41b /+EmGVnAJLqBcXmQRFBoJJRfuLMR8SlBYaNByyM21cHxMlAQTn/0hpPshNOOvEu/XAFOBz3cFIqU CqTqc/sLUegTBxj6DvEr0VQVfTzh97QZQmdiXnfgolXsttlpF9U6r0TtSsWe5HonfOV116rLJeff awrbD02TTqigzXsu8lkBarcNuAeBfos4GzjmCleZPe4h6KP1DBbdi+w0jpwqHAAVF41og9JwnxgI zRFo1clrUs3ERo/ctfPYV3Me6ZQ5BL/T3jjetFPsaRyifsSP5BtwrfKi+fv3FmRmaZ9JUaLiFRhn Bkp/1Wy1TbMz4GHrXb7pmA8y1x1LPC5aAVKRCfLf6o3YBkBjqhHk/sM3nhRSP/TizPJhk9H9Z2vX Uq6/aKtAQ6BXNVN48FP4YUIHZMbXb5tMOA1jrGKvNouicwoN9SG9dKpN6nIDSdvHXx1iY8f93ZHs M+71bbRuMGjeyNYmsHVee7QHIJihdjK4TWxPAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD VR0OBBYEFMmAd+BikoL1RpzzuvdMw964o605MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsF AAOCAgEAU18h9bqwOlI5LJKwbADJ784g7wbylp7ppHR/ehb8t/W2+xUbP6umwHJdELFx7rxP462s A20ucS6vxOOto70MEae0/0qyexAQH6dXQbLArvQsWdZHEIjzIVEpMMpghq9Gqx3tOluwlN5E40EI osHsHdb9T7bWR9AUC8rmyrV7d35BH16Dx7aMOZawP5aBQW9gkOLo+fsicdl9sz1Gv7SEr5AcD48S aq/v7h56rgJKihcrdv6sVIkkLE8/trKnToyokZf7KcZ7XC25y2a2t6hbElGFtQl+Ynhw/qlqYLYd DnkM/crqJIByw5c/8nerQyIKx+u2DISCLIBrQYoIwOula9+ZEsuK1V6ADJHgJgg2SMX6OBE1/yWD LfJ6v9r9jv6ly0UsH8SIU653DtmadsWOLB2jutXsMq7Aqqz30XpN69QH4kj3Io6wpJ9qzo6ysmD0 oyLQI+uUWnpp3Q+/QFesa1lQ2aOZ4W7+jQF5JyMV3pKdewlNWudLSDBaGOYKbeaP4NK75t98biGC wWg5TbSYWGZizEqQXsP6JwSxeRV0mcy+rSDeJmAc61ZRpqPq5KM/p/9h3PFaTWwyI0PurKju7koS CTxdccK+efrCh2gdC/1cacwG0Jp9VJkqyTkaGa9LKkPzY11aWOIv4x3kqdbQCtCev9eBCfHJxyYN rJgWVqA= -----END CERTIFICATE----- Buypass Class 3 Root CA ======================= -----BEGIN CERTIFICATE----- MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU QnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3MgQ2xhc3MgMyBSb290IENBMB4X DTEwMTAyNjA4Mjg1OFoXDTQwMTAyNjA4Mjg1OFowTjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1 eXBhc3MgQVMtOTgzMTYzMzI3MSAwHgYDVQQDDBdCdXlwYXNzIENsYXNzIDMgUm9vdCBDQTCCAiIw DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKXaCpUWUOOV8l6ddjEGMnqb8RB2uACatVI2zSRH sJ8YZLya9vrVediQYkwiL944PdbgqOkcLNt4EemOaFEVcsfzM4fkoF0LXOBXByow9c3EN3coTRiR 5r/VUv1xLXA+58bEiuPwKAv0dpihi4dVsjoT/Lc+JzeOIuOoTyrvYLs9tznDDgFHmV0ST9tD+leh 7fmdvhFHJlsTmKtdFoqwNxxXnUX/iJY2v7vKB3tvh2PX0DJq1l1sDPGzbjniazEuOQAnFN44wOwZ ZoYS6J1yFhNkUsepNxz9gjDthBgd9K5c/3ATAOux9TN6S9ZV+AWNS2mw9bMoNlwUxFFzTWsL8TQH 2xc519woe2v1n/MuwU8XKhDzzMro6/1rqy6any2CbgTUUgGTLT2G/H783+9CHaZr77kgxve9oKeV /afmiSTYzIw0bOIjL9kSGiG5VZFvC5F5GQytQIgLcOJ60g7YaEi7ghM5EFjp2CoHxhLbWNvSO1UQ RwUVZ2J+GGOmRj8JDlQyXr8NYnon74Do29lLBlo3WiXQCBJ31G8JUJc9yB3D34xFMFbG02SrZvPA Xpacw8Tvw3xrizp5f7NJzz3iiZ+gMEuFuZyUJHmPfWupRWgPK9Dx2hzLabjKSWJtyNBjYt1gD1iq j6G8BaVmos8bdrKEZLFMOVLAMLrwjEsCsLa3AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD VR0OBBYEFEe4zf/lb+74suwvTg75JbCOPGvDMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsF AAOCAgEAACAjQTUEkMJAYmDv4jVM1z+s4jSQuKFvdvoWFqRINyzpkMLyPPgKn9iB5btb2iUspKdV cSQy9sgL8rxq+JOssgfCX5/bzMiKqr5qb+FJEMwx14C7u8jYog5kV+qi9cKpMRXSIGrs/CIBKM+G uIAeqcwRpTzyFrNHnfzSgCHEy9BHcEGhyoMZCCxt8l13nIoUE9Q2HJLw5QY33KbmkJs4j1xrG0aG Q0JfPgEHU1RdZX33inOhmlRaHylDFCfChQ+1iHsaO5S3HWCntZznKWlXWpuTekMwGwPXYshApqr8 ZORK15FTAaggiG6cX0S5y2CBNOxv033aSF/rtJC8LakcC6wc1aJoIIAE1vyxjy+7SjENSoYc6+I2 KSb12tjE8nVhz36udmNKekBlk4f4HoCMhuWG1o8O/FMsYOgWYRqiPkN7zTlgVGr18okmAWiDSKIz 6MkEkbIRNBE+6tBDGR8Dk5AM/1E9V/RBbuHLoL7ryWPNbczk+DaqaJ3tvV2XcEQNtg413OEMXbug UZTLfhbrES+jkkXITHHZvMmZUldGL1DPvTVp9D0VzgalLA8+9oG6lLvDu79leNKGef9JOxqDDPDe eOzI8k1MGt6CKfjBWtrt7uYnXuhF0J0cUahoq0Tj0Itq4/g7u9xN12TyUb7mqqta6THuBrxzvxNi Cp/HuZc= -----END CERTIFICATE----- T-TeleSec GlobalRoot Class 3 ============================ -----BEGIN CERTIFICATE----- MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoM IlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBU cnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwHhcNMDgx MDAxMTAyOTU2WhcNMzMxMDAxMjM1OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lz dGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBD ZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwggEiMA0GCSqGSIb3 DQEBAQUAA4IBDwAwggEKAoIBAQC9dZPwYiJvJK7genasfb3ZJNW4t/zN8ELg63iIVl6bmlQdTQyK 9tPPcPRStdiTBONGhnFBSivwKixVA9ZIw+A5OO3yXDw/RLyTPWGrTs0NvvAgJ1gORH8EGoel15YU NpDQSXuhdfsaa3Ox+M6pCSzyU9XDFES4hqX2iys52qMzVNn6chr3IhUciJFrf2blw2qAsCTz34ZF iP0Zf3WHHx+xGwpzJFu5ZeAsVMhg02YXP+HMVDNzkQI6pn97djmiH5a2OK61yJN0HZ65tOVgnS9W 0eDrXltMEnAMbEQgqxHY9Bn20pxSN+f6tsIxO0rUFJmtxxr1XV/6B7h8DR/Wgx6zAgMBAAGjQjBA MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS1A/d2O2GCahKqGFPr AyGUv/7OyjANBgkqhkiG9w0BAQsFAAOCAQEAVj3vlNW92nOyWL6ukK2YJ5f+AbGwUgC4TeQbIXQb fsDuXmkqJa9c1h3a0nnJ85cp4IaH3gRZD/FZ1GSFS5mvJQQeyUapl96Cshtwn5z2r3Ex3XsFpSzT ucpH9sry9uetuUg/vBa3wW306gmv7PO15wWeph6KU1HWk4HMdJP2udqmJQV0eVp+QD6CSyYRMG7h P0HHRwA11fXT91Q+gT3aSWqas+8QPebrb9HIIkfLzM8BMZLZGOMivgkeGj5asuRrDFR6fUNOuIml e9eiPZaGzPImNC1qkp2aGtAw4l1OBLBfiyB+d8E9lYLRRpo7PHi4b6HQDWSieB4pTpPDpFQUWw== -----END CERTIFICATE----- D-TRUST Root Class 3 CA 2 2009 ============================== -----BEGIN CERTIFICATE----- MIIEMzCCAxugAwIBAgIDCYPzMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQK DAxELVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTAe Fw0wOTExMDUwODM1NThaFw0yOTExMDUwODM1NThaME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxE LVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTCCASIw DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANOySs96R+91myP6Oi/WUEWJNTrGa9v+2wBoqOAD ER03UAifTUpolDWzU9GUY6cgVq/eUXjsKj3zSEhQPgrfRlWLJ23DEE0NkVJD2IfgXU42tSHKXzlA BF9bfsyjxiupQB7ZNoTWSPOSHjRGICTBpFGOShrvUD9pXRl/RcPHAY9RySPocq60vFYJfxLLHLGv KZAKyVXMD9O0Gu1HNVpK7ZxzBCHQqr0ME7UAyiZsxGsMlFqVlNpQmvH/pStmMaTJOKDfHR+4CS7z p+hnUquVH+BGPtikw8paxTGA6Eian5Rp/hnd2HN8gcqW3o7tszIFZYQ05ub9VxC1X3a/L7AQDcUC AwEAAaOCARowggEWMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFP3aFMSfMN4hvR5COfyrYyNJ 4PGEMA4GA1UdDwEB/wQEAwIBBjCB0wYDVR0fBIHLMIHIMIGAoH6gfIZ6bGRhcDovL2RpcmVjdG9y eS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwUm9vdCUyMENsYXNzJTIwMyUyMENBJTIwMiUyMDIw MDksTz1ELVRydXN0JTIwR21iSCxDPURFP2NlcnRpZmljYXRlcmV2b2NhdGlvbmxpc3QwQ6BBoD+G PWh0dHA6Ly93d3cuZC10cnVzdC5uZXQvY3JsL2QtdHJ1c3Rfcm9vdF9jbGFzc18zX2NhXzJfMjAw OS5jcmwwDQYJKoZIhvcNAQELBQADggEBAH+X2zDI36ScfSF6gHDOFBJpiBSVYEQBrLLpME+bUMJm 2H6NMLVwMeniacfzcNsgFYbQDfC+rAF1hM5+n02/t2A7nPPKHeJeaNijnZflQGDSNiH+0LS4F9p0 o3/U37CYAqxva2ssJSRyoWXuJVrl5jLn8t+rSfrzkGkj2wTZ51xY/GXUl77M/C4KzCUqNQT4YJEV dT1B/yMfGchs64JTBKbkTCJNjYy6zltz7GRUUG3RnFX7acM2w4y8PIWmawomDeCTmGCufsYkl4ph X5GOZpIJhzbNi5stPvZR1FDUWSi9g/LMKHtThm3YJohw1+qRzT65ysCQblrGXnRl11z+o+I= -----END CERTIFICATE----- D-TRUST Root Class 3 CA 2 EV 2009 ================================= -----BEGIN CERTIFICATE----- MIIEQzCCAyugAwIBAgIDCYP0MA0GCSqGSIb3DQEBCwUAMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQK DAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAw OTAeFw0wOTExMDUwODUwNDZaFw0yOTExMDUwODUwNDZaMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQK DAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAw OTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJnxhDRwui+3MKCOvXwEz75ivJn9gpfS egpnljgJ9hBOlSJzmY3aFS3nBfwZcyK3jpgAvDw9rKFs+9Z5JUut8Mxk2og+KbgPCdM03TP1YtHh zRnp7hhPTFiu4h7WDFsVWtg6uMQYZB7jM7K1iXdODL/ZlGsTl28So/6ZqQTMFexgaDbtCHu39b+T 7WYxg4zGcTSHThfqr4uRjRxWQa4iN1438h3Z0S0NL2lRp75mpoo6Kr3HGrHhFPC+Oh25z1uxav60 sUYgovseO3Dvk5h9jHOW8sXvhXCtKSb8HgQ+HKDYD8tSg2J87otTlZCpV6LqYQXY+U3EJ/pure35 11H3a6UCAwEAAaOCASQwggEgMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNOUikxiEyoZLsyv cop9NteaHNxnMA4GA1UdDwEB/wQEAwIBBjCB3QYDVR0fBIHVMIHSMIGHoIGEoIGBhn9sZGFwOi8v ZGlyZWN0b3J5LmQtdHJ1c3QubmV0L0NOPUQtVFJVU1QlMjBSb290JTIwQ2xhc3MlMjAzJTIwQ0El MjAyJTIwRVYlMjAyMDA5LE89RC1UcnVzdCUyMEdtYkgsQz1ERT9jZXJ0aWZpY2F0ZXJldm9jYXRp b25saXN0MEagRKBChkBodHRwOi8vd3d3LmQtdHJ1c3QubmV0L2NybC9kLXRydXN0X3Jvb3RfY2xh c3NfM19jYV8yX2V2XzIwMDkuY3JsMA0GCSqGSIb3DQEBCwUAA4IBAQA07XtaPKSUiO8aEXUHL7P+ PPoeUSbrh/Yp3uDx1MYkCenBz1UbtDDZzhr+BlGmFaQt77JLvyAoJUnRpjZ3NOhk31KxEcdzes05 nsKtjHEh8lprr988TlWvsoRlFIm5d8sqMb7Po23Pb0iUMkZv53GMoKaEGTcH8gNFCSuGdXzfX2lX ANtu2KZyIktQ1HWYVt+3GP9DQ1CuekR78HlR10M9p9OB0/DJT7naxpeG0ILD5EJt/rDiZE4OJudA NCa1CInXCGNjOCd1HjPqbqjdn5lPdE2BiYBL3ZqXKVwvvoFBuYz/6n1gBp7N1z3TLqMVvKjmJuVv w9y4AyHqnxbxLFS1 -----END CERTIFICATE----- CA Disig Root R2 ================ -----BEGIN CERTIFICATE----- MIIFaTCCA1GgAwIBAgIJAJK4iNuwisFjMA0GCSqGSIb3DQEBCwUAMFIxCzAJBgNVBAYTAlNLMRMw EQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMuMRkwFwYDVQQDExBDQSBEaXNp ZyBSb290IFIyMB4XDTEyMDcxOTA5MTUzMFoXDTQyMDcxOTA5MTUzMFowUjELMAkGA1UEBhMCU0sx EzARBgNVBAcTCkJyYXRpc2xhdmExEzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERp c2lnIFJvb3QgUjIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCio8QACdaFXS1tFPbC w3OeNcJxVX6B+6tGUODBfEl45qt5WDza/3wcn9iXAng+a0EE6UG9vgMsRfYvZNSrXaNHPWSb6Wia xswbP7q+sos0Ai6YVRn8jG+qX9pMzk0DIaPY0jSTVpbLTAwAFjxfGs3Ix2ymrdMxp7zo5eFm1tL7 A7RBZckQrg4FY8aAamkw/dLukO8NJ9+flXP04SXabBbeQTg06ov80egEFGEtQX6sx3dOy1FU+16S GBsEWmjGycT6txOgmLcRK7fWV8x8nhfRyyX+hk4kLlYMeE2eARKmK6cBZW58Yh2EhN/qwGu1pSqV g8NTEQxzHQuyRpDRQjrOQG6Vrf/GlK1ul4SOfW+eioANSW1z4nuSHsPzwfPrLgVv2RvPN3YEyLRa 5Beny912H9AZdugsBbPWnDTYltxhh5EF5EQIM8HauQhl1K6yNg3ruji6DOWbnuuNZt2Zz9aJQfYE koopKW1rOhzndX0CcQ7zwOe9yxndnWCywmZgtrEE7snmhrmaZkCo5xHtgUUDi/ZnWejBBhG93c+A Ak9lQHhcR1DIm+YfgXvkRKhbhZri3lrVx/k6RGZL5DJUfORsnLMOPReisjQS1n6yqEm70XooQL6i Fh/f5DcfEXP7kAplQ6INfPgGAVUzfbANuPT1rqVCV3w2EYx7XsQDnYx5nQIDAQABo0IwQDAPBgNV HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUtZn4r7CU9eMg1gqtzk5WpC5u Qu0wDQYJKoZIhvcNAQELBQADggIBACYGXnDnZTPIgm7ZnBc6G3pmsgH2eDtpXi/q/075KMOYKmFM tCQSin1tERT3nLXK5ryeJ45MGcipvXrA1zYObYVybqjGom32+nNjf7xueQgcnYqfGopTpti72TVV sRHFqQOzVju5hJMiXn7B9hJSi+osZ7z+Nkz1uM/Rs0mSO9MpDpkblvdhuDvEK7Z4bLQjb/D907Je dR+Zlais9trhxTF7+9FGs9K8Z7RiVLoJ92Owk6Ka+elSLotgEqv89WBW7xBci8QaQtyDW2QOy7W8 1k/BfDxujRNt+3vrMNDcTa/F1balTFtxyegxvug4BkihGuLq0t4SOVga/4AOgnXmt8kHbA7v/zjx mHHEt38OFdAlab0inSvtBfZGR6ztwPDUO+Ls7pZbkBNOHlY667DvlruWIxG68kOGdGSVyCh13x01 utI3gzhTODY7z2zp+WsO0PsE6E9312UBeIYMej4hYvF/Y3EMyZ9E26gnonW+boE+18DrG5gPcFw0 sorMwIUY6256s/daoQe/qUKS82Ail+QUoQebTnbAjn39pCXHR+3/H3OszMOl6W8KjptlwlCFtaOg UxLMVYdh84GuEEZhvUQhuMI9dM9+JDX6HAcOmz0iyu8xL4ysEr3vQCj8KWefshNPZiTEUxnpHikV 7+ZtsH8tZ/3zbBt1RqPlShfppNcL -----END CERTIFICATE----- ACCVRAIZ1 ========= -----BEGIN CERTIFICATE----- MIIH0zCCBbugAwIBAgIIXsO3pkN/pOAwDQYJKoZIhvcNAQEFBQAwQjESMBAGA1UEAwwJQUNDVlJB SVoxMRAwDgYDVQQLDAdQS0lBQ0NWMQ0wCwYDVQQKDARBQ0NWMQswCQYDVQQGEwJFUzAeFw0xMTA1 MDUwOTM3MzdaFw0zMDEyMzEwOTM3MzdaMEIxEjAQBgNVBAMMCUFDQ1ZSQUlaMTEQMA4GA1UECwwH UEtJQUNDVjENMAsGA1UECgwEQUNDVjELMAkGA1UEBhMCRVMwggIiMA0GCSqGSIb3DQEBAQUAA4IC DwAwggIKAoICAQCbqau/YUqXry+XZpp0X9DZlv3P4uRm7x8fRzPCRKPfmt4ftVTdFXxpNRFvu8gM jmoYHtiP2Ra8EEg2XPBjs5BaXCQ316PWywlxufEBcoSwfdtNgM3802/J+Nq2DoLSRYWoG2ioPej0 RGy9ocLLA76MPhMAhN9KSMDjIgro6TenGEyxCQ0jVn8ETdkXhBilyNpAlHPrzg5XPAOBOp0KoVdD aaxXbXmQeOW1tDvYvEyNKKGno6e6Ak4l0Squ7a4DIrhrIA8wKFSVf+DuzgpmndFALW4ir50awQUZ 0m/A8p/4e7MCQvtQqR0tkw8jq8bBD5L/0KIV9VMJcRz/RROE5iZe+OCIHAr8Fraocwa48GOEAqDG WuzndN9wrqODJerWx5eHk6fGioozl2A3ED6XPm4pFdahD9GILBKfb6qkxkLrQaLjlUPTAYVtjrs7 8yM2x/474KElB0iryYl0/wiPgL/AlmXz7uxLaL2diMMxs0Dx6M/2OLuc5NF/1OVYm3z61PMOm3WR 5LpSLhl+0fXNWhn8ugb2+1KoS5kE3fj5tItQo05iifCHJPqDQsGH+tUtKSpacXpkatcnYGMN285J 9Y0fkIkyF/hzQ7jSWpOGYdbhdQrqeWZ2iE9x6wQl1gpaepPluUsXQA+xtrn13k/c4LOsOxFwYIRK Q26ZIMApcQrAZQIDAQABo4ICyzCCAscwfQYIKwYBBQUHAQEEcTBvMEwGCCsGAQUFBzAChkBodHRw Oi8vd3d3LmFjY3YuZXMvZmlsZWFkbWluL0FyY2hpdm9zL2NlcnRpZmljYWRvcy9yYWl6YWNjdjEu Y3J0MB8GCCsGAQUFBzABhhNodHRwOi8vb2NzcC5hY2N2LmVzMB0GA1UdDgQWBBTSh7Tj3zcnk1X2 VuqB5TbMjB4/vTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNKHtOPfNyeTVfZW6oHlNsyM Hj+9MIIBcwYDVR0gBIIBajCCAWYwggFiBgRVHSAAMIIBWDCCASIGCCsGAQUFBwICMIIBFB6CARAA QQB1AHQAbwByAGkAZABhAGQAIABkAGUAIABDAGUAcgB0AGkAZgBpAGMAYQBjAGkA8wBuACAAUgBh AO0AegAgAGQAZQAgAGwAYQAgAEEAQwBDAFYAIAAoAEEAZwBlAG4AYwBpAGEAIABkAGUAIABUAGUA YwBuAG8AbABvAGcA7QBhACAAeQAgAEMAZQByAHQAaQBmAGkAYwBhAGMAaQDzAG4AIABFAGwAZQBj AHQAcgDzAG4AaQBjAGEALAAgAEMASQBGACAAUQA0ADYAMAAxADEANQA2AEUAKQAuACAAQwBQAFMA IABlAG4AIABoAHQAdABwADoALwAvAHcAdwB3AC4AYQBjAGMAdgAuAGUAczAwBggrBgEFBQcCARYk aHR0cDovL3d3dy5hY2N2LmVzL2xlZ2lzbGFjaW9uX2MuaHRtMFUGA1UdHwROMEwwSqBIoEaGRGh0 dHA6Ly93d3cuYWNjdi5lcy9maWxlYWRtaW4vQXJjaGl2b3MvY2VydGlmaWNhZG9zL3JhaXphY2N2 MV9kZXIuY3JsMA4GA1UdDwEB/wQEAwIBBjAXBgNVHREEEDAOgQxhY2N2QGFjY3YuZXMwDQYJKoZI hvcNAQEFBQADggIBAJcxAp/n/UNnSEQU5CmH7UwoZtCPNdpNYbdKl02125DgBS4OxnnQ8pdpD70E R9m+27Up2pvZrqmZ1dM8MJP1jaGo/AaNRPTKFpV8M9xii6g3+CfYCS0b78gUJyCpZET/LtZ1qmxN YEAZSUNUY9rizLpm5U9EelvZaoErQNV/+QEnWCzI7UiRfD+mAM/EKXMRNt6GGT6d7hmKG9Ww7Y49 nCrADdg9ZuM8Db3VlFzi4qc1GwQA9j9ajepDvV+JHanBsMyZ4k0ACtrJJ1vnE5Bc5PUzolVt3OAJ TS+xJlsndQAJxGJ3KQhfnlmstn6tn1QwIgPBHnFk/vk4CpYY3QIUrCPLBhwepH2NDd4nQeit2hW3 sCPdK6jT2iWH7ehVRE2I9DZ+hJp4rPcOVkkO1jMl1oRQQmwgEh0q1b688nCBpHBgvgW1m54ERL5h I6zppSSMEYCUWqKiuUnSwdzRp+0xESyeGabu4VXhwOrPDYTkF7eifKXeVSUG7szAh1xA2syVP1Xg Nce4hL60Xc16gwFy7ofmXx2utYXGJt/mwZrpHgJHnyqobalbz+xFd3+YJ5oyXSrjhO7FmGYvliAd 3djDJ9ew+f7Zfc3Qn48LFFhRny+Lwzgt3uiP1o2HpPVWQxaZLPSkVrQ0uGE3ycJYgBugl6H8WY3p EfbRD0tVNEYqi4Y7 -----END CERTIFICATE----- TWCA Global Root CA =================== -----BEGIN CERTIFICATE----- MIIFQTCCAymgAwIBAgICDL4wDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCVFcxEjAQBgNVBAoT CVRBSVdBTi1DQTEQMA4GA1UECxMHUm9vdCBDQTEcMBoGA1UEAxMTVFdDQSBHbG9iYWwgUm9vdCBD QTAeFw0xMjA2MjcwNjI4MzNaFw0zMDEyMzExNTU5NTlaMFExCzAJBgNVBAYTAlRXMRIwEAYDVQQK EwlUQUlXQU4tQ0ExEDAOBgNVBAsTB1Jvb3QgQ0ExHDAaBgNVBAMTE1RXQ0EgR2xvYmFsIFJvb3Qg Q0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCwBdvI64zEbooh745NnHEKH1Jw7W2C nJfF10xORUnLQEK1EjRsGcJ0pDFfhQKX7EMzClPSnIyOt7h52yvVavKOZsTuKwEHktSz0ALfUPZV r2YOy+BHYC8rMjk1Ujoog/h7FsYYuGLWRyWRzvAZEk2tY/XTP3VfKfChMBwqoJimFb3u/Rk28OKR Q4/6ytYQJ0lM793B8YVwm8rqqFpD/G2Gb3PpN0Wp8DbHzIh1HrtsBv+baz4X7GGqcXzGHaL3SekV tTzWoWH1EfcFbx39Eb7QMAfCKbAJTibc46KokWofwpFFiFzlmLhxpRUZyXx1EcxwdE8tmx2RRP1W KKD+u4ZqyPpcC1jcxkt2yKsi2XMPpfRaAok/T54igu6idFMqPVMnaR1sjjIsZAAmY2E2TqNGtz99 sy2sbZCilaLOz9qC5wc0GZbpuCGqKX6mOL6OKUohZnkfs8O1CWfe1tQHRvMq2uYiN2DLgbYPoA/p yJV/v1WRBXrPPRXAb94JlAGD1zQbzECl8LibZ9WYkTunhHiVJqRaCPgrdLQABDzfuBSO6N+pjWxn kjMdwLfS7JLIvgm/LCkFbwJrnu+8vyq8W8BQj0FwcYeyTbcEqYSjMq+u7msXi7Kx/mzhkIyIqJdI zshNy/MGz19qCkKxHh53L46g5pIOBvwFItIm4TFRfTLcDwIDAQABoyMwITAOBgNVHQ8BAf8EBAMC AQYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAXzSBdu+WHdXltdkCY4QWwa6g cFGn90xHNcgL1yg9iXHZqjNB6hQbbCEAwGxCGX6faVsgQt+i0trEfJdLjbDorMjupWkEmQqSpqsn LhpNgb+E1HAerUf+/UqdM+DyucRFCCEK2mlpc3INvjT+lIutwx4116KD7+U4x6WFH6vPNOw/KP4M 8VeGTslV9xzU2KV9Bnpv1d8Q34FOIWWxtuEXeZVFBs5fzNxGiWNoRI2T9GRwoD2dKAXDOXC4Ynsg /eTb6QihuJ49CcdP+yz4k3ZB3lLg4VfSnQO8d57+nile98FRYB/e2guyLXW3Q0iT5/Z5xoRdgFlg lPx4mI88k1HtQJAH32RjJMtOcQWh15QaiDLxInQirqWm2BJpTGCjAu4r7NRjkgtevi92a6O2JryP A9gK8kxkRr05YuWW6zRjESjMlfGt7+/cgFhI6Uu46mWs6fyAtbXIRfmswZ/ZuepiiI7E8UuDEq3m i4TWnsLrgxifarsbJGAzcMzs9zLzXNl5fe+epP7JI8Mk7hWSsT2RTyaGvWZzJBPqpK5jwa19hAM8 EHiGG3njxPPyBJUgriOCxLM6AGK/5jYk4Ve6xx6QddVfP5VhK8E7zeWzaGHQRiapIVJpLesux+t3 zqY6tQMzT3bR51xUAV3LePTJDL/PEo4XLSNolOer/qmyKwbQBM0= -----END CERTIFICATE----- TeliaSonera Root CA v1 ====================== -----BEGIN CERTIFICATE----- MIIFODCCAyCgAwIBAgIRAJW+FqD3LkbxezmCcvqLzZYwDQYJKoZIhvcNAQEFBQAwNzEUMBIGA1UE CgwLVGVsaWFTb25lcmExHzAdBgNVBAMMFlRlbGlhU29uZXJhIFJvb3QgQ0EgdjEwHhcNMDcxMDE4 MTIwMDUwWhcNMzIxMDE4MTIwMDUwWjA3MRQwEgYDVQQKDAtUZWxpYVNvbmVyYTEfMB0GA1UEAwwW VGVsaWFTb25lcmEgUm9vdCBDQSB2MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMK+ 6yfwIaPzaSZVfp3FVRaRXP3vIb9TgHot0pGMYzHw7CTww6XScnwQbfQ3t+XmfHnqjLWCi65ItqwA 3GV17CpNX8GH9SBlK4GoRz6JI5UwFpB/6FcHSOcZrr9FZ7E3GwYq/t75rH2D+1665I+XZ75Ljo1k B1c4VWk0Nj0TSO9P4tNmHqTPGrdeNjPUtAa9GAH9d4RQAEX1jF3oI7x+/jXh7VB7qTCNGdMJjmhn Xb88lxhTuylixcpecsHHltTbLaC0H2kD7OriUPEMPPCs81Mt8Bz17Ww5OXOAFshSsCPN4D7c3TxH oLs1iuKYaIu+5b9y7tL6pe0S7fyYGKkmdtwoSxAgHNN/Fnct7W+A90m7UwW7XWjH1Mh1Fj+JWov3 F0fUTPHSiXk+TT2YqGHeOh7S+F4D4MHJHIzTjU3TlTazN19jY5szFPAtJmtTfImMMsJu7D0hADnJ oWjiUIMusDor8zagrC/kb2HCUQk5PotTubtn2txTuXZZNp1D5SDgPTJghSJRt8czu90VL6R4pgd7 gUY2BIbdeTXHlSw7sKMXNeVzH7RcWe/a6hBle3rQf5+ztCo3O3CLm1u5K7fsslESl1MpWtTwEhDc TwK7EpIvYtQ/aUN8Ddb8WHUBiJ1YFkveupD/RwGJBmr2X7KQarMCpgKIv7NHfirZ1fpoeDVNAgMB AAGjPzA9MA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBTwj1k4ALP1j5qW DNXr+nuqF+gTEjANBgkqhkiG9w0BAQUFAAOCAgEAvuRcYk4k9AwI//DTDGjkk0kiP0Qnb7tt3oNm zqjMDfz1mgbldxSR651Be5kqhOX//CHBXfDkH1e3damhXwIm/9fH907eT/j3HEbAek9ALCI18Bmx 0GtnLLCo4MBANzX2hFxc469CeP6nyQ1Q6g2EdvZR74NTxnr/DlZJLo961gzmJ1TjTQpgcmLNkQfW pb/ImWvtxBnmq0wROMVvMeJuScg/doAmAyYp4Db29iBT4xdwNBedY2gea+zDTYa4EzAvXUYNR0PV G6pZDrlcjQZIrXSHX8f8MVRBE+LHIQ6e4B4N4cB7Q4WQxYpYxmUKeFfyxiMPAdkgS94P+5KFdSpc c41teyWRyu5FrgZLAMzTsVlQ2jqIOylDRl6XK1TOU2+NSueW+r9xDkKLfP0ooNBIytrEgUy7onOT JsjrDNYmiLbAJM+7vVvrdX3pCI6GMyx5dwlppYn8s3CQh3aP0yK7Qs69cwsgJirQmz1wHiRszYd2 qReWt88NkvuOGKmYSdGe/mBEciG5Ge3C9THxOUiIkCR1VBatzvT4aRRkOfujuLpwQMcnHL/EVlP6 Y2XQ8xwOFvVrhlhNGNTkDY6lnVuR3HYkUD/GKvvZt5y11ubQ2egZixVxSK236thZiNSQvxaz2ems WWFUyBy6ysHK4bkgTI86k4mloMy/0/Z1pHWWbVY= -----END CERTIFICATE----- T-TeleSec GlobalRoot Class 2 ============================ -----BEGIN CERTIFICATE----- MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoM IlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBU cnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwHhcNMDgx MDAxMTA0MDE0WhcNMzMxMDAxMjM1OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lz dGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBD ZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwggEiMA0GCSqGSIb3 DQEBAQUAA4IBDwAwggEKAoIBAQCqX9obX+hzkeXaXPSi5kfl82hVYAUdAqSzm1nzHoqvNK38DcLZ SBnuaY/JIPwhqgcZ7bBcrGXHX+0CfHt8LRvWurmAwhiCFoT6ZrAIxlQjgeTNuUk/9k9uN0goOA/F vudocP05l03Sx5iRUKrERLMjfTlH6VJi1hKTXrcxlkIF+3anHqP1wvzpesVsqXFP6st4vGCvx970 2cu+fjOlbpSD8DT6IavqjnKgP6TeMFvvhk1qlVtDRKgQFRzlAVfFmPHmBiiRqiDFt1MmUUOyCxGV WOHAD3bZwI18gfNycJ5v/hqO2V81xrJvNHy+SE/iWjnX2J14np+GPgNeGYtEotXHAgMBAAGjQjBA MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS/WSA2AHmgoCJrjNXy YdK4LMuCSjANBgkqhkiG9w0BAQsFAAOCAQEAMQOiYQsfdOhyNsZt+U2e+iKo4YFWz827n+qrkRk4 r6p8FU3ztqONpfSO9kSpp+ghla0+AGIWiPACuvxhI+YzmzB6azZie60EI4RYZeLbK4rnJVM3YlNf vNoBYimipidx5joifsFvHZVwIEoHNN/q/xWA5brXethbdXwFeilHfkCoMRN3zUA7tFFHei4R40cR 3p1m0IvVVGb6g1XqfMIpiRvpb7PO4gWEyS8+eIVibslfwXhjdFjASBgMmTnrpMwatXlajRWc2BQN 9noHV8cigwUtPJslJj0Ys6lDfMjIq2SPDqO/nBudMNva0Bkuqjzx+zOAduTNrRlPBSeOE6Fuwg== -----END CERTIFICATE----- Atos TrustedRoot 2011 ===================== -----BEGIN CERTIFICATE----- MIIDdzCCAl+gAwIBAgIIXDPLYixfszIwDQYJKoZIhvcNAQELBQAwPDEeMBwGA1UEAwwVQXRvcyBU cnVzdGVkUm9vdCAyMDExMQ0wCwYDVQQKDARBdG9zMQswCQYDVQQGEwJERTAeFw0xMTA3MDcxNDU4 MzBaFw0zMDEyMzEyMzU5NTlaMDwxHjAcBgNVBAMMFUF0b3MgVHJ1c3RlZFJvb3QgMjAxMTENMAsG A1UECgwEQXRvczELMAkGA1UEBhMCREUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCV hTuXbyo7LjvPpvMpNb7PGKw+qtn4TaA+Gke5vJrf8v7MPkfoepbCJI419KkM/IL9bcFyYie96mvr 54rMVD6QUM+A1JX76LWC1BTFtqlVJVfbsVD2sGBkWXppzwO3bw2+yj5vdHLqqjAqc2K+SZFhyBH+ DgMq92og3AIVDV4VavzjgsG1xZ1kCWyjWZgHJ8cblithdHFsQ/H3NYkQ4J7sVaE3IqKHBAUsR320 HLliKWYoyrfhk/WklAOZuXCFteZI6o1Q/NnezG8HDt0Lcp2AMBYHlT8oDv3FdU9T1nSatCQujgKR z3bFmx5VdJx4IbHwLfELn8LVlhgf8FQieowHAgMBAAGjfTB7MB0GA1UdDgQWBBSnpQaxLKYJYO7R l+lwrrw7GWzbITAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKelBrEspglg7tGX6XCuvDsZ bNshMBgGA1UdIAQRMA8wDQYLKwYBBAGwLQMEAQEwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB CwUAA4IBAQAmdzTblEiGKkGdLD4GkGDEjKwLVLgfuXvTBznk+j57sj1O7Z8jvZfza1zv7v1Apt+h k6EKhqzvINB5Ab149xnYJDE0BAGmuhWawyfc2E8PzBhj/5kPDpFrdRbhIfzYJsdHt6bPWHJxfrrh TZVHO8mvbaG0weyJ9rQPOLXiZNwlz6bb65pcmaHFCN795trV1lpFDMS3wrUU77QR/w4VtfX128a9 61qn8FYiqTxlVMYVqL2Gns2Dlmh6cYGJ4Qvh6hEbaAjMaZ7snkGeRDImeuKHCnE96+RapNLbxc3G 3mB/ufNPRJLvKrcYPqcZ2Qt9sTdBQrC6YB3y/gkRsPCHe6ed -----END CERTIFICATE----- QuoVadis Root CA 1 G3 ===================== -----BEGIN CERTIFICATE----- MIIFYDCCA0igAwIBAgIUeFhfLq0sGUvjNwc1NBMotZbUZZMwDQYJKoZIhvcNAQELBQAwSDELMAkG A1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAcBgNVBAMTFVF1b1ZhZGlzIFJv b3QgQ0EgMSBHMzAeFw0xMjAxMTIxNzI3NDRaFw00MjAxMTIxNzI3NDRaMEgxCzAJBgNVBAYTAkJN MRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDEg RzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCgvlAQjunybEC0BJyFuTHK3C3kEakE PBtVwedYMB0ktMPvhd6MLOHBPd+C5k+tR4ds7FtJwUrVu4/sh6x/gpqG7D0DmVIB0jWerNrwU8lm PNSsAgHaJNM7qAJGr6Qc4/hzWHa39g6QDbXwz8z6+cZM5cOGMAqNF34168Xfuw6cwI2H44g4hWf6 Pser4BOcBRiYz5P1sZK0/CPTz9XEJ0ngnjybCKOLXSoh4Pw5qlPafX7PGglTvF0FBM+hSo+LdoIN ofjSxxR3W5A2B4GbPgb6Ul5jxaYA/qXpUhtStZI5cgMJYr2wYBZupt0lwgNm3fME0UDiTouG9G/l g6AnhF4EwfWQvTA9xO+oabw4m6SkltFi2mnAAZauy8RRNOoMqv8hjlmPSlzkYZqn0ukqeI1RPToV 7qJZjqlc3sX5kCLliEVx3ZGZbHqfPT2YfF72vhZooF6uCyP8Wg+qInYtyaEQHeTTRCOQiJ/GKubX 9ZqzWB4vMIkIG1SitZgj7Ah3HJVdYdHLiZxfokqRmu8hqkkWCKi9YSgxyXSthfbZxbGL0eUQMk1f iyA6PEkfM4VZDdvLCXVDaXP7a3F98N/ETH3Goy7IlXnLc6KOTk0k+17kBL5yG6YnLUlamXrXXAkg t3+UuU/xDRxeiEIbEbfnkduebPRq34wGmAOtzCjvpUfzUwIDAQABo0IwQDAPBgNVHRMBAf8EBTAD AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUo5fW816iEOGrRZ88F2Q87gFwnMwwDQYJKoZI hvcNAQELBQADggIBABj6W3X8PnrHX3fHyt/PX8MSxEBd1DKquGrX1RUVRpgjpeaQWxiZTOOtQqOC MTaIzen7xASWSIsBx40Bz1szBpZGZnQdT+3Btrm0DWHMY37XLneMlhwqI2hrhVd2cDMT/uFPpiN3 GPoajOi9ZcnPP/TJF9zrx7zABC4tRi9pZsMbj/7sPtPKlL92CiUNqXsCHKnQO18LwIE6PWThv6ct Tr1NxNgpxiIY0MWscgKCP6o6ojoilzHdCGPDdRS5YCgtW2jgFqlmgiNR9etT2DGbe+m3nUvriBbP +V04ikkwj+3x6xn0dxoxGE1nVGwvb2X52z3sIexe9PSLymBlVNFxZPT5pqOBMzYzcfCkeF9OrYMh 3jRJjehZrJ3ydlo28hP0r+AJx2EqbPfgna67hkooby7utHnNkDPDs3b69fBsnQGQ+p6Q9pxyz0fa wx/kNSBT8lTR32GDpgLiJTjehTItXnOQUl1CxM49S+H5GYQd1aJQzEH7QRTDvdbJWqNjZgKAvQU6 O0ec7AAmTPWIUb+oI38YB7AL7YsmoWTTYUrrXJ/es69nA7Mf3W1daWhpq1467HxpvMc7hU6eFbm0 FU/DlXpY18ls6Wy58yljXrQs8C097Vpl4KlbQMJImYFtnh8GKjwStIsPm6Ik8KaN1nrgS7ZklmOV hMJKzRwuJIczYOXD -----END CERTIFICATE----- QuoVadis Root CA 2 G3 ===================== -----BEGIN CERTIFICATE----- MIIFYDCCA0igAwIBAgIURFc0JFuBiZs18s64KztbpybwdSgwDQYJKoZIhvcNAQELBQAwSDELMAkG A1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAcBgNVBAMTFVF1b1ZhZGlzIFJv b3QgQ0EgMiBHMzAeFw0xMjAxMTIxODU5MzJaFw00MjAxMTIxODU5MzJaMEgxCzAJBgNVBAYTAkJN MRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDIg RzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQChriWyARjcV4g/Ruv5r+LrI3HimtFh ZiFfqq8nUeVuGxbULX1QsFN3vXg6YOJkApt8hpvWGo6t/x8Vf9WVHhLL5hSEBMHfNrMWn4rjyduY NM7YMxcoRvynyfDStNVNCXJJ+fKH46nafaF9a7I6JaltUkSs+L5u+9ymc5GQYaYDFCDy54ejiK2t oIz/pgslUiXnFgHVy7g1gQyjO/Dh4fxaXc6AcW34Sas+O7q414AB+6XrW7PFXmAqMaCvN+ggOp+o MiwMzAkd056OXbxMmO7FGmh77FOm6RQ1o9/NgJ8MSPsc9PG/Srj61YxxSscfrf5BmrODXfKEVu+l V0POKa2Mq1W/xPtbAd0jIaFYAI7D0GoT7RPjEiuA3GfmlbLNHiJuKvhB1PLKFAeNilUSxmn1uIZo L1NesNKqIcGY5jDjZ1XHm26sGahVpkUG0CM62+tlXSoREfA7T8pt9DTEceT/AFr2XK4jYIVz8eQQ sSWu1ZK7E8EM4DnatDlXtas1qnIhO4M15zHfeiFuuDIIfR0ykRVKYnLP43ehvNURG3YBZwjgQQvD 6xVu+KQZ2aKrr+InUlYrAoosFCT5v0ICvybIxo/gbjh9Uy3l7ZizlWNof/k19N+IxWA1ksB8aRxh lRbQ694Lrz4EEEVlWFA4r0jyWbYW8jwNkALGcC4BrTwV1wIDAQABo0IwQDAPBgNVHRMBAf8EBTAD AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQU7edvdlq/YOxJW8ald7tyFnGbxD0wDQYJKoZI hvcNAQELBQADggIBAJHfgD9DCX5xwvfrs4iP4VGyvD11+ShdyLyZm3tdquXK4Qr36LLTn91nMX66 AarHakE7kNQIXLJgapDwyM4DYvmL7ftuKtwGTTwpD4kWilhMSA/ohGHqPHKmd+RCroijQ1h5fq7K pVMNqT1wvSAZYaRsOPxDMuHBR//47PERIjKWnML2W2mWeyAMQ0GaW/ZZGYjeVYg3UQt4XAoeo0L9 x52ID8DyeAIkVJOviYeIyUqAHerQbj5hLja7NQ4nlv1mNDthcnPxFlxHBlRJAHpYErAK74X9sbgz dWqTHBLmYF5vHX/JHyPLhGGfHoJE+V+tYlUkmlKY7VHnoX6XOuYvHxHaU4AshZ6rNRDbIl9qxV6X U/IyAgkwo1jwDQHVcsaxfGl7w/U2Rcxhbl5MlMVerugOXou/983g7aEOGzPuVBj+D77vfoRrQ+Nw mNtddbINWQeFFSM51vHfqSYP1kjHs6Yi9TM3WpVHn3u6GBVv/9YUZINJ0gpnIdsPNWNgKCLjsZWD zYWm3S8P52dSbrsvhXz1SnPnxT7AvSESBT/8twNJAlvIJebiVDj1eYeMHVOyToV7BjjHLPj4sHKN JeV3UvQDHEimUF+IIDBu8oJDqz2XhOdT+yHBTw8imoa4WSr2Rz0ZiC3oheGe7IUIarFsNMkd7Egr O3jtZsSOeWmD3n+M -----END CERTIFICATE----- QuoVadis Root CA 3 G3 ===================== -----BEGIN CERTIFICATE----- MIIFYDCCA0igAwIBAgIULvWbAiin23r/1aOp7r0DoM8Sah0wDQYJKoZIhvcNAQELBQAwSDELMAkG A1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAcBgNVBAMTFVF1b1ZhZGlzIFJv b3QgQ0EgMyBHMzAeFw0xMjAxMTIyMDI2MzJaFw00MjAxMTIyMDI2MzJaMEgxCzAJBgNVBAYTAkJN MRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDMg RzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCzyw4QZ47qFJenMioKVjZ/aEzHs286 IxSR/xl/pcqs7rN2nXrpixurazHb+gtTTK/FpRp5PIpM/6zfJd5O2YIyC0TeytuMrKNuFoM7pmRL Mon7FhY4futD4tN0SsJiCnMK3UmzV9KwCoWdcTzeo8vAMvMBOSBDGzXRU7Ox7sWTaYI+FrUoRqHe 6okJ7UO4BUaKhvVZR74bbwEhELn9qdIoyhA5CcoTNs+cra1AdHkrAj80//ogaX3T7mH1urPnMNA3 I4ZyYUUpSFlob3emLoG+B01vr87ERRORFHAGjx+f+IdpsQ7vw4kZ6+ocYfx6bIrc1gMLnia6Et3U VDmrJqMz6nWB2i3ND0/kA9HvFZcba5DFApCTZgIhsUfei5pKgLlVj7WiL8DWM2fafsSntARE60f7 5li59wzweyuxwHApw0BiLTtIadwjPEjrewl5qW3aqDCYz4ByA4imW0aucnl8CAMhZa634RylsSqi Md5mBPfAdOhx3v89WcyWJhKLhZVXGqtrdQtEPREoPHtht+KPZ0/l7DxMYIBpVzgeAVuNVejH38DM dyM0SXV89pgR6y3e7UEuFAUCf+D+IOs15xGsIs5XPd7JMG0QA4XN8f+MFrXBsj6IbGB/kE+V9/Yt rQE5BwT6dYB9v0lQ7e/JxHwc64B+27bQ3RP+ydOc17KXqQIDAQABo0IwQDAPBgNVHRMBAf8EBTAD AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUxhfQvKjqAkPyGwaZXSuQILnXnOQwDQYJKoZI hvcNAQELBQADggIBADRh2Va1EodVTd2jNTFGu6QHcrxfYWLopfsLN7E8trP6KZ1/AvWkyaiTt3px KGmPc+FSkNrVvjrlt3ZqVoAh313m6Tqe5T72omnHKgqwGEfcIHB9UqM+WXzBusnIFUBhynLWcKzS t/Ac5IYp8M7vaGPQtSCKFWGafoaYtMnCdvvMujAWzKNhxnQT5WvvoxXqA/4Ti2Tk08HS6IT7SdEQ TXlm66r99I0xHnAUrdzeZxNMgRVhvLfZkXdxGYFgu/BYpbWcC/ePIlUnwEsBbTuZDdQdm2NnL9Du DcpmvJRPpq3t/O5jrFc/ZSXPsoaP0Aj/uHYUbt7lJ+yreLVTubY/6CD50qi+YUbKh4yE8/nxoGib Ih6BJpsQBJFxwAYf3KDTuVan45gtf4Od34wrnDKOMpTwATwiKp9Dwi7DmDkHOHv8XgBCH/MyJnmD hPbl8MFREsALHgQjDFSlTC9JxUrRtm5gDWv8a4uFJGS3iQ6rJUdbPM9+Sb3H6QrG2vd+DhcI00iX 0HGS8A85PjRqHH3Y8iKuu2n0M7SmSFXRDw4m6Oy2Cy2nhTXN/VnIn9HNPlopNLk9hM6xZdRZkZFW dSHBd575euFgndOtBBj0fOtek49TSiIp+EgrPk2GrFt/ywaZWWDYWGWVjUTR939+J399roD1B0y2 PpxxVJkES/1Y+Zj0 -----END CERTIFICATE----- DigiCert Assured ID Root G2 =========================== -----BEGIN CERTIFICATE----- MIIDljCCAn6gAwIBAgIQC5McOtY5Z+pnI7/Dr5r0SzANBgkqhkiG9w0BAQsFADBlMQswCQYDVQQG EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQw IgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIwHhcNMTMwODAxMTIwMDAwWhcNMzgw MTE1MTIwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQL ExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIw ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZ5ygvUj82ckmIkzTz+GoeMVSAn61UQbVH 35ao1K+ALbkKz3X9iaV9JPrjIgwrvJUXCzO/GU1BBpAAvQxNEP4HteccbiJVMWWXvdMX0h5i89vq bFCMP4QMls+3ywPgym2hFEwbid3tALBSfK+RbLE4E9HpEgjAALAcKxHad3A2m67OeYfcgnDmCXRw VWmvo2ifv922ebPynXApVfSr/5Vh88lAbx3RvpO704gqu52/clpWcTs/1PPRCv4o76Pu2ZmvA9OP YLfykqGxvYmJHzDNw6YuYjOuFgJ3RFrngQo8p0Quebg/BLxcoIfhG69Rjs3sLPr4/m3wOnyqi+Rn lTGNAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBTO w0q5mVXyuNtgv6l+vVa1lzan1jANBgkqhkiG9w0BAQsFAAOCAQEAyqVVjOPIQW5pJ6d1Ee88hjZv 0p3GeDgdaZaikmkuOGybfQTUiaWxMTeKySHMq2zNixya1r9I0jJmwYrA8y8678Dj1JGG0VDjA9tz d29KOVPt3ibHtX2vK0LRdWLjSisCx1BL4GnilmwORGYQRI+tBev4eaymG+g3NJ1TyWGqolKvSnAW hsI6yLETcDbYz+70CjTVW0z9B5yiutkBclzzTcHdDrEcDcRjvq30FPuJ7KJBDkzMyFdA0G4Dqs0M jomZmWzwPDCvON9vvKO+KSAnq3T/EyJ43pdSVR6DtVQgA+6uwE9W3jfMw3+qBCe703e4YtsXfJwo IhNzbM8m9Yop5w== -----END CERTIFICATE----- DigiCert Assured ID Root G3 =========================== -----BEGIN CERTIFICATE----- MIICRjCCAc2gAwIBAgIQC6Fa+h3foLVJRK/NJKBs7DAKBggqhkjOPQQDAzBlMQswCQYDVQQGEwJV UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQwIgYD VQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1 MTIwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwdjAQ BgcqhkjOPQIBBgUrgQQAIgNiAAQZ57ysRGXtzbg/WPuNsVepRC0FFfLvC/8QdJ+1YlJfZn4f5dwb RXkLzMZTCp2NXQLZqVneAlr2lSoOjThKiknGvMYDOAdfVdp+CW7if17QRSAPWXYQ1qAk8C3eNvJs KTmjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBTL0L2p4ZgF UaFNN6KDec6NHSrkhDAKBggqhkjOPQQDAwNnADBkAjAlpIFFAmsSS3V0T8gj43DydXLefInwz5Fy YZ5eEJJZVrmDxxDnOOlYJjZ91eQ0hjkCMHw2U/Aw5WJjOpnitqM7mzT6HtoQknFekROn3aRukswy 1vUhZscv6pZjamVFkpUBtA== -----END CERTIFICATE----- DigiCert Global Root G2 ======================= -----BEGIN CERTIFICATE----- MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBhMQswCQYDVQQG EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAw HgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUx MjAwMDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3 dy5kaWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkq hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI2/Ou8jqJ kTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx1x7e/dfgy5SDN67sH0NO 3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQq2EGnI/yuum06ZIya7XzV+hdG82MHauV BJVJ8zUtluNJbd134/tJS7SsVQepj5WztCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyM UNGPHgm+F6HmIcr9g+UQvIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQAB o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV5uNu 5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY1Yl9PMWLSn/pvtsr F9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4NeF22d+mQrvHRAiGfzZ0JFrabA0U WTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NGFdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBH QRFXGU7Aj64GxJUTFy8bJZ918rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/ iyK5S9kJRaTepLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl MrY= -----END CERTIFICATE----- DigiCert Global Root G3 ======================= -----BEGIN CERTIFICATE----- MIICPzCCAcWgAwIBAgIQBVVWvPJepDU1w6QP1atFcjAKBggqhkjOPQQDAzBhMQswCQYDVQQGEwJV UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAwHgYD VQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAw MDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5k aWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEczMHYwEAYHKoZIzj0C AQYFK4EEACIDYgAE3afZu4q4C/sLfyHS8L6+c/MzXRq8NOrexpu80JX28MzQC7phW1FGfp4tn+6O YwwX7Adw9c+ELkCDnOg/QW07rdOkFFk2eJ0DQ+4QE2xy3q6Ip6FrtUPOZ9wj/wMco+I+o0IwQDAP BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUs9tIpPmhxdiuNkHMEWNp Yim8S8YwCgYIKoZIzj0EAwMDaAAwZQIxAK288mw/EkrRLTnDCgmXc/SINoyIJ7vmiI1Qhadj+Z4y 3maTD/HMsQmP3Wyr+mt/oAIwOWZbwmSNuJ5Q3KjVSaLtx9zRSX8XAbjIho9OjIgrqJqpisXRAL34 VOKa5Vt8sycX -----END CERTIFICATE----- DigiCert Trusted Root G4 ======================== -----BEGIN CERTIFICATE----- MIIFkDCCA3igAwIBAgIQBZsbV56OITLiOQe9p3d1XDANBgkqhkiG9w0BAQwFADBiMQswCQYDVQQG EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSEw HwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1 MTIwMDAwWjBiMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwggIiMA0G CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz7MKnJS7JIT3yithZwuEp pz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS5F/WBTxSD1Ifxp4VpX6+n6lXFllVcq9o k3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7bXHiLQwb7iDVySAdYyktzuxeTsiT+CFhmzTrBcZe7Fsa vOvJz82sNEBfsXpm7nfISKhmV1efVFiODCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGY QJB5w3jHtrHEtWoYOAMQjdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14Ztk6 MUSaM0C/CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2h4mXaXpI8OCiEhtm mnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt6zPZxd9LBADMfRyVw4/3IbKyEbe7 f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPRiQfhvbfmQ6QYuKZ3AeEPlAwhHbJUKSWJbOUOUlFH dL4mrLZBdd56rF+NP8m800ERElvlEFDrMcXKchYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8 oR7FwI+isX4KJpn15GkvmB0t9dmpsh3lGwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1Ud DwEB/wQEAwIBhjAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wDQYJKoZIhvcNAQEMBQAD ggIBALth2X2pbL4XxJEbw6GiAI3jZGgPVs93rnD5/ZpKmbnJeFwMDF/k5hQpVgs2SV1EY+CtnJYY ZhsjDT156W1r1lT40jzBQ0CuHVD1UvyQO7uYmWlrx8GnqGikJ9yd+SeuMIW59mdNOj6PWTkiU0Tr yF0Dyu1Qen1iIQqAyHNm0aAFYF/opbSnr6j3bTWcfFqK1qI4mfN4i/RN0iAL3gTujJtHgXINwBQy 7zBZLq7gcfJW5GqXb5JQbZaNaHqasjYUegbyJLkJEVDXCLG4iXqEI2FCKeWjzaIgQdfRnGTZ6iah ixTXTBmyUEFxPT9NcCOGDErcgdLMMpSEDQgJlxxPwO5rIHQw0uA5NBCFIRUBCOhVMt5xSdkoF1BN 5r5N0XWs0Mr7QbhDparTwwVETyw2m+L64kW4I1NsBm9nVX9GtUw/bihaeSbSpKhil9Ie4u1Ki7wb /UdKDd9nZn6yW0HQO+T0O/QEY+nvwlQAUaCKKsnOeMzV6ocEGLPOr0mIr/OSmbaz5mEP0oUA51Aa 5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1/YldvIViHTLSoCtU7ZpXwdv6EM8Zt4tK G48BtieVU+i2iW1bvGjUI+iLUaJW+fCmgKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP 82Z+ -----END CERTIFICATE----- COMODO RSA Certification Authority ================================== -----BEGIN CERTIFICATE----- MIIF2DCCA8CgAwIBAgIQTKr5yttjb+Af907YWwOGnTANBgkqhkiG9w0BAQwFADCBhTELMAkGA1UE BhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgG A1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlv biBBdXRob3JpdHkwHhcNMTAwMTE5MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMC R0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UE ChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBB dXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCR6FSS0gpWsawNJN3Fz0Rn dJkrN6N9I3AAcbxT38T6KhKPS38QVr2fcHK3YX/JSw8Xpz3jsARh7v8Rl8f0hj4K+j5c+ZPmNHrZ FGvnnLOFoIJ6dq9xkNfs/Q36nGz637CC9BR++b7Epi9Pf5l/tfxnQ3K9DADWietrLNPtj5gcFKt+ 5eNu/Nio5JIk2kNrYrhV/erBvGy2i/MOjZrkm2xpmfh4SDBF1a3hDTxFYPwyllEnvGfDyi62a+pG x8cgoLEfZd5ICLqkTqnyg0Y3hOvozIFIQ2dOciqbXL1MGyiKXCJ7tKuY2e7gUYPDCUZObT6Z+pUX 2nwzV0E8jVHtC7ZcryxjGt9XyD+86V3Em69FmeKjWiS0uqlWPc9vqv9JWL7wqP/0uK3pN/u6uPQL OvnoQ0IeidiEyxPx2bvhiWC4jChWrBQdnArncevPDt09qZahSL0896+1DSJMwBGB7FY79tOi4lu3 sgQiUpWAk2nojkxl8ZEDLXB0AuqLZxUpaVICu9ffUGpVRr+goyhhf3DQw6KqLCGqR84onAZFdr+C GCe01a60y1Dma/RMhnEw6abfFobg2P9A3fvQQoh/ozM6LlweQRGBY84YcWsr7KaKtzFcOmpH4MN5 WdYgGq/yapiqcrxXStJLnbsQ/LBMQeXtHT1eKJ2czL+zUdqnR+WEUwIDAQABo0IwQDAdBgNVHQ4E FgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8w DQYJKoZIhvcNAQEMBQADggIBAArx1UaEt65Ru2yyTUEUAJNMnMvlwFTPoCWOAvn9sKIN9SCYPBMt rFaisNZ+EZLpLrqeLppysb0ZRGxhNaKatBYSaVqM4dc+pBroLwP0rmEdEBsqpIt6xf4FpuHA1sj+ nq6PK7o9mfjYcwlYRm6mnPTXJ9OV2jeDchzTc+CiR5kDOF3VSXkAKRzH7JsgHAckaVd4sjn8OoSg tZx8jb8uk2IntznaFxiuvTwJaP+EmzzV1gsD41eeFPfR60/IvYcjt7ZJQ3mFXLrrkguhxuhoqEwW sRqZCuhTLJK7oQkYdQxlqHvLI7cawiiFwxv/0Cti76R7CZGYZ4wUAc1oBmpjIXUDgIiKboHGhfKp pC3n9KUkEEeDys30jXlYsQab5xoq2Z0B15R97QNKyvDb6KkBPvVWmckejkk9u+UJueBPSZI9FoJA zMxZxuY67RIuaTxslbH9qh17f4a+Hg4yRvv7E491f0yLS0Zj/gA0QHDBw7mh3aZw4gSzQbzpgJHq ZJx64SIDqZxubw5lT2yHh17zbqD5daWbQOhTsiedSrnAdyGN/4fy3ryM7xfft0kL0fJuMAsaDk52 7RH89elWsn2/x20Kk4yl0MC2Hb46TpSi125sC8KKfPog88Tk5c0NqMuRkrF8hey1FGlmDoLnzc7I LaZRfyHBNVOFBkpdn627G190 -----END CERTIFICATE----- USERTrust RSA Certification Authority ===================================== -----BEGIN CERTIFICATE----- MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCBiDELMAkGA1UE BhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQK ExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNh dGlvbiBBdXRob3JpdHkwHhcNMTAwMjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UE BhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQK ExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNh dGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCAEmUXNg7D2wiz 0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2j Y0K2dvKpOyuR+OJv0OwWIJAJPuLodMkYtJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFn RghRy4YUVD+8M/5+bJz/Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O +T23LLb2VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT79uq /nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6c0Plfg6lZrEpfDKE Y1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmTYo61Zs8liM2EuLE/pDkP2QKe6xJM lXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97lc6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8 yexDJtC/QV9AqURE9JnnV4eeUB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+ eLf8ZxXhyVeEHg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd BgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF MAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPFUp/L+M+ZBn8b2kMVn54CVVeW FPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KOVWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ 7l8wXEskEVX/JJpuXior7gtNn3/3ATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQ Eg9zKC7F4iRO/Fjs8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM 8WcRiQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYzeSf7dNXGi FSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZXHlKYC6SQK5MNyosycdi yA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9c J2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRBVXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGw sAvgnEzDHNb842m1R0aBL6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gx Q+6IHdfGjjxDah2nGN59PRbxYvnKkKj9 -----END CERTIFICATE----- USERTrust ECC Certification Authority ===================================== -----BEGIN CERTIFICATE----- MIICjzCCAhWgAwIBAgIQXIuZxVqUxdJxVt7NiYDMJjAKBggqhkjOPQQDAzCBiDELMAkGA1UEBhMC VVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlv biBBdXRob3JpdHkwHhcNMTAwMjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMC VVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlv biBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQarFRaqfloI+d61SRvU8Za2EurxtW2 0eZzca7dnNYMYf3boIkDuAUU7FfO7l0/4iGzzvfUinngo4N+LZfQYcTxmdwlkWOrfzCjtHDix6Ez nPO/LlxTsV+zfTJ/ijTjeXmjQjBAMB0GA1UdDgQWBBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAOBgNV HQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjA2Z6EWCNzklwBB HU6+4WMBzzuqQhFkoJ2UOQIReVx7Hfpkue4WQrO/isIJxOzksU0CMQDpKmFHjFJKS04YcPbWRNZu 9YO6bVi9JNlWSOrvxKJGgYhqOkbRqZtNyWHa0V1Xahg= -----END CERTIFICATE----- GlobalSign ECC Root CA - R5 =========================== -----BEGIN CERTIFICATE----- MIICHjCCAaSgAwIBAgIRYFlJ4CYuu1X5CneKcflK2GwwCgYIKoZIzj0EAwMwUDEkMCIGA1UECxMb R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD EwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoXDTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMb R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD EwpHbG9iYWxTaWduMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAER0UOlvt9Xb/pOdEh+J8LttV7HpI6 SFkc8GIxLcB6KP4ap1yztsyX50XUWPrRd21DosCHZTQKH3rd6zwzocWdTaRvQZU4f8kehOvRnkmS h5SHDDqFSmafnVmTTZdhBoZKo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAd BgNVHQ4EFgQUPeYpSJvqB8ohREom3m7e0oPQn1kwCgYIKoZIzj0EAwMDaAAwZQIxAOVpEslu28Yx uglB4Zf4+/2a4n0Sye18ZNPLBSWLVtmg515dTguDnFt2KaAJJiFqYgIwcdK1j1zqO+F4CYWodZI7 yFz9SO8NdCKoCOJuxUnOxwy8p2Fp8fc74SrL+SvzZpA3 -----END CERTIFICATE----- IdenTrust Commercial Root CA 1 ============================== -----BEGIN CERTIFICATE----- MIIFYDCCA0igAwIBAgIQCgFCgAAAAUUjyES1AAAAAjANBgkqhkiG9w0BAQsFADBKMQswCQYDVQQG EwJVUzESMBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBS b290IENBIDEwHhcNMTQwMTE2MTgxMjIzWhcNMzQwMTE2MTgxMjIzWjBKMQswCQYDVQQGEwJVUzES MBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBSb290IENB IDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCnUBneP5k91DNG8W9RYYKyqU+PZ4ld hNlT3Qwo2dfw/66VQ3KZ+bVdfIrBQuExUHTRgQ18zZshq0PirK1ehm7zCYofWjK9ouuU+ehcCuz/ mNKvcbO0U59Oh++SvL3sTzIwiEsXXlfEU8L2ApeN2WIrvyQfYo3fw7gpS0l4PJNgiCL8mdo2yMKi 1CxUAGc1bnO/AljwpN3lsKImesrgNqUZFvX9t++uP0D1bVoE/c40yiTcdCMbXTMTEl3EASX2MN0C XZ/g1Ue9tOsbobtJSdifWwLziuQkkORiT0/Br4sOdBeo0XKIanoBScy0RnnGF7HamB4HWfp1IYVl 3ZBWzvurpWCdxJ35UrCLvYf5jysjCiN2O/cz4ckA82n5S6LgTrx+kzmEB/dEcH7+B1rlsazRGMzy NeVJSQjKVsk9+w8YfYs7wRPCTY/JTw436R+hDmrfYi7LNQZReSzIJTj0+kuniVyc0uMNOYZKdHzV WYfCP04MXFL0PfdSgvHqo6z9STQaKPNBiDoT7uje/5kdX7rL6B7yuVBgwDHTc+XvvqDtMwt0viAg xGds8AgDelWAf0ZOlqf0Hj7h9tgJ4TNkK2PXMl6f+cB7D3hvl7yTmvmcEpB4eoCHFddydJxVdHix uuFucAS6T6C6aMN7/zHwcz09lCqxC0EOoP5NiGVreTO01wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMC AQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU7UQZwNPwBovupHu+QucmVMiONnYwDQYJKoZI hvcNAQELBQADggIBAA2ukDL2pkt8RHYZYR4nKM1eVO8lvOMIkPkp165oCOGUAFjvLi5+U1KMtlwH 6oi6mYtQlNeCgN9hCQCTrQ0U5s7B8jeUeLBfnLOic7iPBZM4zY0+sLj7wM+x8uwtLRvM7Kqas6pg ghstO8OEPVeKlh6cdbjTMM1gCIOQ045U8U1mwF10A0Cj7oV+wh93nAbowacYXVKV7cndJZ5t+qnt ozo00Fl72u1Q8zW/7esUTTHHYPTa8Yec4kjixsU3+wYQ+nVZZjFHKdp2mhzpgq7vmrlR94gjmmmV YjzlVYA211QC//G5Xc7UI2/YRYRKW2XviQzdFKcgyxilJbQN+QHwotL0AMh0jqEqSI5l2xPE4iUX feu+h1sXIFRRk0pTAwvsXcoz7WL9RccvW9xYoIA55vrX/hMUpu09lEpCdNTDd1lzzY9GvlU47/ro kTLql1gEIt44w8y8bckzOmoKaT+gyOpyj4xjhiO9bTyWnpXgSUyqorkqG5w2gXjtw+hG4iZZRHUe 2XWJUc0QhJ1hYMtd+ZciTY6Y5uN/9lu7rs3KSoFrXgvzUeF0K+l+J6fZmUlO+KWA2yUPHGNiiskz Z2s8EIPGrd6ozRaOjfAHN3Gf8qv8QfXBi+wAN10J5U6A7/qxXDgGpRtK4dw4LTzcqx+QGtVKnO7R cGzM7vRX+Bi6hG6H -----END CERTIFICATE----- IdenTrust Public Sector Root CA 1 ================================= -----BEGIN CERTIFICATE----- MIIFZjCCA06gAwIBAgIQCgFCgAAAAUUjz0Z8AAAAAjANBgkqhkiG9w0BAQsFADBNMQswCQYDVQQG EwJVUzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVuVHJ1c3QgUHVibGljIFNlY3Rv ciBSb290IENBIDEwHhcNMTQwMTE2MTc1MzMyWhcNMzQwMTE2MTc1MzMyWjBNMQswCQYDVQQGEwJV UzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVuVHJ1c3QgUHVibGljIFNlY3RvciBS b290IENBIDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2IpT8pEiv6EdrCvsnduTy P4o7ekosMSqMjbCpwzFrqHd2hCa2rIFCDQjrVVi7evi8ZX3yoG2LqEfpYnYeEe4IFNGyRBb06tD6 Hi9e28tzQa68ALBKK0CyrOE7S8ItneShm+waOh7wCLPQ5CQ1B5+ctMlSbdsHyo+1W/CD80/HLaXI rcuVIKQxKFdYWuSNG5qrng0M8gozOSI5Cpcu81N3uURF/YTLNiCBWS2ab21ISGHKTN9T0a9SvESf qy9rg3LvdYDaBjMbXcjaY8ZNzaxmMc3R3j6HEDbhuaR672BQssvKplbgN6+rNBM5Jeg5ZuSYeqoS mJxZZoY+rfGwyj4GD3vwEUs3oERte8uojHH01bWRNszwFcYr3lEXsZdMUD2xlVl8BX0tIdUAvwFn ol57plzy9yLxkA2T26pEUWbMfXYD62qoKjgZl3YNa4ph+bz27nb9cCvdKTz4Ch5bQhyLVi9VGxyh LrXHFub4qjySjmm2AcG1hp2JDws4lFTo6tyePSW8Uybt1as5qsVATFSrsrTZ2fjXctscvG29ZV/v iDUqZi/u9rNl8DONfJhBaUYPQxxp+pu10GFqzcpL2UyQRqsVWaFHVCkugyhfHMKiq3IXAAaOReyL 4jM9f9oZRORicsPfIsbyVtTdX5Vy7W1f90gDW/3FKqD2cyOEEBsB5wIDAQABo0IwQDAOBgNVHQ8B Af8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU43HgntinQtnbcZFrlJPrw6PRFKMw DQYJKoZIhvcNAQELBQADggIBAEf63QqwEZE4rU1d9+UOl1QZgkiHVIyqZJnYWv6IAcVYpZmxI1Qj t2odIFflAWJBF9MJ23XLblSQdf4an4EKwt3X9wnQW3IV5B4Jaj0z8yGa5hV+rVHVDRDtfULAj+7A mgjVQdZcDiFpboBhDhXAuM/FSRJSzL46zNQuOAXeNf0fb7iAaJg9TaDKQGXSc3z1i9kKlT/YPyNt GtEqJBnZhbMX73huqVjRI9PHE+1yJX9dsXNw0H8GlwmEKYBhHfpe/3OsoOOJuBxxFcbeMX8S3OFt m6/n6J91eEyrRjuazr8FGF1NFTwWmhlQBJqymm9li1JfPFgEKCXAZmExfrngdbkaqIHWchezxQMx NRF4eKLg6TCMf4DfWN88uieW4oA0beOY02QnrEh+KHdcxiVhJfiFDGX6xDIvpZgF5PgLZxYWxoK4 Mhn5+bl53B/N66+rDt0b20XkeucC4pVd/GnwU2lhlXV5C15V5jgclKlZM57IcXR5f1GJtshquDDI ajjDbp7hNxbqBWJMWxJH7ae0s1hWx0nzfxJoCTFx8G34Tkf71oXuxVhAGaQdp/lLQzfcaFpPz+vC ZHTetBXZ9FRUGi8c15dxVJCO2SCdUyt/q4/i6jC8UDfv8Ue1fXwsBOxonbRJRBD0ckscZOf85muQ 3Wl9af0AVqW3rLatt8o+Ae+c -----END CERTIFICATE----- Entrust Root Certification Authority - G2 ========================================= -----BEGIN CERTIFICATE----- MIIEPjCCAyagAwIBAgIESlOMKDANBgkqhkiG9w0BAQsFADCBvjELMAkGA1UEBhMCVVMxFjAUBgNV BAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVy bXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ug b25seTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIw HhcNMDkwNzA3MTcyNTU0WhcNMzAxMjA3MTc1NTU0WjCBvjELMAkGA1UEBhMCVVMxFjAUBgNVBAoT DUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVybXMx OTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25s eTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIwggEi MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6hLZy254Ma+KZ6TABp3bqMriVQRrJ2mFOWHLP /vaCeb9zYQYKpSfYs1/TRU4cctZOMvJyig/3gxnQaoCAAEUesMfnmr8SVycco2gvCoe9amsOXmXz HHfV1IWNcCG0szLni6LVhjkCsbjSR87kyUnEO6fe+1R9V77w6G7CebI6C1XiUJgWMhNcL3hWwcKU s/Ja5CeanyTXxuzQmyWC48zCxEXFjJd6BmsqEZ+pCm5IO2/b1BEZQvePB7/1U1+cPvQXLOZprE4y TGJ36rfo5bs0vBmLrpxR57d+tVOxMyLlbc9wPBr64ptntoP0jaWvYkxN4FisZDQSA/i2jZRjJKRx AgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqciZ6 0B7vfec7aVHUbI2fkBJmqzANBgkqhkiG9w0BAQsFAAOCAQEAeZ8dlsa2eT8ijYfThwMEYGprmi5Z iXMRrEPR9RP/jTkrwPK9T3CMqS/qF8QLVJ7UG5aYMzyorWKiAHarWWluBh1+xLlEjZivEtRh2woZ Rkfz6/djwUAFQKXSt/S1mja/qYh2iARVBCuch38aNzx+LaUa2NSJXsq9rD1s2G2v1fN2D807iDgi nWyTmsQ9v4IbZT+mD12q/OWyFcq1rca8PdCE6OoGcrBNOTJ4vz4RnAuknZoh8/CbCzB428Hch0P+ vGOaysXCHMnHjf87ElgI5rY97HosTvuDls4MPGmHVHOkc8KT/1EQrBVUAdj8BbGJoX90g5pJ19xO e4pIb4tF9g== -----END CERTIFICATE----- Entrust Root Certification Authority - EC1 ========================================== -----BEGIN CERTIFICATE----- MIIC+TCCAoCgAwIBAgINAKaLeSkAAAAAUNCR+TAKBggqhkjOPQQDAzCBvzELMAkGA1UEBhMCVVMx FjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVn YWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDEyIEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXpl ZCB1c2Ugb25seTEzMDEGA1UEAxMqRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5 IC0gRUMxMB4XDTEyMTIxODE1MjUzNloXDTM3MTIxODE1NTUzNlowgb8xCzAJBgNVBAYTAlVTMRYw FAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3QubmV0L2xlZ2Fs LXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxMiBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhvcml6ZWQg dXNlIG9ubHkxMzAxBgNVBAMTKkVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAt IEVDMTB2MBAGByqGSM49AgEGBSuBBAAiA2IABIQTydC6bUF74mzQ61VfZgIaJPRbiWlH47jCffHy AsWfoPZb1YsGGYZPUxBtByQnoaD41UcZYUx9ypMn6nQM72+WCf5j7HBdNq1nd67JnXxVRDqiY1Ef 9eNi1KlHBz7MIKNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE FLdj5xrdjekIplWDpOBqUEFlEUJJMAoGCCqGSM49BAMDA2cAMGQCMGF52OVCR98crlOZF7ZvHH3h vxGU0QOIdeSNiaSKd0bebWHvAvX7td/M/k7//qnmpwIwW5nXhTcGtXsI/esni0qU+eH6p44mCOh8 kmhtc9hvJqwhAriZtyZBWyVgrtBIGu4G -----END CERTIFICATE----- CFCA EV ROOT ============ -----BEGIN CERTIFICATE----- MIIFjTCCA3WgAwIBAgIEGErM1jANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJDTjEwMC4GA1UE CgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRUwEwYDVQQDDAxDRkNB IEVWIFJPT1QwHhcNMTIwODA4MDMwNzAxWhcNMjkxMjMxMDMwNzAxWjBWMQswCQYDVQQGEwJDTjEw MC4GA1UECgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRUwEwYDVQQD DAxDRkNBIEVWIFJPT1QwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDXXWvNED8fBVnV BU03sQ7smCuOFR36k0sXgiFxEFLXUWRwFsJVaU2OFW2fvwwbwuCjZ9YMrM8irq93VCpLTIpTUnrD 7i7es3ElweldPe6hL6P3KjzJIx1qqx2hp/Hz7KDVRM8Vz3IvHWOX6Jn5/ZOkVIBMUtRSqy5J35DN uF++P96hyk0g1CXohClTt7GIH//62pCfCqktQT+x8Rgp7hZZLDRJGqgG16iI0gNyejLi6mhNbiyW ZXvKWfry4t3uMCz7zEasxGPrb382KzRzEpR/38wmnvFyXVBlWY9ps4deMm/DGIq1lY+wejfeWkU7 xzbh72fROdOXW3NiGUgthxwG+3SYIElz8AXSG7Ggo7cbcNOIabla1jj0Ytwli3i/+Oh+uFzJlU9f py25IGvPa931DfSCt/SyZi4QKPaXWnuWFo8BGS1sbn85WAZkgwGDg8NNkt0yxoekN+kWzqotaK8K gWU6cMGbrU1tVMoqLUuFG7OA5nBFDWteNfB/O7ic5ARwiRIlk9oKmSJgamNgTnYGmE69g60dWIol hdLHZR4tjsbftsbhf4oEIRUpdPA+nJCdDC7xij5aqgwJHsfVPKPtl8MeNPo4+QgO48BdK4PRVmrJ tqhUUy54Mmc9gn900PvhtgVguXDbjgv5E1hvcWAQUhC5wUEJ73IfZzF4/5YFjQIDAQABo2MwYTAf BgNVHSMEGDAWgBTj/i39KNALtbq2osS/BqoFjJP7LzAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB /wQEAwIBBjAdBgNVHQ4EFgQU4/4t/SjQC7W6tqLEvwaqBYyT+y8wDQYJKoZIhvcNAQELBQADggIB ACXGumvrh8vegjmWPfBEp2uEcwPenStPuiB/vHiyz5ewG5zz13ku9Ui20vsXiObTej/tUxPQ4i9q ecsAIyjmHjdXNYmEwnZPNDatZ8POQQaIxffu2Bq41gt/UP+TqhdLjOztUmCypAbqTuv0axn96/Ua 4CUqmtzHQTb3yHQFhDmVOdYLO6Qn+gjYXB74BGBSESgoA//vU2YApUo0FmZ8/Qmkrp5nGm9BC2sG E5uPhnEFtC+NiWYzKXZUmhH4J/qyP5Hgzg0b8zAarb8iXRvTvyUFTeGSGn+ZnzxEk8rUQElsgIfX BDrDMlI1Dlb4pd19xIsNER9Tyx6yF7Zod1rg1MvIB671Oi6ON7fQAUtDKXeMOZePglr4UeWJoBjn aH9dCi77o0cOPaYjesYBx4/IXr9tgFa+iiS6M+qf4TIRnvHST4D2G0CvOJ4RUHlzEhLN5mydLIhy PDCBBpEi6lmt2hkuIsKNuYyH4Ga8cyNfIWRjgEj1oDwYPZTISEEdQLpe/v5WOaHIz16eGWRGENoX kbcFgKyLmZJ956LYBws2J+dIeWCKw9cTXPhyQN9Ky8+ZAAoACxGV2lZFA4gKn2fQ1XmxqI1AbQ3C ekD6819kR5LLU7m7Wc5P/dAVUwHY3+vZ5nbv0CO7O6l5s9UCKc2Jo5YPSjXnTkLAdc0Hz+Ys63su -----END CERTIFICATE----- OISTE WISeKey Global Root GB CA =============================== -----BEGIN CERTIFICATE----- MIIDtTCCAp2gAwIBAgIQdrEgUnTwhYdGs/gjGvbCwDANBgkqhkiG9w0BAQsFADBtMQswCQYDVQQG EwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNl ZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwgUm9vdCBHQiBDQTAeFw0xNDEyMDExNTAw MzJaFw0zOTEyMDExNTEwMzFaMG0xCzAJBgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYD VQQLExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEds b2JhbCBSb290IEdCIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2Be3HEokKtaX scriHvt9OO+Y9bI5mE4nuBFde9IllIiCFSZqGzG7qFshISvYD06fWvGxWuR51jIjK+FTzJlFXHtP rby/h0oLS5daqPZI7H17Dc0hBt+eFf1Biki3IPShehtX1F1Q/7pn2COZH8g/497/b1t3sWtuuMlk 9+HKQUYOKXHQuSP8yYFfTvdv37+ErXNku7dCjmn21HYdfp2nuFeKUWdy19SouJVUQHMD9ur06/4o Qnc/nSMbsrY9gBQHTC5P99UKFg29ZkM3fiNDecNAhvVMKdqOmq0NpQSHiB6F4+lT1ZvIiwNjeOvg GUpuuy9rM2RYk61pv48b74JIxwIDAQABo1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB /zAdBgNVHQ4EFgQUNQ/INmNe4qPs+TtmFc5RUuORmj0wEAYJKwYBBAGCNxUBBAMCAQAwDQYJKoZI hvcNAQELBQADggEBAEBM+4eymYGQfp3FsLAmzYh7KzKNbrghcViXfa43FK8+5/ea4n32cZiZBKpD dHij40lhPnOMTZTg+XHEthYOU3gf1qKHLwI5gSk8rxWYITD+KJAAjNHhy/peyP34EEY7onhCkRd0 VQreUGdNZtGn//3ZwLWoo4rOZvUPQ82nK1d7Y0Zqqi5S2PTt4W2tKZB4SLrhI6qjiey1q5bAtEui HZeeevJuQHHfaPFlTc58Bd9TZaml8LGXBHAVRgOY1NK/VLSgWH1Sb9pWJmLU2NuJMW8c8CLC02Ic Nc1MaRVUGpCY3useX8p3x8uOPUNpnJpY0CQ73xtAln41rYHHTnG6iBM= -----END CERTIFICATE----- SZAFIR ROOT CA2 =============== -----BEGIN CERTIFICATE----- MIIDcjCCAlqgAwIBAgIUPopdB+xV0jLVt+O2XwHrLdzk1uQwDQYJKoZIhvcNAQELBQAwUTELMAkG A1UEBhMCUEwxKDAmBgNVBAoMH0tyYWpvd2EgSXpiYSBSb3psaWN6ZW5pb3dhIFMuQS4xGDAWBgNV BAMMD1NaQUZJUiBST09UIENBMjAeFw0xNTEwMTkwNzQzMzBaFw0zNTEwMTkwNzQzMzBaMFExCzAJ BgNVBAYTAlBMMSgwJgYDVQQKDB9LcmFqb3dhIEl6YmEgUm96bGljemVuaW93YSBTLkEuMRgwFgYD VQQDDA9TWkFGSVIgUk9PVCBDQTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC3vD5Q qEvNQLXOYeeWyrSh2gwisPq1e3YAd4wLz32ohswmUeQgPYUM1ljj5/QqGJ3a0a4m7utT3PSQ1hNK DJA8w/Ta0o4NkjrcsbH/ON7Dui1fgLkCvUqdGw+0w8LBZwPd3BucPbOw3gAeqDRHu5rr/gsUvTaE 2g0gv/pby6kWIK05YO4vdbbnl5z5Pv1+TW9NL++IDWr63fE9biCloBK0TXC5ztdyO4mTp4CEHCdJ ckm1/zuVnsHMyAHs6A6KCpbns6aH5db5BSsNl0BwPLqsdVqc1U2dAgrSS5tmS0YHF2Wtn2yIANwi ieDhZNRnvDF5YTy7ykHNXGoAyDw4jlivAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0P AQH/BAQDAgEGMB0GA1UdDgQWBBQuFqlKGLXLzPVvUPMjX/hd56zwyDANBgkqhkiG9w0BAQsFAAOC AQEAtXP4A9xZWx126aMqe5Aosk3AM0+qmrHUuOQn/6mWmc5G4G18TKI4pAZw8PRBEew/R40/cof5 O/2kbytTAOD/OblqBw7rHRz2onKQy4I9EYKL0rufKq8h5mOGnXkZ7/e7DDWQw4rtTw/1zBLZpD67 oPwglV9PJi8RI4NOdQcPv5vRtB3pEAT+ymCPoky4rc/hkA/NrgrHXXu3UNLUYfrVFdvXn4dRVOul 4+vJhaAlIDf7js4MNIThPIGyd05DpYhfhmehPea0XGG2Ptv+tyjFogeutcrKjSoS75ftwjCkySp6 +/NNIxuZMzSgLvWpCz/UXeHPhJ/iGcJfitYgHuNztw== -----END CERTIFICATE----- Certum Trusted Network CA 2 =========================== -----BEGIN CERTIFICATE----- MIIF0jCCA7qgAwIBAgIQIdbQSk8lD8kyN/yqXhKN6TANBgkqhkiG9w0BAQ0FADCBgDELMAkGA1UE BhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMuQS4xJzAlBgNVBAsTHkNlcnR1 bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEkMCIGA1UEAxMbQ2VydHVtIFRydXN0ZWQgTmV0d29y ayBDQSAyMCIYDzIwMTExMDA2MDgzOTU2WhgPMjA0NjEwMDYwODM5NTZaMIGAMQswCQYDVQQGEwJQ TDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENl cnRpZmljYXRpb24gQXV0aG9yaXR5MSQwIgYDVQQDExtDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENB IDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC9+Xj45tWADGSdhhuWZGc/IjoedQF9 7/tcZ4zJzFxrqZHmuULlIEub2pt7uZld2ZuAS9eEQCsn0+i6MLs+CRqnSZXvK0AkwpfHp+6bJe+o CgCXhVqqndwpyeI1B+twTUrWwbNWuKFBOJvR+zF/j+Bf4bE/D44WSWDXBo0Y+aomEKsq09DRZ40b Rr5HMNUuctHFY9rnY3lEfktjJImGLjQ/KUxSiyqnwOKRKIm5wFv5HdnnJ63/mgKXwcZQkpsCLL2p uTRZCr+ESv/f/rOf69me4Jgj7KZrdxYq28ytOxykh9xGc14ZYmhFV+SQgkK7QtbwYeDBoz1mo130 GO6IyY0XRSmZMnUCMe4pJshrAua1YkV/NxVaI2iJ1D7eTiew8EAMvE0Xy02isx7QBlrd9pPPV3WZ 9fqGGmd4s7+W/jTcvedSVuWz5XV710GRBdxdaeOVDUO5/IOWOZV7bIBaTxNyxtd9KXpEulKkKtVB Rgkg/iKgtlswjbyJDNXXcPiHUv3a76xRLgezTv7QCdpw75j6VuZt27VXS9zlLCUVyJ4ueE742pye hizKV/Ma5ciSixqClnrDvFASadgOWkaLOusm+iPJtrCBvkIApPjW/jAux9JG9uWOdf3yzLnQh1vM BhBgu4M1t15n3kfsmUjxpKEV/q2MYo45VU85FrmxY53/twIDAQABo0IwQDAPBgNVHRMBAf8EBTAD AQH/MB0GA1UdDgQWBBS2oVQ5AsOgP46KvPrU+Bym0ToO/TAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZI hvcNAQENBQADggIBAHGlDs7k6b8/ONWJWsQCYftMxRQXLYtPU2sQF/xlhMcQSZDe28cmk4gmb3DW Al45oPePq5a1pRNcgRRtDoGCERuKTsZPpd1iHkTfCVn0W3cLN+mLIMb4Ck4uWBzrM9DPhmDJ2vuA L55MYIR4PSFk1vtBHxgP58l1cb29XN40hz5BsA72udY/CROWFC/emh1auVbONTqwX3BNXuMp8SMo clm2q8KMZiYcdywmdjWLKKdpoPk79SPdhRB0yZADVpHnr7pH1BKXESLjokmUbOe3lEu6LaTaM4tM pkT/WjzGHWTYtTHkpjx6qFcL2+1hGsvxznN3Y6SHb0xRONbkX8eftoEq5IVIeVheO/jbAoJnwTnb w3RLPTYe+SmTiGhbqEQZIfCn6IENLOiTNrQ3ssqwGyZ6miUfmpqAnksqP/ujmv5zMnHCnsZy4Ypo J/HkD7TETKVhk/iXEAcqMCWpuchxuO9ozC1+9eB+D4Kob7a6bINDd82Kkhehnlt4Fj1F4jNy3eFm ypnTycUm/Q1oBEauttmbjL4ZvrHG8hnjXALKLNhvSgfZyTXaQHXyxKcZb55CEJh15pWLYLztxRLX is7VmFxWlgPF7ncGNf/P5O4/E2Hu29othfDNrp2yGAlFw5Khchf8R7agCyzxxN5DaAhqXzvwdmP7 zAYspsbiDrW5viSP -----END CERTIFICATE----- Hellenic Academic and Research Institutions RootCA 2015 ======================================================= -----BEGIN CERTIFICATE----- MIIGCzCCA/OgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBpjELMAkGA1UEBhMCR1IxDzANBgNVBAcT BkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0 aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNVBAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNl YXJjaCBJbnN0aXR1dGlvbnMgUm9vdENBIDIwMTUwHhcNMTUwNzA3MTAxMTIxWhcNNDAwNjMwMTAx MTIxWjCBpjELMAkGA1UEBhMCR1IxDzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMg QWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNV BAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgUm9vdENBIDIw MTUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDC+Kk/G4n8PDwEXT2QNrCROnk8Zlrv bTkBSRq0t89/TSNTt5AA4xMqKKYx8ZEA4yjsriFBzh/a/X0SWwGDD7mwX5nh8hKDgE0GPt+sr+eh iGsxr/CL0BgzuNtFajT0AoAkKAoCFZVedioNmToUW/bLy1O8E00BiDeUJRtCvCLYjqOWXjrZMts+ 6PAQZe104S+nfK8nNLspfZu2zwnI5dMK/IhlZXQK3HMcXM1AsRzUtoSMTFDPaI6oWa7CJ06CojXd FPQf/7J31Ycvqm59JCfnxssm5uX+Zwdj2EUN3TpZZTlYepKZcj2chF6IIbjV9Cz82XBST3i4vTwr i5WY9bPRaM8gFH5MXF/ni+X1NYEZN9cRCLdmvtNKzoNXADrDgfgXy5I2XdGj2HUb4Ysn6npIQf1F GQatJ5lOwXBH3bWfgVMS5bGMSF0xQxfjjMZ6Y5ZLKTBOhE5iGV48zpeQpX8B653g+IuJ3SWYPZK2 fu/Z8VFRfS0myGlZYeCsargqNhEEelC9MoS+L9xy1dcdFkfkR2YgP/SWxa+OAXqlD3pk9Q0Yh9mu iNX6hME6wGkoLfINaFGq46V3xqSQDqE3izEjR8EJCOtu93ib14L8hCCZSRm2Ekax+0VVFqmjZayc Bw/qa9wfLgZy7IaIEuQt218FL+TwA9MmM+eAws1CoRc0CwIDAQABo0IwQDAPBgNVHRMBAf8EBTAD AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUcRVnyMjJvXVdctA4GGqd83EkVAswDQYJKoZI hvcNAQELBQADggIBAHW7bVRLqhBYRjTyYtcWNl0IXtVsyIe9tC5G8jH4fOpCtZMWVdyhDBKg2mF+ D1hYc2Ryx+hFjtyp8iY/xnmMsVMIM4GwVhO+5lFc2JsKT0ucVlMC6U/2DWDqTUJV6HwbISHTGzrM d/K4kPFox/la/vot9L/J9UUbzjgQKjeKeaO04wlshYaT/4mWJ3iBj2fjRnRUjtkNaeJK9E10A/+y d+2VZ5fkscWrv2oj6NSU4kQoYsRL4vDY4ilrGnB+JGGTe08DMiUNRSQrlrRGar9KC/eaj8GsGsVn 82800vpzY4zvFrCopEYq+OsS7HK07/grfoxSwIuEVPkvPuNVqNxmsdnhX9izjFk0WaSrT2y7Hxjb davYy5LNlDhhDgcGH0tGEPEVvo2FXDtKK4F5D7Rpn0lQl033DlZdwJVqwjbDG2jJ9SrcR5q+ss7F Jej6A7na+RZukYT1HCjI/CbM1xyQVqdfbzoEvM14iQuODy+jqk+iGxI9FghAD/FGTNeqewjBCvVt J94Cj8rDtSvK6evIIVM4pcw72Hc3MKJP2W/R8kCtQXoXxdZKNYm3QdV8hn9VTYNKpXMgwDqvkPGa JI7ZjnHKe7iG2rKPmT4dEw0SEe7Uq/DpFXYC5ODfqiAeW2GFZECpkJcNrVPSWh2HagCXZWK0vm9q p/UsQu0yrbYhnr68 -----END CERTIFICATE----- Hellenic Academic and Research Institutions ECC RootCA 2015 =========================================================== -----BEGIN CERTIFICATE----- MIICwzCCAkqgAwIBAgIBADAKBggqhkjOPQQDAjCBqjELMAkGA1UEBhMCR1IxDzANBgNVBAcTBkF0 aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9u cyBDZXJ0LiBBdXRob3JpdHkxRDBCBgNVBAMTO0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJj aCBJbnN0aXR1dGlvbnMgRUNDIFJvb3RDQSAyMDE1MB4XDTE1MDcwNzEwMzcxMloXDTQwMDYzMDEw MzcxMlowgaoxCzAJBgNVBAYTAkdSMQ8wDQYDVQQHEwZBdGhlbnMxRDBCBgNVBAoTO0hlbGxlbmlj IEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9yaXR5MUQwQgYD VQQDEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25zIEVDQyBSb290 Q0EgMjAxNTB2MBAGByqGSM49AgEGBSuBBAAiA2IABJKgQehLgoRc4vgxEZmGZE4JJS+dQS8KrjVP dJWyUWRrjWvmP3CV8AVER6ZyOFB2lQJajq4onvktTpnvLEhvTCUp6NFxW98dwXU3tNf6e3pCnGoK Vlp8aQuqgAkkbH7BRqNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0O BBYEFLQiC4KZJAEOnLvkDv2/+5cgk5kqMAoGCCqGSM49BAMCA2cAMGQCMGfOFmI4oqxiRaeplSTA GiecMjvAwNW6qef4BENThe5SId6d9SWDPp5YSy/XZxMOIQIwBeF1Ad5o7SofTUwJCA3sS61kFyjn dc5FZXIhF8siQQ6ME5g4mlRtm8rifOoCWCKR -----END CERTIFICATE----- ISRG Root X1 ============ -----BEGIN CERTIFICATE----- MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAwTzELMAkGA1UE BhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2VhcmNoIEdyb3VwMRUwEwYDVQQD EwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQG EwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMT DElTUkcgUm9vdCBYMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54r Vygch77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+0TM8ukj1 3Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6UA5/TR5d8mUgjU+g4rk8K b4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sWT8KOEUt+zwvo/7V3LvSye0rgTBIlDHCN Aymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyHB5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ 4Q7e2RCOFvu396j3x+UCB5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf 1b0SHzUvKBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWnOlFu hjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTnjh8BCNAw1FtxNrQH usEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbwqHyGO0aoSCqI3Haadr8faqU9GY/r OPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CIrU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4G A1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY 9umbbjANBgkqhkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ3BebYhtF8GaV 0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KKNFtY2PwByVS5uCbMiogziUwt hDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJw TdwJx4nLCgdNbOhdjsnvzqvHu7UrTkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nx e5AW0wdeRlN8NwdCjNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZA JzVcoyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq4RgqsahD YVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPAmRGunUHBcnWEvgJBQl9n JEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57demyPxgcYxn/eR44/KJ4EBs+lVDR3veyJ m+kXQ99b21/+jh5Xos1AnX5iItreGCc= -----END CERTIFICATE----- AC RAIZ FNMT-RCM ================ -----BEGIN CERTIFICATE----- MIIFgzCCA2ugAwIBAgIPXZONMGc2yAYdGsdUhGkHMA0GCSqGSIb3DQEBCwUAMDsxCzAJBgNVBAYT AkVTMREwDwYDVQQKDAhGTk1ULVJDTTEZMBcGA1UECwwQQUMgUkFJWiBGTk1ULVJDTTAeFw0wODEw MjkxNTU5NTZaFw0zMDAxMDEwMDAwMDBaMDsxCzAJBgNVBAYTAkVTMREwDwYDVQQKDAhGTk1ULVJD TTEZMBcGA1UECwwQQUMgUkFJWiBGTk1ULVJDTTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC ggIBALpxgHpMhm5/yBNtwMZ9HACXjywMI7sQmkCpGreHiPibVmr75nuOi5KOpyVdWRHbNi63URcf qQgfBBckWKo3Shjf5TnUV/3XwSyRAZHiItQDwFj8d0fsjz50Q7qsNI1NOHZnjrDIbzAzWHFctPVr btQBULgTfmxKo0nRIBnuvMApGGWn3v7v3QqQIecaZ5JCEJhfTzC8PhxFtBDXaEAUwED653cXeuYL j2VbPNmaUtu1vZ5Gzz3rkQUCwJaydkxNEJY7kvqcfw+Z374jNUUeAlz+taibmSXaXvMiwzn15Cou 08YfxGyqxRxqAQVKL9LFwag0Jl1mpdICIfkYtwb1TplvqKtMUejPUBjFd8g5CSxJkjKZqLsXF3mw WsXmo8RZZUc1g16p6DULmbvkzSDGm0oGObVo/CK67lWMK07q87Hj/LaZmtVC+nFNCM+HHmpxffnT tOmlcYF7wk5HlqX2doWjKI/pgG6BU6VtX7hI+cL5NqYuSf+4lsKMB7ObiFj86xsc3i1w4peSMKGJ 47xVqCfWS+2QrYv6YyVZLag13cqXM7zlzced0ezvXg5KkAYmY6252TUtB7p2ZSysV4999AeU14EC ll2jB0nVetBX+RvnU0Z1qrB5QstocQjpYL05ac70r8NWQMetUqIJ5G+GR4of6ygnXYMgrwTJbFaa i0b1AgMBAAGjgYMwgYAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE FPd9xf3E6Jobd2Sn9R2gzL+HYJptMD4GA1UdIAQ3MDUwMwYEVR0gADArMCkGCCsGAQUFBwIBFh1o dHRwOi8vd3d3LmNlcnQuZm5tdC5lcy9kcGNzLzANBgkqhkiG9w0BAQsFAAOCAgEAB5BK3/MjTvDD nFFlm5wioooMhfNzKWtN/gHiqQxjAb8EZ6WdmF/9ARP67Jpi6Yb+tmLSbkyU+8B1RXxlDPiyN8+s D8+Nb/kZ94/sHvJwnvDKuO+3/3Y3dlv2bojzr2IyIpMNOmqOFGYMLVN0V2Ue1bLdI4E7pWYjJ2cJ j+F3qkPNZVEI7VFY/uY5+ctHhKQV8Xa7pO6kO8Rf77IzlhEYt8llvhjho6Tc+hj507wTmzl6NLrT Qfv6MooqtyuGC2mDOL7Nii4LcK2NJpLuHvUBKwrZ1pebbuCoGRw6IYsMHkCtA+fdZn71uSANA+iW +YJF1DngoABd15jmfZ5nc8OaKveri6E6FO80vFIOiZiaBECEHX5FaZNXzuvO+FB8TxxuBEOb+dY7 Ixjp6o7RTUaN8Tvkasq6+yO3m/qZASlaWFot4/nUbQ4mrcFuNLwy+AwF+mWj2zs3gyLp1txyM/1d 8iC9djwj2ij3+RvrWWTV3F9yfiD8zYm1kGdNYno/Tq0dwzn+evQoFt9B9kiABdcPUXmsEKvU7ANm 5mqwujGSQkBqvjrTcuFqN1W8rB2Vt2lh8kORdOag0wokRqEIr9baRRmW1FMdW4R58MD3R++Lj8UG rp1MYp3/RgT408m2ECVAdf4WqslKYIYvuu8wd+RU4riEmViAqhOLUTpPSPaLtrM= -----END CERTIFICATE----- Amazon Root CA 1 ================ -----BEGIN CERTIFICATE----- MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsFADA5MQswCQYD VQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAxMB4XDTE1 MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpv bjEZMBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC ggEBALJ4gHHKeNXjca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgH FzZM9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qwIFAGbHrQ gLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6VOujw5H5SNz/0egwLX0t dHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L93FcXmn/6pUCyziKrlA4b9v7LWIbxcce VOF34GfID5yHI9Y/QCB/IIDEgEw+OyQmjgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB /zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3 DQEBCwUAA4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDIU5PM CCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUsN+gDS63pYaACbvXy 8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vvo/ufQJVtMVT8QtPHRh8jrdkPSHCa 2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2 xJNDd2ZhwLnoQdeXeGADbkpyrqXRfboQnoZsG4q5WTP468SQvvG5 -----END CERTIFICATE----- Amazon Root CA 2 ================ -----BEGIN CERTIFICATE----- MIIFQTCCAymgAwIBAgITBmyf0pY1hp8KD+WGePhbJruKNzANBgkqhkiG9w0BAQwFADA5MQswCQYD VQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAyMB4XDTE1 MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpv bjEZMBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC ggIBAK2Wny2cSkxKgXlRmeyKy2tgURO8TW0G/LAIjd0ZEGrHJgw12MBvIITplLGbhQPDW9tK6Mj4 kHbZW0/jTOgGNk3Mmqw9DJArktQGGWCsN0R5hYGCrVo34A3MnaZMUnbqQ523BNFQ9lXg1dKmSYXp N+nKfq5clU1Imj+uIFptiJXZNLhSGkOQsL9sBbm2eLfq0OQ6PBJTYv9K8nu+NQWpEjTj82R0Yiw9 AElaKP4yRLuH3WUnAnE72kr3H9rN9yFVkE8P7K6C4Z9r2UXTu/Bfh+08LDmG2j/e7HJV63mjrdvd fLC6HM783k81ds8P+HgfajZRRidhW+mez/CiVX18JYpvL7TFz4QuK/0NURBs+18bvBt+xa47mAEx kv8LV/SasrlX6avvDXbR8O70zoan4G7ptGmh32n2M8ZpLpcTnqWHsFcQgTfJU7O7f/aS0ZzQGPSS btqDT6ZjmUyl+17vIWR6IF9sZIUVyzfpYgwLKhbcAS4y2j5L9Z469hdAlO+ekQiG+r5jqFoz7Mt0 Q5X5bGlSNscpb/xVA1wf+5+9R+vnSUeVC06JIglJ4PVhHvG/LopyboBZ/1c6+XUyo05f7O0oYtlN c/LMgRdg7c3r3NunysV+Ar3yVAhU/bQtCSwXVEqY0VThUWcI0u1ufm8/0i2BWSlmy5A5lREedCf+ 3euvAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSw DPBMMPQFWAJI/TPlUq9LhONmUjANBgkqhkiG9w0BAQwFAAOCAgEAqqiAjw54o+Ci1M3m9Zh6O+oA A7CXDpO8Wqj2LIxyh6mx/H9z/WNxeKWHWc8w4Q0QshNabYL1auaAn6AFC2jkR2vHat+2/XcycuUY +gn0oJMsXdKMdYV2ZZAMA3m3MSNjrXiDCYZohMr/+c8mmpJ5581LxedhpxfL86kSk5Nrp+gvU5LE YFiwzAJRGFuFjWJZY7attN6a+yb3ACfAXVU3dJnJUH/jWS5E4ywl7uxMMne0nxrpS10gxdr9HIcW xkPo1LsmmkVwXqkLN1PiRnsn/eBG8om3zEK2yygmbtmlyTrIQRNg91CMFa6ybRoVGld45pIq2WWQ gj9sAq+uEjonljYE1x2igGOpm/HlurR8FLBOybEfdF849lHqm/osohHUqS0nGkWxr7JOcQ3AWEbW aQbLU8uz/mtBzUF+fUwPfHJ5elnNXkoOrJupmHN5fLT0zLm4BwyydFy4x2+IoZCn9Kr5v2c69BoV Yh63n749sSmvZ6ES8lgQGVMDMBu4Gon2nL2XA46jCfMdiyHxtN/kHNGfZQIG6lzWE7OE76KlXIx3 KadowGuuQNKotOrN8I1LOJwZmhsoVLiJkO/KdYE+HvJkJMcYr07/R54H9jVlpNMKVv/1F2Rs76gi JUmTtt8AF9pYfl3uxRuw0dFfIRDH+fO6AgonB8Xx1sfT4PsJYGw= -----END CERTIFICATE----- Amazon Root CA 3 ================ -----BEGIN CERTIFICATE----- MIIBtjCCAVugAwIBAgITBmyf1XSXNmY/Owua2eiedgPySjAKBggqhkjOPQQDAjA5MQswCQYDVQQG EwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAzMB4XDTE1MDUy NjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZ MBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCmXp8ZB f8ANm+gBG1bG8lKlui2yEujSLtf6ycXYqm0fc4E7O5hrOXwzpcVOho6AF2hiRVd9RFgdszflZwjr Zt6jQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSrttvXBp43 rDCGB5Fwx5zEGbF4wDAKBggqhkjOPQQDAgNJADBGAiEA4IWSoxe3jfkrBqWTrBqYaGFy+uGh0Psc eGCmQ5nFuMQCIQCcAu/xlJyzlvnrxir4tiz+OpAUFteMYyRIHN8wfdVoOw== -----END CERTIFICATE----- Amazon Root CA 4 ================ -----BEGIN CERTIFICATE----- MIIB8jCCAXigAwIBAgITBmyf18G7EEwpQ+Vxe3ssyBrBDjAKBggqhkjOPQQDAzA5MQswCQYDVQQG EwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSA0MB4XDTE1MDUy NjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZ MBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgNDB2MBAGByqGSM49AgEGBSuBBAAiA2IABNKrijdPo1MN /sGKe0uoe0ZLY7Bi9i0b2whxIdIA6GO9mif78DluXeo9pcmBqqNbIJhFXRbb/egQbeOc4OO9X4Ri 83BkM6DLJC9wuoihKqB1+IGuYgbEgds5bimwHvouXKNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV HQ8BAf8EBAMCAYYwHQYDVR0OBBYEFNPsxzplbszh2naaVvuc84ZtV+WBMAoGCCqGSM49BAMDA2gA MGUCMDqLIfG9fhGt0O9Yli/W651+kI0rz2ZVwyzjKKlwCkcO8DdZEv8tmZQoTipPNU0zWgIxAOp1 AE47xDqUEpHJWEadIRNyp4iciuRMStuW1KyLa2tJElMzrdfkviT8tQp21KW8EA== -----END CERTIFICATE----- TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1 ============================================= -----BEGIN CERTIFICATE----- MIIEYzCCA0ugAwIBAgIBATANBgkqhkiG9w0BAQsFADCB0jELMAkGA1UEBhMCVFIxGDAWBgNVBAcT D0dlYnplIC0gS29jYWVsaTFCMEAGA1UEChM5VHVya2l5ZSBCaWxpbXNlbCB2ZSBUZWtub2xvamlr IEFyYXN0aXJtYSBLdXJ1bXUgLSBUVUJJVEFLMS0wKwYDVQQLEyRLYW11IFNlcnRpZmlrYXN5b24g TWVya2V6aSAtIEthbXUgU00xNjA0BgNVBAMTLVRVQklUQUsgS2FtdSBTTSBTU0wgS29rIFNlcnRp ZmlrYXNpIC0gU3VydW0gMTAeFw0xMzExMjUwODI1NTVaFw00MzEwMjUwODI1NTVaMIHSMQswCQYD VQQGEwJUUjEYMBYGA1UEBxMPR2ViemUgLSBLb2NhZWxpMUIwQAYDVQQKEzlUdXJraXllIEJpbGlt c2VsIHZlIFRla25vbG9qaWsgQXJhc3Rpcm1hIEt1cnVtdSAtIFRVQklUQUsxLTArBgNVBAsTJEth bXUgU2VydGlmaWthc3lvbiBNZXJrZXppIC0gS2FtdSBTTTE2MDQGA1UEAxMtVFVCSVRBSyBLYW11 IFNNIFNTTCBLb2sgU2VydGlmaWthc2kgLSBTdXJ1bSAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A MIIBCgKCAQEAr3UwM6q7a9OZLBI3hNmNe5eA027n/5tQlT6QlVZC1xl8JoSNkvoBHToP4mQ4t4y8 6Ij5iySrLqP1N+RAjhgleYN1Hzv/bKjFxlb4tO2KRKOrbEz8HdDc72i9z+SqzvBV96I01INrN3wc wv61A+xXzry0tcXtAA9TNypN9E8Mg/uGz8v+jE69h/mniyFXnHrfA2eJLJ2XYacQuFWQfw4tJzh0 3+f92k4S400VIgLI4OD8D62K18lUUMw7D8oWgITQUVbDjlZ/iSIzL+aFCr2lqBs23tPcLG07xxO9 WSMs5uWk99gL7eqQQESolbuT1dCANLZGeA4fAJNG4e7p+exPFwIDAQABo0IwQDAdBgNVHQ4EFgQU ZT/HiobGPN08VFw1+DrtUgxHV8gwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJ KoZIhvcNAQELBQADggEBACo/4fEyjq7hmFxLXs9rHmoJ0iKpEsdeV31zVmSAhHqT5Am5EM2fKifh AHe+SMg1qIGf5LgsyX8OsNJLN13qudULXjS99HMpw+0mFZx+CFOKWI3QSyjfwbPfIPP54+M638yc lNhOT8NrF7f3cuitZjO1JVOr4PhMqZ398g26rrnZqsZr+ZO7rqu4lzwDGrpDxpa5RXI4s6ehlj2R e37AIVNMh+3yC1SVUZPVIqUNivGTDj5UDrDYyU7c8jEyVupk+eq1nRZmQnLzf9OxMUP8pI4X8W0j q5Rm+K37DwhuJi1/FwcJsoz7UMCflo3Ptv0AnVoUmr8CRPXBwp8iXqIPoeM= -----END CERTIFICATE----- GDCA TrustAUTH R5 ROOT ====================== -----BEGIN CERTIFICATE----- MIIFiDCCA3CgAwIBAgIIfQmX/vBH6nowDQYJKoZIhvcNAQELBQAwYjELMAkGA1UEBhMCQ04xMjAw BgNVBAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZIENPLixMVEQuMR8wHQYDVQQD DBZHRENBIFRydXN0QVVUSCBSNSBST09UMB4XDTE0MTEyNjA1MTMxNVoXDTQwMTIzMTE1NTk1OVow YjELMAkGA1UEBhMCQ04xMjAwBgNVBAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZ IENPLixMVEQuMR8wHQYDVQQDDBZHRENBIFRydXN0QVVUSCBSNSBST09UMIICIjANBgkqhkiG9w0B AQEFAAOCAg8AMIICCgKCAgEA2aMW8Mh0dHeb7zMNOwZ+Vfy1YI92hhJCfVZmPoiC7XJjDp6L3TQs AlFRwxn9WVSEyfFrs0yw6ehGXTjGoqcuEVe6ghWinI9tsJlKCvLriXBjTnnEt1u9ol2x8kECK62p OqPseQrsXzrj/e+APK00mxqriCZ7VqKChh/rNYmDf1+uKU49tm7srsHwJ5uu4/Ts765/94Y9cnrr pftZTqfrlYwiOXnhLQiPzLyRuEH3FMEjqcOtmkVEs7LXLM3GKeJQEK5cy4KOFxg2fZfmiJqwTTQJ 9Cy5WmYqsBebnh52nUpmMUHfP/vFBu8btn4aRjb3ZGM74zkYI+dndRTVdVeSN72+ahsmUPI2JgaQ xXABZG12ZuGR224HwGGALrIuL4xwp9E7PLOR5G62xDtw8mySlwnNR30YwPO7ng/Wi64HtloPzgsM R6flPri9fcebNaBhlzpBdRfMK5Z3KpIhHtmVdiBnaM8Nvd/WHwlqmuLMc3GkL30SgLdTMEZeS1SZ D2fJpcjyIMGC7J0R38IC+xo70e0gmu9lZJIQDSri3nDxGGeCjGHeuLzRL5z7D9Ar7Rt2ueQ5Vfj4 oR24qoAATILnsn8JuLwwoC8N9VKejveSswoAHQBUlwbgsQfZxw9cZX08bVlX5O2ljelAU58VS6Bx 9hoh49pwBiFYFIeFd3mqgnkCAwEAAaNCMEAwHQYDVR0OBBYEFOLJQJ9NzuiaoXzPDj9lxSmIahlR MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQDRSVfg p8xoWLoBDysZzY2wYUWsEe1jUGn4H3++Fo/9nesLqjJHdtJnJO29fDMylyrHBYZmDRd9FBUb1Ov9 H5r2XpdptxolpAqzkT9fNqyL7FeoPueBihhXOYV0GkLH6VsTX4/5COmSdI31R9KrO9b7eGZONn35 6ZLpBN79SWP8bfsUcZNnL0dKt7n/HipzcEYwv1ryL3ml4Y0M2fmyYzeMN2WFcGpcWwlyua1jPLHd +PwyvzeG5LuOmCd+uh8W4XAR8gPfJWIyJyYYMoSf/wA6E7qaTfRPuBRwIrHKK5DOKcFw9C+df/KQ HtZa37dG/OaG+svgIHZ6uqbL9XzeYqWxi+7egmaKTjowHz+Ay60nugxe19CxVsp3cbK1daFQqUBD F8Io2c9Si1vIY9RCPqAzekYu9wogRlR+ak8x8YF+QnQ4ZXMn7sZ8uI7XpTrXmKGcjBBV09tL7ECQ 8s1uV9JiDnxXk7Gnbc2dg7sq5+W2O3FYrf3RRbxake5TFW/TRQl1brqQXR4EzzffHqhmsYzmIGrv /EhOdJhCrylvLmrH+33RZjEizIYAfmaDDEL0vTSSwxrqT8p+ck0LcIymSLumoRT2+1hEmRSuqguT aaApJUqlyyvdimYHFngVV3Eb7PVHhPOeMTd61X8kreS8/f3MboPoDKi3QWwH3b08hpcv0g== -----END CERTIFICATE----- SSL.com Root Certification Authority RSA ======================================== -----BEGIN CERTIFICATE----- MIIF3TCCA8WgAwIBAgIIeyyb0xaAMpkwDQYJKoZIhvcNAQELBQAwfDELMAkGA1UEBhMCVVMxDjAM BgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9TU0wgQ29ycG9yYXRpb24x MTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBSU0EwHhcNMTYw MjEyMTczOTM5WhcNNDEwMjEyMTczOTM5WjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMx EDAOBgNVBAcMB0hvdXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NM LmNvbSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFJTQTCCAiIwDQYJKoZIhvcNAQEBBQAD ggIPADCCAgoCggIBAPkP3aMrfcvQKv7sZ4Wm5y4bunfh4/WvpOz6Sl2RxFdHaxh3a3by/ZPkPQ/C Fp4LZsNWlJ4Xg4XOVu/yFv0AYvUiCVToZRdOQbngT0aXqhvIuG5iXmmxX9sqAn78bMrzQdjt0Oj8 P2FI7bADFB0QDksZ4LtO7IZl/zbzXmcCC52GVWH9ejjt/uIZALdvoVBidXQ8oPrIJZK0bnoix/ge oeOy3ZExqysdBP+lSgQ36YWkMyv94tZVNHwZpEpox7Ko07fKoZOI68GXvIz5HdkihCR0xwQ9aqkp k8zruFvh/l8lqjRYyMEjVJ0bmBHDOJx+PYZspQ9AhnwC9FwCTyjLrnGfDzrIM/4RJTXq/LrFYD3Z fBjVsqnTdXgDciLKOsMf7yzlLqn6niy2UUb9rwPW6mBo6oUWNmuF6R7As93EJNyAKoFBbZQ+yODJ gUEAnl6/f8UImKIYLEJAs/lvOCdLToD0PYFH4Ih86hzOtXVcUS4cK38acijnALXRdMbX5J+tB5O2 UzU1/Dfkw/ZdFr4hc96SCvigY2q8lpJqPvi8ZVWb3vUNiSYE/CUapiVpy8JtynziWV+XrOvvLsi8 1xtZPCvM8hnIk2snYxnP/Okm+Mpxm3+T/jRnhE6Z6/yzeAkzcLpmpnbtG3PrGqUNxCITIJRWCk4s bE6x/c+cCbqiM+2HAgMBAAGjYzBhMB0GA1UdDgQWBBTdBAkHovV6fVJTEpKV7jiAJQ2mWTAPBgNV HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFN0ECQei9Xp9UlMSkpXuOIAlDaZZMA4GA1UdDwEB/wQE AwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAIBgRlCn7Jp0cHh5wYfGVcpNxJK1ok1iOMq8bs3AD/CUr dIWQPXhq9LmLpZc7tRiRux6n+UBbkflVma8eEdBcHadm47GUBwwyOabqG7B52B2ccETjit3E+ZUf ijhDPwGFpUenPUayvOUiaPd7nNgsPgohyC0zrL/FgZkxdMF1ccW+sfAjRfSda/wZY52jvATGGAsl u1OJD7OAUN5F7kR/q5R4ZJjT9ijdh9hwZXT7DrkT66cPYakylszeu+1jTBi7qUD3oFRuIIhxdRjq erQ0cuAjJ3dctpDqhiVAq+8zD8ufgr6iIPv2tS0a5sKFsXQP+8hlAqRSAUfdSSLBv9jra6x+3uxj MxW3IwiPxg+NQVrdjsW5j+VFP3jbutIbQLH+cU0/4IGiul607BXgk90IH37hVZkLId6Tngr75qNJ vTYw/ud3sqB1l7UtgYgXZSD32pAAn8lSzDLKNXz1PQ/YK9f1JmzJBjSWFupwWRoyeXkLtoh/D1JI Pb9s2KJELtFOt3JY04kTlf5Eq/jXixtunLwsoFvVagCvXzfh1foQC5ichucmj87w7G6KVwuA406y wKBjYZC6VWg3dGq2ktufoYYitmUnDuy2n0Jg5GfCtdpBC8TTi2EbvPofkSvXRAdeuims2cXp71NI WuuA8ShYIc2wBlX7Jz9TkHCpBB5XJ7k= -----END CERTIFICATE----- SSL.com Root Certification Authority ECC ======================================== -----BEGIN CERTIFICATE----- MIICjTCCAhSgAwIBAgIIdebfy8FoW6gwCgYIKoZIzj0EAwIwfDELMAkGA1UEBhMCVVMxDjAMBgNV BAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9TU0wgQ29ycG9yYXRpb24xMTAv BgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYwMjEy MTgxNDAzWhcNNDEwMjEyMTgxNDAzWjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAO BgNVBAcMB0hvdXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNv bSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49AgEGBSuBBAAiA2IA BEVuqVDEpiM2nl8ojRfLliJkP9x6jh3MCLOicSS6jkm5BBtHllirLZXI7Z4INcgn64mMU1jrYor+ 8FsPazFSY0E7ic3s7LaNGdM0B9y7xgZ/wkWV7Mt/qCPgCemB+vNH06NjMGEwHQYDVR0OBBYEFILR hXMw5zUE044CkvvlpNHEIejNMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUgtGFczDnNQTT jgKS++Wk0cQh6M0wDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2cAMGQCMG/n61kRpGDPYbCW e+0F+S8Tkdzt5fxQaxFGRrMcIQBiu77D5+jNB5n5DQtdcj7EqgIwH7y6C+IwJPt8bYBVCpk+gA0z 5Wajs6O7pdWLjwkspl1+4vAHCGht0nxpbl/f5Wpl -----END CERTIFICATE----- SSL.com EV Root Certification Authority RSA R2 ============================================== -----BEGIN CERTIFICATE----- MIIF6zCCA9OgAwIBAgIIVrYpzTS8ePYwDQYJKoZIhvcNAQELBQAwgYIxCzAJBgNVBAYTAlVTMQ4w DAYDVQQIDAVUZXhhczEQMA4GA1UEBwwHSG91c3RvbjEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9u MTcwNQYDVQQDDC5TU0wuY29tIEVWIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIy MB4XDTE3MDUzMTE4MTQzN1oXDTQyMDUzMDE4MTQzN1owgYIxCzAJBgNVBAYTAlVTMQ4wDAYDVQQI DAVUZXhhczEQMA4GA1UEBwwHSG91c3RvbjEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMTcwNQYD VQQDDC5TU0wuY29tIEVWIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIyMIICIjAN BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAjzZlQOHWTcDXtOlG2mvqM0fNTPl9fb69LT3w23jh hqXZuglXaO1XPqDQCEGD5yhBJB/jchXQARr7XnAjssufOePPxU7Gkm0mxnu7s9onnQqG6YE3Bf7w cXHswxzpY6IXFJ3vG2fThVUCAtZJycxa4bH3bzKfydQ7iEGonL3Lq9ttewkfokxykNorCPzPPFTO Zw+oz12WGQvE43LrrdF9HSfvkusQv1vrO6/PgN3B0pYEW3p+pKk8OHakYo6gOV7qd89dAFmPZiw+ B6KjBSYRaZfqhbcPlgtLyEDhULouisv3D5oi53+aNxPN8k0TayHRwMwi8qFG9kRpnMphNQcAb9Zh CBHqurj26bNg5U257J8UZslXWNvNh2n4ioYSA0e/ZhN2rHd9NCSFg83XqpyQGp8hLH94t2S42Oim 9HizVcuE0jLEeK6jj2HdzghTreyI/BXkmg3mnxp3zkyPuBQVPWKchjgGAGYS5Fl2WlPAApiiECto RHuOec4zSnaqW4EWG7WK2NAAe15itAnWhmMOpgWVSbooi4iTsjQc2KRVbrcc0N6ZVTsj9CLg+Slm JuwgUHfbSguPvuUCYHBBXtSuUDkiFCbLsjtzdFVHB3mBOagwE0TlBIqulhMlQg+5U8Sb/M3kHN48 +qvWBkofZ6aYMBzdLNvcGJVXZsb/XItW9XcCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNV HSMEGDAWgBT5YLvU49U09rj1BoAlp3PbRmmonjAdBgNVHQ4EFgQU+WC71OPVNPa49QaAJadz20Zp qJ4wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQBWs47LCp1Jjr+kxJG7ZhcFUZh1 ++VQLHqe8RT6q9OKPv+RKY9ji9i0qVQBDb6Thi/5Sm3HXvVX+cpVHBK+Rw82xd9qt9t1wkclf7nx Y/hoLVUE0fKNsKTPvDxeH3jnpaAgcLAExbf3cqfeIg29MyVGjGSSJuM+LmOW2puMPfgYCdcDzH2G guDKBAdRUNf/ktUM79qGn5nX67evaOI5JpS6aLe/g9Pqemc9YmeuJeVy6OLk7K4S9ksrPJ/psEDz OFSz/bdoyNrGj1E8svuR3Bznm53htw1yj+KkxKl4+esUrMZDBcJlOSgYAsOCsp0FvmXtll9ldDz7 CTUue5wT/RsPXcdtgTpWD8w74a8CLyKsRspGPKAcTNZEtF4uXBVmCeEmKf7GUmG6sXP/wwyc5Wxq lD8UykAWlYTzWamsX0xhk23RO8yilQwipmdnRC652dKKQbNmC1r7fSOl8hqw/96bg5Qu0T/fkreR rwU7ZcegbLHNYhLDkBvjJc40vG93drEQw/cFGsDWr3RiSBd3kmmQYRzelYB0VI8YHMPzA9C/pEN1 hlMYegouCRw2n5H9gooiS9EOUCXdywMMF8mDAAhONU2Ki+3wApRmLER/y5UnlhetCTCstnEXbosX 9hwJ1C07mKVx01QT2WDz9UtmT/rx7iASjbSsV7FFY6GsdqnC+w== -----END CERTIFICATE----- SSL.com EV Root Certification Authority ECC =========================================== -----BEGIN CERTIFICATE----- MIIClDCCAhqgAwIBAgIILCmcWxbtBZUwCgYIKoZIzj0EAwIwfzELMAkGA1UEBhMCVVMxDjAMBgNV BAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9TU0wgQ29ycG9yYXRpb24xNDAy BgNVBAMMK1NTTC5jb20gRVYgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYw MjEyMTgxNTIzWhcNNDEwMjEyMTgxNTIzWjB/MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMx EDAOBgNVBAcMB0hvdXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjE0MDIGA1UEAwwrU1NM LmNvbSBFViBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49AgEGBSuB BAAiA2IABKoSR5CYG/vvw0AHgyBO8TCCogbR8pKGYfL2IWjKAMTH6kMAVIbc/R/fALhBYlzccBYy 3h+Z1MzFB8gIH2EWB1E9fVwHU+M1OIzfzZ/ZLg1KthkuWnBaBu2+8KGwytAJKaNjMGEwHQYDVR0O BBYEFFvKXuXe0oGqzagtZFG22XKbl+ZPMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUW8pe 5d7SgarNqC1kUbbZcpuX5k8wDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2gAMGUCMQCK5kCJ N+vp1RPZytRrJPOwPYdGWBrssd9v+1a6cGvHOMzosYxPD/fxZ3YOg9AeUY8CMD32IygmTMZgh5Mm m7I1HrrW9zzRHM76JTymGoEVW/MSD2zuZYrJh6j5B+BimoxcSg== -----END CERTIFICATE----- GlobalSign Root CA - R6 ======================= -----BEGIN CERTIFICATE----- MIIFgzCCA2ugAwIBAgIORea7A4Mzw4VlSOb/RVEwDQYJKoZIhvcNAQEMBQAwTDEgMB4GA1UECxMX R2xvYmFsU2lnbiBSb290IENBIC0gUjYxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkds b2JhbFNpZ24wHhcNMTQxMjEwMDAwMDAwWhcNMzQxMjEwMDAwMDAwWjBMMSAwHgYDVQQLExdHbG9i YWxTaWduIFJvb3QgQ0EgLSBSNjETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFs U2lnbjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAJUH6HPKZvnsFMp7PPcNCPG0RQss grRIxutbPK6DuEGSMxSkb3/pKszGsIhrxbaJ0cay/xTOURQh7ErdG1rG1ofuTToVBu1kZguSgMpE 3nOUTvOniX9PeGMIyBJQbUJmL025eShNUhqKGoC3GYEOfsSKvGRMIRxDaNc9PIrFsmbVkJq3MQbF vuJtMgamHvm566qjuL++gmNQ0PAYid/kD3n16qIfKtJwLnvnvJO7bVPiSHyMEAc4/2ayd2F+4OqM PKq0pPbzlUoSB239jLKJz9CgYXfIWHSw1CM69106yqLbnQneXUQtkPGBzVeS+n68UARjNN9rkxi+ azayOeSsJDa38O+2HBNXk7besvjihbdzorg1qkXy4J02oW9UivFyVm4uiMVRQkQVlO6jxTiWm05O WgtH8wY2SXcwvHE35absIQh1/OZhFj931dmRl4QKbNQCTXTAFO39OfuD8l4UoQSwC+n+7o/hbguy CLNhZglqsQY6ZZZZwPA1/cnaKI0aEYdwgQqomnUdnjqGBQCe24DWJfncBZ4nWUx2OVvq+aWh2IMP 0f/fMBH5hc8zSPXKbWQULHpYT9NLCEnFlWQaYw55PfWzjMpYrZxCRXluDocZXFSxZba/jJvcE+kN b7gu3GduyYsRtYQUigAZcIN5kZeR1BonvzceMgfYFGM8KEyvAgMBAAGjYzBhMA4GA1UdDwEB/wQE AwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSubAWjkxPioufi1xzWx/B/yGdToDAfBgNV HSMEGDAWgBSubAWjkxPioufi1xzWx/B/yGdToDANBgkqhkiG9w0BAQwFAAOCAgEAgyXt6NH9lVLN nsAEoJFp5lzQhN7craJP6Ed41mWYqVuoPId8AorRbrcWc+ZfwFSY1XS+wc3iEZGtIxg93eFyRJa0 lV7Ae46ZeBZDE1ZXs6KzO7V33EByrKPrmzU+sQghoefEQzd5Mr6155wsTLxDKZmOMNOsIeDjHfrY BzN2VAAiKrlNIC5waNrlU/yDXNOd8v9EDERm8tLjvUYAGm0CuiVdjaExUd1URhxN25mW7xocBFym Fe944Hn+Xds+qkxV/ZoVqW/hpvvfcDDpw+5CRu3CkwWJ+n1jez/QcYF8AOiYrg54NMMl+68KnyBr 3TsTjxKM4kEaSHpzoHdpx7Zcf4LIHv5YGygrqGytXm3ABdJ7t+uA/iU3/gKbaKxCXcPu9czc8FB1 0jZpnOZ7BN9uBmm23goJSFmH63sUYHpkqmlD75HHTOwY3WzvUy2MmeFe8nI+z1TIvWfspA9MRf/T uTAjB0yPEL+GltmZWrSZVxykzLsViVO6LAUP5MSeGbEYNNVMnbrt9x+vJJUEeKgDu+6B5dpffItK oZB0JaezPkvILFa9x8jvOOJckvB595yEunQtYQEgfn7R8k8HWV+LLUNS60YMlOH1Zkd5d9VUWx+t JDfLRVpOoERIyNiwmcUVhAn21klJwGW45hpxbqCo8YLoRT5s1gLXCmeDBVrJpBA= -----END CERTIFICATE----- OISTE WISeKey Global Root GC CA =============================== -----BEGIN CERTIFICATE----- MIICaTCCAe+gAwIBAgIQISpWDK7aDKtARb8roi066jAKBggqhkjOPQQDAzBtMQswCQYDVQQGEwJD SDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNlZDEo MCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwgUm9vdCBHQyBDQTAeFw0xNzA1MDkwOTQ4MzRa Fw00MjA1MDkwOTU4MzNaMG0xCzAJBgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYDVQQL ExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEdsb2Jh bCBSb290IEdDIENBMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAETOlQwMYPchi82PG6s4nieUqjFqdr VCTbUf/q9Akkwwsin8tqJ4KBDdLArzHkdIJuyiXZjHWd8dvQmqJLIX4Wp2OQ0jnUsYd4XxiWD1Ab NTcPasbc2RNNpI6QN+a9WzGRo1QwUjAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAd BgNVHQ4EFgQUSIcUrOPDnpBgOtfKie7TrYy0UGYwEAYJKwYBBAGCNxUBBAMCAQAwCgYIKoZIzj0E AwMDaAAwZQIwJsdpW9zV57LnyAyMjMPdeYwbY9XJUpROTYJKcx6ygISpJcBMWm1JKWB4E+J+SOtk AjEA2zQgMgj/mkkCtojeFK9dbJlxjRo/i9fgojaGHAeCOnZT/cKi7e97sIBPWA9LUzm9 -----END CERTIFICATE----- UCA Global G2 Root ================== -----BEGIN CERTIFICATE----- MIIFRjCCAy6gAwIBAgIQXd+x2lqj7V2+WmUgZQOQ7zANBgkqhkiG9w0BAQsFADA9MQswCQYDVQQG EwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxGzAZBgNVBAMMElVDQSBHbG9iYWwgRzIgUm9vdDAeFw0x NjAzMTEwMDAwMDBaFw00MDEyMzEwMDAwMDBaMD0xCzAJBgNVBAYTAkNOMREwDwYDVQQKDAhVbmlU cnVzdDEbMBkGA1UEAwwSVUNBIEdsb2JhbCBHMiBSb290MIICIjANBgkqhkiG9w0BAQEFAAOCAg8A MIICCgKCAgEAxeYrb3zvJgUno4Ek2m/LAfmZmqkywiKHYUGRO8vDaBsGxUypK8FnFyIdK+35KYmT oni9kmugow2ifsqTs6bRjDXVdfkX9s9FxeV67HeToI8jrg4aA3++1NDtLnurRiNb/yzmVHqUwCoV 8MmNsHo7JOHXaOIxPAYzRrZUEaalLyJUKlgNAQLx+hVRZ2zA+te2G3/RVogvGjqNO7uCEeBHANBS h6v7hn4PJGtAnTRnvI3HLYZveT6OqTwXS3+wmeOwcWDcC/Vkw85DvG1xudLeJ1uK6NjGruFZfc8o LTW4lVYa8bJYS7cSN8h8s+1LgOGN+jIjtm+3SJUIsUROhYw6AlQgL9+/V087OpAh18EmNVQg7Mc/ R+zvWr9LesGtOxdQXGLYD0tK3Cv6brxzks3sx1DoQZbXqX5t2Okdj4q1uViSukqSKwxW/YDrCPBe KW4bHAyvj5OJrdu9o54hyokZ7N+1wxrrFv54NkzWbtA+FxyQF2smuvt6L78RHBgOLXMDj6DlNaBa 4kx1HXHhOThTeEDMg5PXCp6dW4+K5OXgSORIskfNTip1KnvyIvbJvgmRlld6iIis7nCs+dwp4wwc OxJORNanTrAmyPPZGpeRaOrvjUYG0lZFWJo8DA+DuAUlwznPO6Q0ibd5Ei9Hxeepl2n8pndntd97 8XplFeRhVmUCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O BBYEFIHEjMz15DD/pQwIX4wVZyF0Ad/fMA0GCSqGSIb3DQEBCwUAA4ICAQATZSL1jiutROTL/7lo 5sOASD0Ee/ojL3rtNtqyzm325p7lX1iPyzcyochltq44PTUbPrw7tgTQvPlJ9Zv3hcU2tsu8+Mg5 1eRfB70VVJd0ysrtT7q6ZHafgbiERUlMjW+i67HM0cOU2kTC5uLqGOiiHycFutfl1qnN3e92mI0A Ds0b+gO3joBYDic/UvuUospeZcnWhNq5NXHzJsBPd+aBJ9J3O5oUb3n09tDh05S60FdRvScFDcH9 yBIw7m+NESsIndTUv4BFFJqIRNow6rSn4+7vW4LVPtateJLbXDzz2K36uGt/xDYotgIVilQsnLAX c47QN6MUPJiVAAwpBVueSUmxX8fjy88nZY41F7dXyDDZQVu5FLbowg+UMaeUmMxq67XhJ/UQqAHo jhJi6IjMtX9Gl8CbEGY4GjZGXyJoPd/JxhMnq1MGrKI8hgZlb7F+sSlEmqO6SWkoaY/X5V+tBIZk bxqgDMUIYs6Ao9Dz7GjevjPHF1t/gMRMTLGmhIrDO7gJzRSBuhjjVFc2/tsvfEehOjPI+Vg7RE+x ygKJBJYoaMVLuCaJu9YzL1DV/pqJuhgyklTGW+Cd+V7lDSKb9triyCGyYiGqhkCyLmTTX8jjfhFn RR8F/uOi77Oos/N9j/gMHyIfLXC0uAE0djAA5SN4p1bXUB+K+wb1whnw0A== -----END CERTIFICATE----- UCA Extended Validation Root ============================ -----BEGIN CERTIFICATE----- MIIFWjCCA0KgAwIBAgIQT9Irj/VkyDOeTzRYZiNwYDANBgkqhkiG9w0BAQsFADBHMQswCQYDVQQG EwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxJTAjBgNVBAMMHFVDQSBFeHRlbmRlZCBWYWxpZGF0aW9u IFJvb3QwHhcNMTUwMzEzMDAwMDAwWhcNMzgxMjMxMDAwMDAwWjBHMQswCQYDVQQGEwJDTjERMA8G A1UECgwIVW5pVHJ1c3QxJTAjBgNVBAMMHFVDQSBFeHRlbmRlZCBWYWxpZGF0aW9uIFJvb3QwggIi MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCpCQcoEwKwmeBkqh5DFnpzsZGgdT6o+uM4AHrs iWogD4vFsJszA1qGxliG1cGFu0/GnEBNyr7uaZa4rYEwmnySBesFK5pI0Lh2PpbIILvSsPGP2KxF Rv+qZ2C0d35qHzwaUnoEPQc8hQ2E0B92CvdqFN9y4zR8V05WAT558aopO2z6+I9tTcg1367r3CTu eUWnhbYFiN6IXSV8l2RnCdm/WhUFhvMJHuxYMjMR83dksHYf5BA1FxvyDrFspCqjc/wJHx4yGVMR 59mzLC52LqGj3n5qiAno8geK+LLNEOfic0CTuwjRP+H8C5SzJe98ptfRr5//lpr1kXuYC3fUfugH 0mK1lTnj8/FtDw5lhIpjVMWAtuCeS31HJqcBCF3RiJ7XwzJE+oJKCmhUfzhTA8ykADNkUVkLo4KR el7sFsLzKuZi2irbWWIQJUoqgQtHB0MGcIfS+pMRKXpITeuUx3BNr2fVUbGAIAEBtHoIppB/TuDv B0GHr2qlXov7z1CymlSvw4m6WC31MJixNnI5fkkE/SmnTHnkBVfblLkWU41Gsx2VYVdWf6/wFlth WG82UBEL2KwrlRYaDh8IzTY0ZRBiZtWAXxQgXy0MoHgKaNYs1+lvK9JKBZP8nm9rZ/+I8U6laUpS NwXqxhaN0sSZ0YIrO7o1dfdRUVjzyAfd5LQDfwIDAQABo0IwQDAdBgNVHQ4EFgQU2XQ65DA9DfcS 3H5aBZ8eNJr34RQwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQEL BQADggIBADaNl8xCFWQpN5smLNb7rhVpLGsaGvdftvkHTFnq88nIua7Mui563MD1sC3AO6+fcAUR ap8lTwEpcOPlDOHqWnzcSbvBHiqB9RZLcpHIojG5qtr8nR/zXUACE/xOHAbKsxSQVBcZEhrxH9cM aVr2cXj0lH2RC47skFSOvG+hTKv8dGT9cZr4QQehzZHkPJrgmzI5c6sq1WnIeJEmMX3ixzDx/BR4 dxIOE/TdFpS/S2d7cFOFyrC78zhNLJA5wA3CXWvp4uXViI3WLL+rG761KIcSF3Ru/H38j9CHJrAb +7lsq+KePRXBOy5nAliRn+/4Qh8st2j1da3Ptfb/EX3C8CSlrdP6oDyp+l3cpaDvRKS+1ujl5BOW F3sGPjLtx7dCvHaj2GU4Kzg1USEODm8uNBNA4StnDG1KQTAYI1oyVZnJF+A83vbsea0rWBmirSwi GpWOvpaQXUJXxPkUAzUrHC1RVwinOt4/5Mi0A3PCwSaAuwtCH60NryZy2sy+s6ODWA2CxR9GUeOc GMyNm43sSet1UNWMKFnKdDTajAshqx7qG+XH/RU+wBeq+yNuJkbL+vmxcmtpzyKEC2IPrNkZAJSi djzULZrtBJ4tBmIQN1IchXIbJ+XMxjHsN+xjWZsLHXbMfjKaiJUINlK73nZfdklJrX+9ZSCyycEr dhh2n1ax -----END CERTIFICATE----- Certigna Root CA ================ -----BEGIN CERTIFICATE----- MIIGWzCCBEOgAwIBAgIRAMrpG4nxVQMNo+ZBbcTjpuEwDQYJKoZIhvcNAQELBQAwWjELMAkGA1UE BhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczEcMBoGA1UECwwTMDAwMiA0ODE0NjMwODEwMDAzNjEZ MBcGA1UEAwwQQ2VydGlnbmEgUm9vdCBDQTAeFw0xMzEwMDEwODMyMjdaFw0zMzEwMDEwODMyMjda MFoxCzAJBgNVBAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxHDAaBgNVBAsMEzAwMDIgNDgxNDYz MDgxMDAwMzYxGTAXBgNVBAMMEENlcnRpZ25hIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4IC DwAwggIKAoICAQDNGDllGlmx6mQWDoyUJJV8g9PFOSbcDO8WV43X2KyjQn+Cyu3NW9sOty3tRQgX stmzy9YXUnIo245Onoq2C/mehJpNdt4iKVzSs9IGPjA5qXSjklYcoW9MCiBtnyN6tMbaLOQdLNyz KNAT8kxOAkmhVECe5uUFoC2EyP+YbNDrihqECB63aCPuI9Vwzm1RaRDuoXrC0SIxwoKF0vJVdlB8 JXrJhFwLrN1CTivngqIkicuQstDuI7pmTLtipPlTWmR7fJj6o0ieD5Wupxj0auwuA0Wv8HT4Ks16 XdG+RCYyKfHx9WzMfgIhC59vpD++nVPiz32pLHxYGpfhPTc3GGYo0kDFUYqMwy3OU4gkWGQwFsWq 4NYKpkDfePb1BHxpE4S80dGnBs8B92jAqFe7OmGtBIyT46388NtEbVncSVmurJqZNjBBe3YzIoej wpKGbvlw7q6Hh5UbxHq9MfPU0uWZ/75I7HX1eBYdpnDBfzwboZL7z8g81sWTCo/1VTp2lc5ZmIoJ lXcymoO6LAQ6l73UL77XbJuiyn1tJslV1c/DeVIICZkHJC1kJWumIWmbat10TWuXekG9qxf5kBdI jzb5LdXF2+6qhUVB+s06RbFo5jZMm5BX7CO5hwjCxAnxl4YqKE3idMDaxIzb3+KhF1nOJFl0Mdp/ /TBt2dzhauH8XwIDAQABo4IBGjCCARYwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw HQYDVR0OBBYEFBiHVuBud+4kNTxOc5of1uHieX4rMB8GA1UdIwQYMBaAFBiHVuBud+4kNTxOc5of 1uHieX4rMEQGA1UdIAQ9MDswOQYEVR0gADAxMC8GCCsGAQUFBwIBFiNodHRwczovL3d3d3cuY2Vy dGlnbmEuZnIvYXV0b3JpdGVzLzBtBgNVHR8EZjBkMC+gLaArhilodHRwOi8vY3JsLmNlcnRpZ25h LmZyL2NlcnRpZ25hcm9vdGNhLmNybDAxoC+gLYYraHR0cDovL2NybC5kaGlteW90aXMuY29tL2Nl cnRpZ25hcm9vdGNhLmNybDANBgkqhkiG9w0BAQsFAAOCAgEAlLieT/DjlQgi581oQfccVdV8AOIt OoldaDgvUSILSo3L6btdPrtcPbEo/uRTVRPPoZAbAh1fZkYJMyjhDSSXcNMQH+pkV5a7XdrnxIxP TGRGHVyH41neQtGbqH6mid2PHMkwgu07nM3A6RngatgCdTer9zQoKJHyBApPNeNgJgH60BGM+RFq 7q89w1DTj18zeTyGqHNFkIwgtnJzFyO+B2XleJINugHA64wcZr+shncBlA2c5uk5jR+mUYyZDDl3 4bSb+hxnV29qao6pK0xXeXpXIs/NX2NGjVxZOob4Mkdio2cNGJHc+6Zr9UhhcyNZjgKnvETq9Emd 8VRY+WCv2hikLyhF3HqgiIZd8zvn/yk1gPxkQ5Tm4xxvvq0OKmOZK8l+hfZx6AYDlf7ej0gcWtSS 6Cvu5zHbugRqh5jnxV/vfaci9wHYTfmJ0A6aBVmknpjZbyvKcL5kwlWj9Omvw5Ip3IgWJJk8jSaY tlu3zM63Nwf9JtmYhST/WSMDmu2dnajkXjjO11INb9I/bbEFa0nOipFGc/T2L/Coc3cOZayhjWZS aX5LaAzHHjcng6WMxwLkFM1JAbBzs/3GkDpv0mztO+7skb6iQ12LAEpmJURw3kAP+HwV96LOPNde E4yBFxgX0b3xdxA61GU5wSesVywlVP+i2k+KYTlerj1KjL0= -----END CERTIFICATE----- emSign Root CA - G1 =================== -----BEGIN CERTIFICATE----- MIIDlDCCAnygAwIBAgIKMfXkYgxsWO3W2DANBgkqhkiG9w0BAQsFADBnMQswCQYDVQQGEwJJTjET MBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNobm9sb2dpZXMgTGltaXRl ZDEcMBoGA1UEAxMTZW1TaWduIFJvb3QgQ0EgLSBHMTAeFw0xODAyMTgxODMwMDBaFw00MzAyMTgx ODMwMDBaMGcxCzAJBgNVBAYTAklOMRMwEQYDVQQLEwplbVNpZ24gUEtJMSUwIwYDVQQKExxlTXVk aHJhIFRlY2hub2xvZ2llcyBMaW1pdGVkMRwwGgYDVQQDExNlbVNpZ24gUm9vdCBDQSAtIEcxMIIB IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAk0u76WaK7p1b1TST0Bsew+eeuGQzf2N4aLTN LnF115sgxk0pvLZoYIr3IZpWNVrzdr3YzZr/k1ZLpVkGoZM0Kd0WNHVO8oG0x5ZOrRkVUkr+PHB1 cM2vK6sVmjM8qrOLqs1D/fXqcP/tzxE7lM5OMhbTI0Aqd7OvPAEsbO2ZLIvZTmmYsvePQbAyeGHW DV/D+qJAkh1cF+ZwPjXnorfCYuKrpDhMtTk1b+oDafo6VGiFbdbyL0NVHpENDtjVaqSW0RM8LHhQ 6DqS0hdW5TUaQBw+jSztOd9C4INBdN+jzcKGYEho42kLVACL5HZpIQ15TjQIXhTCzLG3rdd8cIrH hQIDAQABo0IwQDAdBgNVHQ4EFgQU++8Nhp6w492pufEhF38+/PB3KxowDgYDVR0PAQH/BAQDAgEG MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAFn/8oz1h31xPaOfG1vR2vjTnGs2 vZupYeveFix0PZ7mddrXuqe8QhfnPZHr5X3dPpzxz5KsbEjMwiI/aTvFthUvozXGaCocV685743Q NcMYDHsAVhzNixl03r4PEuDQqqE/AjSxcM6dGNYIAwlG7mDgfrbESQRRfXBgvKqy/3lyeqYdPV8q +Mri/Tm3R7nrft8EI6/6nAYH6ftjk4BAtcZsCjEozgyfz7MjNYBBjWzEN3uBL4ChQEKF6dk4jeih U80Bv2noWgbyRQuQ+q7hv53yrlc8pa6yVvSLZUDp/TGBLPQ5Cdjua6e0ph0VpZj3AYHYhX3zUVxx iN66zB+Afko= -----END CERTIFICATE----- emSign ECC Root CA - G3 ======================= -----BEGIN CERTIFICATE----- MIICTjCCAdOgAwIBAgIKPPYHqWhwDtqLhDAKBggqhkjOPQQDAzBrMQswCQYDVQQGEwJJTjETMBEG A1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNobm9sb2dpZXMgTGltaXRlZDEg MB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0gRzMwHhcNMTgwMjE4MTgzMDAwWhcNNDMwMjE4 MTgzMDAwWjBrMQswCQYDVQQGEwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11 ZGhyYSBUZWNobm9sb2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0g RzMwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQjpQy4LRL1KPOxst3iAhKAnjlfSU2fySU0WXTsuwYc 58Byr+iuL+FBVIcUqEqy6HyC5ltqtdyzdc6LBtCGI79G1Y4PPwT01xySfvalY8L1X44uT6EYGQIr MgqCZH0Wk9GjQjBAMB0GA1UdDgQWBBR8XQKEE9TMipuBzhccLikenEhjQjAOBgNVHQ8BAf8EBAMC AQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNpADBmAjEAvvNhzwIQHWSVB7gYboiFBS+D CBeQyh+KTOgNG3qxrdWBCUfvO6wIBHxcmbHtRwfSAjEAnbpV/KlK6O3t5nYBQnvI+GDZjVGLVTv7 jHvrZQnD+JbNR6iC8hZVdyR+EhCVBCyj -----END CERTIFICATE----- emSign Root CA - C1 =================== -----BEGIN CERTIFICATE----- MIIDczCCAlugAwIBAgILAK7PALrEzzL4Q7IwDQYJKoZIhvcNAQELBQAwVjELMAkGA1UEBhMCVVMx EzARBgNVBAsTCmVtU2lnbiBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMRwwGgYDVQQDExNlbVNp Z24gUm9vdCBDQSAtIEMxMB4XDTE4MDIxODE4MzAwMFoXDTQzMDIxODE4MzAwMFowVjELMAkGA1UE BhMCVVMxEzARBgNVBAsTCmVtU2lnbiBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMRwwGgYDVQQD ExNlbVNpZ24gUm9vdCBDQSAtIEMxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAz+up ufGZBczYKCFK83M0UYRWEPWgTywS4/oTmifQz/l5GnRfHXk5/Fv4cI7gklL35CX5VIPZHdPIWoU/ Xse2B+4+wM6ar6xWQio5JXDWv7V7Nq2s9nPczdcdioOl+yuQFTdrHCZH3DspVpNqs8FqOp099cGX OFgFixwR4+S0uF2FHYP+eF8LRWgYSKVGczQ7/g/IdrvHGPMF0Ybzhe3nudkyrVWIzqa2kbBPrH4V I5b2P/AgNBbeCsbEBEV5f6f9vtKppa+cxSMq9zwhbL2vj07FOrLzNBL834AaSaTUqZX3noleooms lMuoaJuvimUnzYnu3Yy1aylwQ6BpC+S5DwIDAQABo0IwQDAdBgNVHQ4EFgQU/qHgcB4qAzlSWkK+ XJGFehiqTbUwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQAD ggEBAMJKVvoVIXsoounlHfv4LcQ5lkFMOycsxGwYFYDGrK9HWS8mC+M2sO87/kOXSTKZEhVb3xEp /6tT+LvBeA+snFOvV71ojD1pM/CjoCNjO2RnIkSt1XHLVip4kqNPEjE2NuLe/gDEo2APJ62gsIq1 NnpSob0n9CAnYuhNlCQT5AoE6TyrLshDCUrGYQTlSTR+08TI9Q/Aqum6VF7zYytPT1DU/rl7mYw9 wC68AivTxEDkigcxHpvOJpkT+xHqmiIMERnHXhuBUDDIlhJu58tBf5E7oke3VIAb3ADMmpDqw8NQ BmIMMMAVSKeoWXzhriKi4gp6D/piq1JM4fHfyr6DDUI= -----END CERTIFICATE----- emSign ECC Root CA - C3 ======================= -----BEGIN CERTIFICATE----- MIICKzCCAbGgAwIBAgIKe3G2gla4EnycqDAKBggqhkjOPQQDAzBaMQswCQYDVQQGEwJVUzETMBEG A1UECxMKZW1TaWduIFBLSTEUMBIGA1UEChMLZU11ZGhyYSBJbmMxIDAeBgNVBAMTF2VtU2lnbiBF Q0MgUm9vdCBDQSAtIEMzMB4XDTE4MDIxODE4MzAwMFoXDTQzMDIxODE4MzAwMFowWjELMAkGA1UE BhMCVVMxEzARBgNVBAsTCmVtU2lnbiBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMSAwHgYDVQQD ExdlbVNpZ24gRUNDIFJvb3QgQ0EgLSBDMzB2MBAGByqGSM49AgEGBSuBBAAiA2IABP2lYa57JhAd 6bciMK4G9IGzsUJxlTm801Ljr6/58pc1kjZGDoeVjbk5Wum739D+yAdBPLtVb4OjavtisIGJAnB9 SMVK4+kiVCJNk7tCDK93nCOmfddhEc5lx/h//vXyqaNCMEAwHQYDVR0OBBYEFPtaSNCAIEDyqOkA B2kZd6fmw/TPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMDA2gA MGUCMQC02C8Cif22TGK6Q04ThHK1rt0c3ta13FaPWEBaLd4gTCKDypOofu4SQMfWh0/434UCMBwU ZOR8loMRnLDRWmFLpg9J0wD8ofzkpf9/rdcw0Md3f76BB1UwUCAU9Vc4CqgxUQ== -----END CERTIFICATE----- Hongkong Post Root CA 3 ======================= -----BEGIN CERTIFICATE----- MIIFzzCCA7egAwIBAgIUCBZfikyl7ADJk0DfxMauI7gcWqQwDQYJKoZIhvcNAQELBQAwbzELMAkG A1UEBhMCSEsxEjAQBgNVBAgTCUhvbmcgS29uZzESMBAGA1UEBxMJSG9uZyBLb25nMRYwFAYDVQQK Ew1Ib25na29uZyBQb3N0MSAwHgYDVQQDExdIb25na29uZyBQb3N0IFJvb3QgQ0EgMzAeFw0xNzA2 MDMwMjI5NDZaFw00MjA2MDMwMjI5NDZaMG8xCzAJBgNVBAYTAkhLMRIwEAYDVQQIEwlIb25nIEtv bmcxEjAQBgNVBAcTCUhvbmcgS29uZzEWMBQGA1UEChMNSG9uZ2tvbmcgUG9zdDEgMB4GA1UEAxMX SG9uZ2tvbmcgUG9zdCBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCz iNfqzg8gTr7m1gNt7ln8wlffKWihgw4+aMdoWJwcYEuJQwy51BWy7sFOdem1p+/l6TWZ5Mwc50tf jTMwIDNT2aa71T4Tjukfh0mtUC1Qyhi+AViiE3CWu4mIVoBc+L0sPOFMV4i707mV78vH9toxdCim 5lSJ9UExyuUmGs2C4HDaOym71QP1mbpV9WTRYA6ziUm4ii8F0oRFKHyPaFASePwLtVPLwpgchKOe sL4jpNrcyCse2m5FHomY2vkALgbpDDtw1VAliJnLzXNg99X/NWfFobxeq81KuEXryGgeDQ0URhLj 0mRiikKYvLTGCAj4/ahMZJx2Ab0vqWwzD9g/KLg8aQFChn5pwckGyuV6RmXpwtZQQS4/t+TtbNe/ JgERohYpSms0BpDsE9K2+2p20jzt8NYt3eEV7KObLyzJPivkaTv/ciWxNoZbx39ri1UbSsUgYT2u y1DhCDq+sI9jQVMwCFk8mB13umOResoQUGC/8Ne8lYePl8X+l2oBlKN8W4UdKjk60FSh0Tlxnf0h +bV78OLgAo9uliQlLKAeLKjEiafv7ZkGL7YKTE/bosw3Gq9HhS2KX8Q0NEwA/RiTZxPRN+ZItIsG xVd7GYYKecsAyVKvQv83j+GjHno9UKtjBucVtT+2RTeUN7F+8kjDf8V1/peNRY8apxpyKBpADwID AQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBQXnc0e i9Y5K3DTXNSguB+wAPzFYTAdBgNVHQ4EFgQUF53NHovWOStw01zUoLgfsAD8xWEwDQYJKoZIhvcN AQELBQADggIBAFbVe27mIgHSQpsY1Q7XZiNc4/6gx5LS6ZStS6LG7BJ8dNVI0lkUmcDrudHr9Egw W62nV3OZqdPlt9EuWSRY3GguLmLYauRwCy0gUCCkMpXRAJi70/33MvJJrsZ64Ee+bs7Lo3I6LWld y8joRTnU+kLBEUx3XZL7av9YROXrgZ6voJmtvqkBZss4HTzfQx/0TW60uhdG/H39h4F5ag0zD/ov +BS5gLNdTaqX4fnkGMX41TiMJjz98iji7lpJiCzfeT2OnpA8vUFKOt1b9pq0zj8lMH8yfaIDlNDc eqFS3m6TjRgm/VWsvY+b0s+v54Ysyx8Jb6NvqYTUc79NoXQbTiNg8swOqn+knEwlqLJmOzj/2ZQw 9nKEvmhVEA/GcywWaZMH/rFF7buiVWqw2rVKAiUnhde3t4ZEFolsgCs+l6mc1X5VTMbeRRAc6uk7 nwNT7u56AQIWeNTowr5GdogTPyK7SBIdUgC0An4hGh6cJfTzPV4e0hz5sy229zdcxsshTrD3mUcY hcErulWuBurQB7Lcq9CClnXO0lD+mefPL5/ndtFhKvshuzHQqp9HpLIiyhY6UFfEW0NnxWViA0kB 60PZ2Pierc+xYw5F9KBaLJstxabArahH9CdMOA0uG0k7UvToiIMrVCjU8jVStDKDYmlkDJGcn5fq dBb9HxEGmpv0 -----END CERTIFICATE----- Microsoft ECC Root Certificate Authority 2017 ============================================= -----BEGIN CERTIFICATE----- MIICWTCCAd+gAwIBAgIQZvI9r4fei7FK6gxXMQHC7DAKBggqhkjOPQQDAzBlMQswCQYDVQQGEwJV UzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYDVQQDEy1NaWNyb3NvZnQgRUND IFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwHhcNMTkxMjE4MjMwNjQ1WhcNNDIwNzE4 MjMxNjA0WjBlMQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYw NAYDVQQDEy1NaWNyb3NvZnQgRUNDIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwdjAQ BgcqhkjOPQIBBgUrgQQAIgNiAATUvD0CQnVBEyPNgASGAlEvaqiBYgtlzPbKnR5vSmZRogPZnZH6 thaxjG7efM3beaYvzrvOcS/lpaso7GMEZpn4+vKTEAXhgShC48Zo9OYbhGBKia/teQ87zvH2RPUB eMCjVDBSMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTIy5lycFIM +Oa+sgRXKSrPQhDtNTAQBgkrBgEEAYI3FQEEAwIBADAKBggqhkjOPQQDAwNoADBlAjBY8k3qDPlf Xu5gKcs68tvWMoQZP3zVL8KxzJOuULsJMsbG7X7JNpQS5GiFBqIb0C8CMQCZ6Ra0DvpWSNSkMBaR eNtUjGUBiudQZsIxtzm6uBoiB078a1QWIP8rtedMDE2mT3M= -----END CERTIFICATE----- Microsoft RSA Root Certificate Authority 2017 ============================================= -----BEGIN CERTIFICATE----- MIIFqDCCA5CgAwIBAgIQHtOXCV/YtLNHcB6qvn9FszANBgkqhkiG9w0BAQwFADBlMQswCQYDVQQG EwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYDVQQDEy1NaWNyb3NvZnQg UlNBIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwHhcNMTkxMjE4MjI1MTIyWhcNNDIw NzE4MjMwMDIzWjBlMQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9u MTYwNAYDVQQDEy1NaWNyb3NvZnQgUlNBIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcw ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKW76UM4wplZEWCpW9R2LBifOZNt9GkMml 7Xhqb0eRaPgnZ1AzHaGm++DlQ6OEAlcBXZxIQIJTELy/xztokLaCLeX0ZdDMbRnMlfl7rEqUrQ7e S0MdhweSE5CAg2Q1OQT85elss7YfUJQ4ZVBcF0a5toW1HLUX6NZFndiyJrDKxHBKrmCk3bPZ7Pw7 1VdyvD/IybLeS2v4I2wDwAW9lcfNcztmgGTjGqwu+UcF8ga2m3P1eDNbx6H7JyqhtJqRjJHTOoI+ dkC0zVJhUXAoP8XFWvLJjEm7FFtNyP9nTUwSlq31/niol4fX/V4ggNyhSyL71Imtus5Hl0dVe49F yGcohJUcaDDv70ngNXtk55iwlNpNhTs+VcQor1fznhPbRiefHqJeRIOkpcrVE7NLP8TjwuaGYaRS MLl6IE9vDzhTyzMMEyuP1pq9KsgtsRx9S1HKR9FIJ3Jdh+vVReZIZZ2vUpC6W6IYZVcSn2i51BVr lMRpIpj0M+Dt+VGOQVDJNE92kKz8OMHY4Xu54+OU4UZpyw4KUGsTuqwPN1q3ErWQgR5WrlcihtnJ 0tHXUeOrO8ZV/R4O03QK0dqq6mm4lyiPSMQH+FJDOvTKVTUssKZqwJz58oHhEmrARdlns87/I6KJ ClTUFLkqqNfs+avNJVgyeY+QW5g5xAgGwax/Dj0ApQIDAQABo1QwUjAOBgNVHQ8BAf8EBAMCAYYw DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUCctZf4aycI8awznjwNnpv7tNsiMwEAYJKwYBBAGC NxUBBAMCAQAwDQYJKoZIhvcNAQEMBQADggIBAKyvPl3CEZaJjqPnktaXFbgToqZCLgLNFgVZJ8og 6Lq46BrsTaiXVq5lQ7GPAJtSzVXNUzltYkyLDVt8LkS/gxCP81OCgMNPOsduET/m4xaRhPtthH80 dK2Jp86519efhGSSvpWhrQlTM93uCupKUY5vVau6tZRGrox/2KJQJWVggEbbMwSubLWYdFQl3JPk +ONVFT24bcMKpBLBaYVu32TxU5nhSnUgnZUP5NbcA/FZGOhHibJXWpS2qdgXKxdJ5XbLwVaZOjex /2kskZGT4d9Mozd2TaGf+G0eHdP67Pv0RR0Tbc/3WeUiJ3IrhvNXuzDtJE3cfVa7o7P4NHmJweDy AmH3pvwPuxwXC65B2Xy9J6P9LjrRk5Sxcx0ki69bIImtt2dmefU6xqaWM/5TkshGsRGRxpl/j8nW ZjEgQRCHLQzWwa80mMpkg/sTV9HB8Dx6jKXB/ZUhoHHBk2dxEuqPiAppGWSZI1b7rCoucL5mxAyE 7+WL85MB+GqQk2dLsmijtWKP6T+MejteD+eMuMZ87zf9dOLITzNy4ZQ5bb0Sr74MTnB8G2+NszKT c0QWbej09+CVgI+WXTik9KveCjCHk9hNAHFiRSdLOkKEW39lt2c0Ui2cFmuqqNh7o0JMcccMyj6D 5KbvtwEwXlGjefVwaaZBRA+GsCyRxj3qrg+E -----END CERTIFICATE----- e-Szigno Root CA 2017 ===================== -----BEGIN CERTIFICATE----- MIICQDCCAeWgAwIBAgIMAVRI7yH9l1kN9QQKMAoGCCqGSM49BAMCMHExCzAJBgNVBAYTAkhVMREw DwYDVQQHDAhCdWRhcGVzdDEWMBQGA1UECgwNTWljcm9zZWMgTHRkLjEXMBUGA1UEYQwOVkFUSFUt MjM1ODQ0OTcxHjAcBgNVBAMMFWUtU3ppZ25vIFJvb3QgQ0EgMjAxNzAeFw0xNzA4MjIxMjA3MDZa Fw00MjA4MjIxMjA3MDZaMHExCzAJBgNVBAYTAkhVMREwDwYDVQQHDAhCdWRhcGVzdDEWMBQGA1UE CgwNTWljcm9zZWMgTHRkLjEXMBUGA1UEYQwOVkFUSFUtMjM1ODQ0OTcxHjAcBgNVBAMMFWUtU3pp Z25vIFJvb3QgQ0EgMjAxNzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABJbcPYrYsHtvxie+RJCx s1YVe45DJH0ahFnuY2iyxl6H0BVIHqiQrb1TotreOpCmYF9oMrWGQd+HWyx7xf58etqjYzBhMA8G A1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSHERUI0arBeAyxr87GyZDv vzAEwDAfBgNVHSMEGDAWgBSHERUI0arBeAyxr87GyZDvvzAEwDAKBggqhkjOPQQDAgNJADBGAiEA tVfd14pVCzbhhkT61NlojbjcI4qKDdQvfepz7L9NbKgCIQDLpbQS+ue16M9+k/zzNY9vTlp8tLxO svxyqltZ+efcMQ== -----END CERTIFICATE----- certSIGN Root CA G2 =================== -----BEGIN CERTIFICATE----- MIIFRzCCAy+gAwIBAgIJEQA0tk7GNi02MA0GCSqGSIb3DQEBCwUAMEExCzAJBgNVBAYTAlJPMRQw EgYDVQQKEwtDRVJUU0lHTiBTQTEcMBoGA1UECxMTY2VydFNJR04gUk9PVCBDQSBHMjAeFw0xNzAy MDYwOTI3MzVaFw00MjAyMDYwOTI3MzVaMEExCzAJBgNVBAYTAlJPMRQwEgYDVQQKEwtDRVJUU0lH TiBTQTEcMBoGA1UECxMTY2VydFNJR04gUk9PVCBDQSBHMjCCAiIwDQYJKoZIhvcNAQEBBQADggIP ADCCAgoCggIBAMDFdRmRfUR0dIf+DjuW3NgBFszuY5HnC2/OOwppGnzC46+CjobXXo9X69MhWf05 N0IwvlDqtg+piNguLWkh59E3GE59kdUWX2tbAMI5Qw02hVK5U2UPHULlj88F0+7cDBrZuIt4Imfk abBoxTzkbFpG583H+u/E7Eu9aqSs/cwoUe+StCmrqzWaTOTECMYmzPhpn+Sc8CnTXPnGFiWeI8Mg wT0PPzhAsP6CRDiqWhqKa2NYOLQV07YRaXseVO6MGiKscpc/I1mbySKEwQdPzH/iV8oScLumZfNp dWO9lfsbl83kqK/20U6o2YpxJM02PbyWxPFsqa7lzw1uKA2wDrXKUXt4FMMgL3/7FFXhEZn91Qqh ngLjYl/rNUssuHLoPj1PrCy7Lobio3aP5ZMqz6WryFyNSwb/EkaseMsUBzXgqd+L6a8VTxaJW732 jcZZroiFDsGJ6x9nxUWO/203Nit4ZoORUSs9/1F3dmKh7Gc+PoGD4FapUB8fepmrY7+EF3fxDTvf 95xhszWYijqy7DwaNz9+j5LP2RIUZNoQAhVB/0/E6xyjyfqZ90bp4RjZsbgyLcsUDFDYg2WD7rlc z8sFWkz6GZdr1l0T08JcVLwyc6B49fFtHsufpaafItzRUZ6CeWRgKRM+o/1Pcmqr4tTluCRVLERL iohEnMqE0yo7AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1Ud DgQWBBSCIS1mxteg4BXrzkwJd8RgnlRuAzANBgkqhkiG9w0BAQsFAAOCAgEAYN4auOfyYILVAzOB ywaK8SJJ6ejqkX/GM15oGQOGO0MBzwdw5AgeZYWR5hEit/UCI46uuR59H35s5r0l1ZUa8gWmr4UC b6741jH/JclKyMeKqdmfS0mbEVeZkkMR3rYzpMzXjWR91M08KCy0mpbqTfXERMQlqiCA2ClV9+BB /AYm/7k29UMUA2Z44RGx2iBfRgB4ACGlHgAoYXhvqAEBj500mv/0OJD7uNGzcgbJceaBxXntC6Z5 8hMLnPddDnskk7RI24Zf3lCGeOdA5jGokHZwYa+cNywRtYK3qq4kNFtyDGkNzVmf9nGvnAvRCjj5 BiKDUyUM/FHE5r7iOZULJK2v0ZXkltd0ZGtxTgI8qoXzIKNDOXZbbFD+mpwUHmUUihW9o4JFWklW atKcsWMy5WHgUyIOpwpJ6st+H6jiYoD2EEVSmAYY3qXNL3+q1Ok+CHLsIwMCPKaq2LxndD0UF/tU Sxfj03k9bWtJySgOLnRQvwzZRjoQhsmnP+mg7H/rpXdYaXHmgwo38oZJar55CJD2AhZkPuXaTH4M NMn5X7azKFGnpyuqSfqNZSlO42sTp5SjLVFteAxEy9/eCG/Oo2Sr05WE1LlSVHJ7liXMvGnjSG4N 0MedJ5qq+BOS3R7fY581qRY27Iy4g/Q9iY/NtBde17MXQRBdJ3NghVdJIgc= -----END CERTIFICATE----- Trustwave Global Certification Authority ======================================== -----BEGIN CERTIFICATE----- MIIF2jCCA8KgAwIBAgIMBfcOhtpJ80Y1LrqyMA0GCSqGSIb3DQEBCwUAMIGIMQswCQYDVQQGEwJV UzERMA8GA1UECAwISWxsaW5vaXMxEDAOBgNVBAcMB0NoaWNhZ28xITAfBgNVBAoMGFRydXN0d2F2 ZSBIb2xkaW5ncywgSW5jLjExMC8GA1UEAwwoVHJ1c3R3YXZlIEdsb2JhbCBDZXJ0aWZpY2F0aW9u IEF1dGhvcml0eTAeFw0xNzA4MjMxOTM0MTJaFw00MjA4MjMxOTM0MTJaMIGIMQswCQYDVQQGEwJV UzERMA8GA1UECAwISWxsaW5vaXMxEDAOBgNVBAcMB0NoaWNhZ28xITAfBgNVBAoMGFRydXN0d2F2 ZSBIb2xkaW5ncywgSW5jLjExMC8GA1UEAwwoVHJ1c3R3YXZlIEdsb2JhbCBDZXJ0aWZpY2F0aW9u IEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALldUShLPDeS0YLOvR29 zd24q88KPuFd5dyqCblXAj7mY2Hf8g+CY66j96xz0XznswuvCAAJWX/NKSqIk4cXGIDtiLK0thAf LdZfVaITXdHG6wZWiYj+rDKd/VzDBcdu7oaJuogDnXIhhpCujwOl3J+IKMujkkkP7NAP4m1ET4Bq stTnoApTAbqOl5F2brz81Ws25kCI1nsvXwXoLG0R8+eyvpJETNKXpP7ScoFDB5zpET71ixpZfR9o WN0EACyW80OzfpgZdNmcc9kYvkHHNHnZ9GLCQ7mzJ7Aiy/k9UscwR7PJPrhq4ufogXBeQotPJqX+ OsIgbrv4Fo7NDKm0G2x2EOFYeUY+VM6AqFcJNykbmROPDMjWLBz7BegIlT1lRtzuzWniTY+HKE40 Cz7PFNm73bZQmq131BnW2hqIyE4bJ3XYsgjxroMwuREOzYfwhI0Vcnyh78zyiGG69Gm7DIwLdVcE uE4qFC49DxweMqZiNu5m4iK4BUBjECLzMx10coos9TkpoNPnG4CELcU9402x/RpvumUHO1jsQkUm +9jaJXLE9gCxInm943xZYkqcBW89zubWR2OZxiRvchLIrH+QtAuRcOi35hYQcRfO3gZPSEF9NUqj ifLJS3tBEW1ntwiYTOURGa5CgNz7kAXU+FDKvuStx8KU1xad5hePrzb7AgMBAAGjQjBAMA8GA1Ud EwEB/wQFMAMBAf8wHQYDVR0OBBYEFJngGWcNYtt2s9o9uFvo/ULSMQ6HMA4GA1UdDwEB/wQEAwIB BjANBgkqhkiG9w0BAQsFAAOCAgEAmHNw4rDT7TnsTGDZqRKGFx6W0OhUKDtkLSGm+J1WE2pIPU/H PinbbViDVD2HfSMF1OQc3Og4ZYbFdada2zUFvXfeuyk3QAUHw5RSn8pk3fEbK9xGChACMf1KaA0H ZJDmHvUqoai7PF35owgLEQzxPy0QlG/+4jSHg9bP5Rs1bdID4bANqKCqRieCNqcVtgimQlRXtpla 4gt5kNdXElE1GYhBaCXUNxeEFfsBctyV3lImIJgm4nb1J2/6ADtKYdkNy1GTKv0WBpanI5ojSP5R vbbEsLFUzt5sQa0WZ37b/TjNuThOssFgy50X31ieemKyJo90lZvkWx3SD92YHJtZuSPTMaCm/zjd zyBP6VhWOmfD0faZmZ26NraAL4hHT4a/RDqA5Dccprrql5gR0IRiR2Qequ5AvzSxnI9O4fKSTx+O 856X3vOmeWqJcU9LJxdI/uz0UA9PSX3MReO9ekDFQdxhVicGaeVyQYHTtgGJoC86cnn+OjC/QezH Yj6RS8fZMXZC+fc8Y+wmjHMMfRod6qh8h6jCJ3zhM0EPz8/8AKAigJ5Kp28AsEFFtyLKaEjFQqKu 3R3y4G5OBVixwJAWKqQ9EEC+j2Jjg6mcgn0tAumDMHzLJ8n9HmYAsC7TIS+OMxZsmO0QqAfWzJPP 29FpHOTKyeC2nOnOcXHebD8WpHk= -----END CERTIFICATE----- Trustwave Global ECC P256 Certification Authority ================================================= -----BEGIN CERTIFICATE----- MIICYDCCAgegAwIBAgIMDWpfCD8oXD5Rld9dMAoGCCqGSM49BAMCMIGRMQswCQYDVQQGEwJVUzER MA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRydXN0d2F2ZSBI b2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBFQ0MgUDI1NiBDZXJ0aWZp Y2F0aW9uIEF1dGhvcml0eTAeFw0xNzA4MjMxOTM1MTBaFw00MjA4MjMxOTM1MTBaMIGRMQswCQYD VQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRy dXN0d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBFQ0MgUDI1 NiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABH77bOYj 43MyCMpg5lOcunSNGLB4kFKA3TjASh3RqMyTpJcGOMoNFWLGjgEqZZ2q3zSRLoHB5DOSMcT9CTqm P62jQzBBMA8GA1UdEwEB/wQFMAMBAf8wDwYDVR0PAQH/BAUDAwcGADAdBgNVHQ4EFgQUo0EGrJBt 0UrrdaVKEJmzsaGLSvcwCgYIKoZIzj0EAwIDRwAwRAIgB+ZU2g6gWrKuEZ+Hxbb/ad4lvvigtwjz RM4q3wghDDcCIC0mA6AFvWvR9lz4ZcyGbbOcNEhjhAnFjXca4syc4XR7 -----END CERTIFICATE----- Trustwave Global ECC P384 Certification Authority ================================================= -----BEGIN CERTIFICATE----- MIICnTCCAiSgAwIBAgIMCL2Fl2yZJ6SAaEc7MAoGCCqGSM49BAMDMIGRMQswCQYDVQQGEwJVUzER MA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRydXN0d2F2ZSBI b2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBFQ0MgUDM4NCBDZXJ0aWZp Y2F0aW9uIEF1dGhvcml0eTAeFw0xNzA4MjMxOTM2NDNaFw00MjA4MjMxOTM2NDNaMIGRMQswCQYD VQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRy dXN0d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBFQ0MgUDM4 NCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTB2MBAGByqGSM49AgEGBSuBBAAiA2IABGvaDXU1CDFH Ba5FmVXxERMuSvgQMSOjfoPTfygIOiYaOs+Xgh+AtycJj9GOMMQKmw6sWASr9zZ9lCOkmwqKi6vr /TklZvFe/oyujUF5nQlgziip04pt89ZF1PKYhDhloKNDMEEwDwYDVR0TAQH/BAUwAwEB/zAPBgNV HQ8BAf8EBQMDBwYAMB0GA1UdDgQWBBRVqYSJ0sEyvRjLbKYHTsjnnb6CkDAKBggqhkjOPQQDAwNn ADBkAjA3AZKXRRJ+oPM+rRk6ct30UJMDEr5E0k9BpIycnR+j9sKS50gU/k6bpZFXrsY3crsCMGcl CrEMXu6pY5Jv5ZAL/mYiykf9ijH3g/56vxC+GCsej/YpHpRZ744hN8tRmKVuSw== -----END CERTIFICATE----- NAVER Global Root Certification Authority ========================================= -----BEGIN CERTIFICATE----- MIIFojCCA4qgAwIBAgIUAZQwHqIL3fXFMyqxQ0Rx+NZQTQ0wDQYJKoZIhvcNAQEMBQAwaTELMAkG A1UEBhMCS1IxJjAkBgNVBAoMHU5BVkVSIEJVU0lORVNTIFBMQVRGT1JNIENvcnAuMTIwMAYDVQQD DClOQVZFUiBHbG9iYWwgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0xNzA4MTgwODU4 NDJaFw0zNzA4MTgyMzU5NTlaMGkxCzAJBgNVBAYTAktSMSYwJAYDVQQKDB1OQVZFUiBCVVNJTkVT UyBQTEFURk9STSBDb3JwLjEyMDAGA1UEAwwpTkFWRVIgR2xvYmFsIFJvb3QgQ2VydGlmaWNhdGlv biBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC21PGTXLVAiQqrDZBb UGOukJR0F0Vy1ntlWilLp1agS7gvQnXp2XskWjFlqxcX0TM62RHcQDaH38dq6SZeWYp34+hInDEW +j6RscrJo+KfziFTowI2MMtSAuXaMl3Dxeb57hHHi8lEHoSTGEq0n+USZGnQJoViAbbJAh2+g1G7 XNr4rRVqmfeSVPc0W+m/6imBEtRTkZazkVrd/pBzKPswRrXKCAfHcXLJZtM0l/aM9BhK4dA9WkW2 aacp+yPOiNgSnABIqKYPszuSjXEOdMWLyEz59JuOuDxp7W87UC9Y7cSw0BwbagzivESq2M0UXZR4 Yb8ObtoqvC8MC3GmsxY/nOb5zJ9TNeIDoKAYv7vxvvTWjIcNQvcGufFt7QSUqP620wbGQGHfnZ3z VHbOUzoBppJB7ASjjw2i1QnK1sua8e9DXcCrpUHPXFNwcMmIpi3Ua2FzUCaGYQ5fG8Ir4ozVu53B A0K6lNpfqbDKzE0K70dpAy8i+/Eozr9dUGWokG2zdLAIx6yo0es+nPxdGoMuK8u180SdOqcXYZai cdNwlhVNt0xz7hlcxVs+Qf6sdWA7G2POAN3aCJBitOUt7kinaxeZVL6HSuOpXgRM6xBtVNbv8ejy YhbLgGvtPe31HzClrkvJE+2KAQHJuFFYwGY6sWZLxNUxAmLpdIQM201GLQIDAQABo0IwQDAdBgNV HQ4EFgQU0p+I36HNLL3s9TsBAZMzJ7LrYEswDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMB Af8wDQYJKoZIhvcNAQEMBQADggIBADLKgLOdPVQG3dLSLvCkASELZ0jKbY7gyKoNqo0hV4/GPnrK 21HUUrPUloSlWGB/5QuOH/XcChWB5Tu2tyIvCZwTFrFsDDUIbatjcu3cvuzHV+YwIHHW1xDBE1UB jCpD5EHxzzp6U5LOogMFDTjfArsQLtk70pt6wKGm+LUx5vR1yblTmXVHIloUFcd4G7ad6Qz4G3bx hYTeodoS76TiEJd6eN4MUZeoIUCLhr0N8F5OSza7OyAfikJW4Qsav3vQIkMsRIz75Sq0bBwcupTg E34h5prCy8VCZLQelHsIJchxzIdFV4XTnyliIoNRlwAYl3dqmJLJfGBs32x9SuRwTMKeuB330DTH D8z7p/8Dvq1wkNoL3chtl1+afwkyQf3NosxabUzyqkn+Zvjp2DXrDige7kgvOtB5CTh8piKCk5XQ A76+AqAF3SAi428diDRgxuYKuQl1C/AH6GmWNcf7I4GOODm4RStDeKLRLBT/DShycpWbXgnbiUSY qqFJu3FS8r/2/yehNq+4tneI3TqkbZs0kNwUXTC/t+sX5Ie3cdCh13cV1ELX8vMxmV2b3RZtP+oG I/hGoiLtk/bdmuYqh7GYVPEi92tF4+KOdh2ajcQGjTa3FPOdVGm3jjzVpG2Tgbet9r1ke8LJaDmg kpzNNIaRkPpkUZ3+/uul9XXeifdy -----END CERTIFICATE----- AC RAIZ FNMT-RCM SERVIDORES SEGUROS =================================== -----BEGIN CERTIFICATE----- MIICbjCCAfOgAwIBAgIQYvYybOXE42hcG2LdnC6dlTAKBggqhkjOPQQDAzB4MQswCQYDVQQGEwJF UzERMA8GA1UECgwIRk5NVC1SQ00xDjAMBgNVBAsMBUNlcmVzMRgwFgYDVQRhDA9WQVRFUy1RMjgy NjAwNEoxLDAqBgNVBAMMI0FDIFJBSVogRk5NVC1SQ00gU0VSVklET1JFUyBTRUdVUk9TMB4XDTE4 MTIyMDA5MzczM1oXDTQzMTIyMDA5MzczM1oweDELMAkGA1UEBhMCRVMxETAPBgNVBAoMCEZOTVQt UkNNMQ4wDAYDVQQLDAVDZXJlczEYMBYGA1UEYQwPVkFURVMtUTI4MjYwMDRKMSwwKgYDVQQDDCNB QyBSQUlaIEZOTVQtUkNNIFNFUlZJRE9SRVMgU0VHVVJPUzB2MBAGByqGSM49AgEGBSuBBAAiA2IA BPa6V1PIyqvfNkpSIeSX0oNnnvBlUdBeh8dHsVnyV0ebAAKTRBdp20LHsbI6GA60XYyzZl2hNPk2 LEnb80b8s0RpRBNm/dfF/a82Tc4DTQdxz69qBdKiQ1oKUm8BA06Oi6NCMEAwDwYDVR0TAQH/BAUw AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFAG5L++/EYZg8k/QQW6rcx/n0m5JMAoGCCqG SM49BAMDA2kAMGYCMQCuSuMrQMN0EfKVrRYj3k4MGuZdpSRea0R7/DjiT8ucRRcRTBQnJlU5dUoD zBOQn5ICMQD6SmxgiHPz7riYYqnOK8LZiqZwMR2vsJRM60/G49HzYqc8/5MuB1xJAWdpEgJyv+c= -----END CERTIFICATE----- GlobalSign Root R46 =================== -----BEGIN CERTIFICATE----- MIIFWjCCA0KgAwIBAgISEdK7udcjGJ5AXwqdLdDfJWfRMA0GCSqGSIb3DQEBDAUAMEYxCzAJBgNV BAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYDVQQDExNHbG9iYWxTaWduIFJv b3QgUjQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMyMDAwMDAwMFowRjELMAkGA1UEBhMCQkUxGTAX BgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExHDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBSNDYwggIi MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCsrHQy6LNl5brtQyYdpokNRbopiLKkHWPd08Es CVeJOaFV6Wc0dwxu5FUdUiXSE2te4R2pt32JMl8Nnp8semNgQB+msLZ4j5lUlghYruQGvGIFAha/ r6gjA7aUD7xubMLL1aa7DOn2wQL7Id5m3RerdELv8HQvJfTqa1VbkNud316HCkD7rRlr+/fKYIje 2sGP1q7Vf9Q8g+7XFkyDRTNrJ9CG0Bwta/OrffGFqfUo0q3v84RLHIf8E6M6cqJaESvWJ3En7YEt bWaBkoe0G1h6zD8K+kZPTXhc+CtI4wSEy132tGqzZfxCnlEmIyDLPRT5ge1lFgBPGmSXZgjPjHvj K8Cd+RTyG/FWaha/LIWFzXg4mutCagI0GIMXTpRW+LaCtfOW3T3zvn8gdz57GSNrLNRyc0NXfeD4 12lPFzYE+cCQYDdF3uYM2HSNrpyibXRdQr4G9dlkbgIQrImwTDsHTUB+JMWKmIJ5jqSngiCNI/on ccnfxkF0oE32kRbcRoxfKWMxWXEM2G/CtjJ9++ZdU6Z+Ffy7dXxd7Pj2Fxzsx2sZy/N78CsHpdls eVR2bJ0cpm4O6XkMqCNqo98bMDGfsVR7/mrLZqrcZdCinkqaByFrgY/bxFn63iLABJzjqls2k+g9 vXqhnQt2sQvHnf3PmKgGwvgqo6GDoLclcqUC4wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYD VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA1yrc4GHqMywptWU4jaWSf8FmSwwDQYJKoZIhvcNAQEM BQADggIBAHx47PYCLLtbfpIrXTncvtgdokIzTfnvpCo7RGkerNlFo048p9gkUbJUHJNOxO97k4Vg JuoJSOD1u8fpaNK7ajFxzHmuEajwmf3lH7wvqMxX63bEIaZHU1VNaL8FpO7XJqti2kM3S+LGteWy gxk6x9PbTZ4IevPuzz5i+6zoYMzRx6Fcg0XERczzF2sUyQQCPtIkpnnpHs6i58FZFZ8d4kuaPp92 CC1r2LpXFNqD6v6MVenQTqnMdzGxRBF6XLE+0xRFFRhiJBPSy03OXIPBNvIQtQ6IbbjhVp+J3pZm OUdkLG5NrmJ7v2B0GbhWrJKsFjLtrWhV/pi60zTe9Mlhww6G9kuEYO4Ne7UyWHmRVSyBQ7N0H3qq JZ4d16GLuc1CLgSkZoNNiTW2bKg2SnkheCLQQrzRQDGQob4Ez8pn7fXwgNNgyYMqIgXQBztSvwye qiv5u+YfjyW6hY0XHgL+XVAEV8/+LbzvXMAaq7afJMbfc2hIkCwU9D9SGuTSyxTDYWnP4vkYxboz nxSjBF25cfe1lNj2M8FawTSLfJvdkzrnE6JwYZ+vj+vYxXX4M2bUdGc6N3ec592kD3ZDZopD8p/7 DEJ4Y9HiD2971KE9dJeFt0g5QdYg/NA6s/rob8SKunE3vouXsXgxT7PntgMTzlSdriVZzH81Xwj3 QEUxeCp6 -----END CERTIFICATE----- GlobalSign Root E46 =================== -----BEGIN CERTIFICATE----- MIICCzCCAZGgAwIBAgISEdK7ujNu1LzmJGjFDYQdmOhDMAoGCCqGSM49BAMDMEYxCzAJBgNVBAYT AkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYDVQQDExNHbG9iYWxTaWduIFJvb3Qg RTQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMyMDAwMDAwMFowRjELMAkGA1UEBhMCQkUxGTAXBgNV BAoTEEdsb2JhbFNpZ24gbnYtc2ExHDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBFNDYwdjAQBgcq hkjOPQIBBgUrgQQAIgNiAAScDrHPt+ieUnd1NPqlRqetMhkytAepJ8qUuwzSChDH2omwlwxwEwkB jtjqR+q+soArzfwoDdusvKSGN+1wCAB16pMLey5SnCNoIwZD7JIvU4Tb+0cUB+hflGddyXqBPCCj QjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBQxCpCPtsad0kRL gLWi5h+xEk8blTAKBggqhkjOPQQDAwNoADBlAjEA31SQ7Zvvi5QCkxeCmb6zniz2C5GMn0oUsfZk vLtoURMMA/cVi4RguYv/Uo7njLwcAjA8+RHUjE7AwWHCFUyqqx0LMV87HOIAl0Qx5v5zli/altP+ CAezNIm8BZ/3Hobui3A= -----END CERTIFICATE----- GLOBALTRUST 2020 ================ -----BEGIN CERTIFICATE----- MIIFgjCCA2qgAwIBAgILWku9WvtPilv6ZeUwDQYJKoZIhvcNAQELBQAwTTELMAkGA1UEBhMCQVQx IzAhBgNVBAoTGmUtY29tbWVyY2UgbW9uaXRvcmluZyBHbWJIMRkwFwYDVQQDExBHTE9CQUxUUlVT VCAyMDIwMB4XDTIwMDIxMDAwMDAwMFoXDTQwMDYxMDAwMDAwMFowTTELMAkGA1UEBhMCQVQxIzAh BgNVBAoTGmUtY29tbWVyY2UgbW9uaXRvcmluZyBHbWJIMRkwFwYDVQQDExBHTE9CQUxUUlVTVCAy MDIwMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAri5WrRsc7/aVj6B3GyvTY4+ETUWi D59bRatZe1E0+eyLinjF3WuvvcTfk0Uev5E4C64OFudBc/jbu9G4UeDLgztzOG53ig9ZYybNpyrO VPu44sB8R85gfD+yc/LAGbaKkoc1DZAoouQVBGM+uq/ufF7MpotQsjj3QWPKzv9pj2gOlTblzLmM CcpL3TGQlsjMH/1WljTbjhzqLL6FLmPdqqmV0/0plRPwyJiT2S0WR5ARg6I6IqIoV6Lr/sCMKKCm fecqQjuCgGOlYx8ZzHyyZqjC0203b+J+BlHZRYQfEs4kUmSFC0iAToexIiIwquuuvuAC4EDosEKA A1GqtH6qRNdDYfOiaxaJSaSjpCuKAsR49GiKweR6NrFvG5Ybd0mN1MkGco/PU+PcF4UgStyYJ9OR JitHHmkHr96i5OTUawuzXnzUJIBHKWk7buis/UDr2O1xcSvy6Fgd60GXIsUf1DnQJ4+H4xj04KlG DfV0OoIu0G4skaMxXDtG6nsEEFZegB31pWXogvziB4xiRfUg3kZwhqG8k9MedKZssCz3AwyIDMvU clOGvGBG85hqwvG/Q/lwIHfKN0F5VVJjjVsSn8VoxIidrPIwq7ejMZdnrY8XD2zHc+0klGvIg5rQ mjdJBKuxFshsSUktq6HQjJLyQUp5ISXbY9e2nKd+Qmn7OmMCAwEAAaNjMGEwDwYDVR0TAQH/BAUw AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFNwuH9FhN3nkq9XVsxJxaD1qaJwiMB8GA1Ud IwQYMBaAFNwuH9FhN3nkq9XVsxJxaD1qaJwiMA0GCSqGSIb3DQEBCwUAA4ICAQCR8EICaEDuw2jA VC/f7GLDw56KoDEoqoOOpFaWEhCGVrqXctJUMHytGdUdaG/7FELYjQ7ztdGl4wJCXtzoRlgHNQIw 4Lx0SsFDKv/bGtCwr2zD/cuz9X9tAy5ZVp0tLTWMstZDFyySCstd6IwPS3BD0IL/qMy/pJTAvoe9 iuOTe8aPmxadJ2W8esVCgmxcB9CpwYhgROmYhRZf+I/KARDOJcP5YBugxZfD0yyIMaK9MOzQ0MAS 8cE54+X1+NZK3TTN+2/BT+MAi1bikvcoskJ3ciNnxz8RFbLEAwW+uxF7Cr+obuf/WEPPm2eggAe2 HcqtbepBEX4tdJP7wry+UUTF72glJ4DjyKDUEuzZpTcdN3y0kcra1LGWge9oXHYQSa9+pTeAsRxS vTOBTI/53WXZFM2KJVj04sWDpQmQ1GwUY7VA3+vA/MRYfg0UFodUJ25W5HCEuGwyEn6CMUO+1918 oa2u1qsgEu8KwxCMSZY13At1XrFP1U80DhEgB3VDRemjEdqso5nCtnkn4rnvyOL2NSl6dPrFf4IF YqYK6miyeUcGbvJXqBUzxvd4Sj1Ce2t+/vdG6tHrju+IaFvowdlxfv1k7/9nR4hYJS8+hge9+6jl gqispdNpQ80xiEmEU5LAsTkbOYMBMMTyqfrQA71yN2BWHzZ8vTmR9W0Nv3vXkg== -----END CERTIFICATE----- ANF Secure Server Root CA ========================= -----BEGIN CERTIFICATE----- MIIF7zCCA9egAwIBAgIIDdPjvGz5a7EwDQYJKoZIhvcNAQELBQAwgYQxEjAQBgNVBAUTCUc2MzI4 NzUxMDELMAkGA1UEBhMCRVMxJzAlBgNVBAoTHkFORiBBdXRvcmlkYWQgZGUgQ2VydGlmaWNhY2lv bjEUMBIGA1UECxMLQU5GIENBIFJhaXoxIjAgBgNVBAMTGUFORiBTZWN1cmUgU2VydmVyIFJvb3Qg Q0EwHhcNMTkwOTA0MTAwMDM4WhcNMzkwODMwMTAwMDM4WjCBhDESMBAGA1UEBRMJRzYzMjg3NTEw MQswCQYDVQQGEwJFUzEnMCUGA1UEChMeQU5GIEF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uMRQw EgYDVQQLEwtBTkYgQ0EgUmFpejEiMCAGA1UEAxMZQU5GIFNlY3VyZSBTZXJ2ZXIgUm9vdCBDQTCC AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANvrayvmZFSVgpCjcqQZAZ2cC4Ffc0m6p6zz BE57lgvsEeBbphzOG9INgxwruJ4dfkUyYA8H6XdYfp9qyGFOtibBTI3/TO80sh9l2Ll49a2pcbnv T1gdpd50IJeh7WhM3pIXS7yr/2WanvtH2Vdy8wmhrnZEE26cLUQ5vPnHO6RYPUG9tMJJo8gN0pcv B2VSAKduyK9o7PQUlrZXH1bDOZ8rbeTzPvY1ZNoMHKGESy9LS+IsJJ1tk0DrtSOOMspvRdOoiXse zx76W0OLzc2oD2rKDF65nkeP8Nm2CgtYZRczuSPkdxl9y0oukntPLxB3sY0vaJxizOBQ+OyRp1RM VwnVdmPF6GUe7m1qzwmd+nxPrWAI/VaZDxUse6mAq4xhj0oHdkLePfTdsiQzW7i1o0TJrH93PB0j 7IKppuLIBkwC/qxcmZkLLxCKpvR/1Yd0DVlJRfbwcVw5Kda/SiOL9V8BY9KHcyi1Swr1+KuCLH5z JTIdC2MKF4EA/7Z2Xue0sUDKIbvVgFHlSFJnLNJhiQcND85Cd8BEc5xEUKDbEAotlRyBr+Qc5RQe 8TZBAQIvfXOn3kLMTOmJDVb3n5HUA8ZsyY/b2BzgQJhdZpmYgG4t/wHFzstGH6wCxkPmrqKEPMVO Hj1tyRRM4y5Bu8o5vzY8KhmqQYdOpc5LMnndkEl/AgMBAAGjYzBhMB8GA1UdIwQYMBaAFJxf0Gxj o1+TypOYCK2Mh6UsXME3MB0GA1UdDgQWBBScX9BsY6Nfk8qTmAitjIelLFzBNzAOBgNVHQ8BAf8E BAMCAYYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEATh65isagmD9uw2nAalxJ UqzLK114OMHVVISfk/CHGT0sZonrDUL8zPB1hT+L9IBdeeUXZ701guLyPI59WzbLWoAAKfLOKyzx j6ptBZNscsdW699QIyjlRRA96Gejrw5VD5AJYu9LWaL2U/HANeQvwSS9eS9OICI7/RogsKQOLHDt dD+4E5UGUcjohybKpFtqFiGS3XNgnhAY3jyB6ugYw3yJ8otQPr0R4hUDqDZ9MwFsSBXXiJCZBMXM 5gf0vPSQ7RPi6ovDj6MzD8EpTBNO2hVWcXNyglD2mjN8orGoGjR0ZVzO0eurU+AagNjqOknkJjCb 5RyKqKkVMoaZkgoQI1YS4PbOTOK7vtuNknMBZi9iPrJyJ0U27U1W45eZ/zo1PqVUSlJZS2Db7v54 EX9K3BR5YLZrZAPbFYPhor72I5dQ8AkzNqdxliXzuUJ92zg/LFis6ELhDtjTO0wugumDLmsx2d1H hk9tl5EuT+IocTUW0fJz/iUrB0ckYyfI+PbZa/wSMVYIwFNCr5zQM378BvAxRAMU8Vjq8moNqRGy g77FGr8H6lnco4g175x2MjxNBiLOFeXdntiP2t7SxDnlF4HPOEfrf4htWRvfn0IUrn7PqLBmZdo3 r5+qPeoott7VMVgWglvquxl1AnMaykgaIZOQCo6ThKd9OyMYkomgjaw= -----END CERTIFICATE----- Certum EC-384 CA ================ -----BEGIN CERTIFICATE----- MIICZTCCAeugAwIBAgIQeI8nXIESUiClBNAt3bpz9DAKBggqhkjOPQQDAzB0MQswCQYDVQQGEwJQ TDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2Vy dGlmaWNhdGlvbiBBdXRob3JpdHkxGTAXBgNVBAMTEENlcnR1bSBFQy0zODQgQ0EwHhcNMTgwMzI2 MDcyNDU0WhcNNDMwMzI2MDcyNDU0WjB0MQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERh dGEgU3lzdGVtcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkx GTAXBgNVBAMTEENlcnR1bSBFQy0zODQgQ0EwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAATEKI6rGFtq vm5kN2PkzeyrOvfMobgOgknXhimfoZTy42B4mIF4Bk3y7JoOV2CDn7TmFy8as10CW4kjPMIRBSqn iBMY81CE1700LCeJVf/OTOffph8oxPBUw7l8t1Ot68KjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD VR0OBBYEFI0GZnQkdjrzife81r1HfS+8EF9LMA4GA1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNo ADBlAjADVS2m5hjEfO/JUG7BJw+ch69u1RsIGL2SKcHvlJF40jocVYli5RsJHrpka/F2tNQCMQC0 QoSZ/6vnnvuRlydd3LBbMHHOXjgaatkl5+r3YZJW+OraNsKHZZYuciUvf9/DE8k= -----END CERTIFICATE----- Certum Trusted Root CA ====================== -----BEGIN CERTIFICATE----- MIIFwDCCA6igAwIBAgIQHr9ZULjJgDdMBvfrVU+17TANBgkqhkiG9w0BAQ0FADB6MQswCQYDVQQG EwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0g Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkxHzAdBgNVBAMTFkNlcnR1bSBUcnVzdGVkIFJvb3QgQ0Ew HhcNMTgwMzE2MTIxMDEzWhcNNDMwMzE2MTIxMDEzWjB6MQswCQYDVQQGEwJQTDEhMB8GA1UEChMY QXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBB dXRob3JpdHkxHzAdBgNVBAMTFkNlcnR1bSBUcnVzdGVkIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEB AQUAA4ICDwAwggIKAoICAQDRLY67tzbqbTeRn06TpwXkKQMlzhyC93yZn0EGze2jusDbCSzBfN8p fktlL5On1AFrAygYo9idBcEq2EXxkd7fO9CAAozPOA/qp1x4EaTByIVcJdPTsuclzxFUl6s1wB52 HO8AU5853BSlLCIls3Jy/I2z5T4IHhQqNwuIPMqw9MjCoa68wb4pZ1Xi/K1ZXP69VyywkI3C7Te2 fJmItdUDmj0VDT06qKhF8JVOJVkdzZhpu9PMMsmN74H+rX2Ju7pgE8pllWeg8xn2A1bUatMn4qGt g/BKEiJ3HAVz4hlxQsDsdUaakFjgao4rpUYwBI4Zshfjvqm6f1bxJAPXsiEodg42MEx51UGamqi4 NboMOvJEGyCI98Ul1z3G4z5D3Yf+xOr1Uz5MZf87Sst4WmsXXw3Hw09Omiqi7VdNIuJGmj8PkTQk fVXjjJU30xrwCSss0smNtA0Aq2cpKNgB9RkEth2+dv5yXMSFytKAQd8FqKPVhJBPC/PgP5sZ0jeJ P/J7UhyM9uH3PAeXjA6iWYEMspA90+NZRu0PqafegGtaqge2Gcu8V/OXIXoMsSt0Puvap2ctTMSY njYJdmZm/Bo/6khUHL4wvYBQv3y1zgD2DGHZ5yQD4OMBgQ692IU0iL2yNqh7XAjlRICMb/gv1SHK HRzQ+8S1h9E6Tsd2tTVItQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSM+xx1 vALTn04uSNn5YFSqxLNP+jAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQENBQADggIBAEii1QAL LtA/vBzVtVRJHlpr9OTy4EA34MwUe7nJ+jW1dReTagVphZzNTxl4WxmB82M+w85bj/UvXgF2Ez8s ALnNllI5SW0ETsXpD4YN4fqzX4IS8TrOZgYkNCvozMrnadyHncI013nR03e4qllY/p0m+jiGPp2K h2RX5Rc64vmNueMzeMGQ2Ljdt4NR5MTMI9UGfOZR0800McD2RrsLrfw9EAUqO0qRJe6M1ISHgCq8 CYyqOhNf6DR5UMEQGfnTKB7U0VEwKbOukGfWHwpjscWpxkIxYxeU72nLL/qMFH3EQxiJ2fAyQOaA 4kZf5ePBAFmo+eggvIksDkc0C+pXwlM2/KfUrzHN/gLldfq5Jwn58/U7yn2fqSLLiMmq0Uc9Nneo WWRrJ8/vJ8HjJLWG965+Mk2weWjROeiQWMODvA8s1pfrzgzhIMfatz7DP78v3DSk+yshzWePS/Tj 6tQ/50+6uaWTRRxmHyH6ZF5v4HaUMst19W7l9o/HuKTMqJZ9ZPskWkoDbGs4xugDQ5r3V7mzKWmT OPQD8rv7gmsHINFSH5pkAnuYZttcTVoP0ISVoDwUQwbKytu4QTbaakRnh6+v40URFWkIsr4WOZck bxJF0WddCajJFdr60qZfE2Efv4WstK2tBZQIgx51F9NxO5NQI1mg7TyRVJ12AMXDuDjb -----END CERTIFICATE----- TunTrust Root CA ================ -----BEGIN CERTIFICATE----- MIIFszCCA5ugAwIBAgIUEwLV4kBMkkaGFmddtLu7sms+/BMwDQYJKoZIhvcNAQELBQAwYTELMAkG A1UEBhMCVE4xNzA1BgNVBAoMLkFnZW5jZSBOYXRpb25hbGUgZGUgQ2VydGlmaWNhdGlvbiBFbGVj dHJvbmlxdWUxGTAXBgNVBAMMEFR1blRydXN0IFJvb3QgQ0EwHhcNMTkwNDI2MDg1NzU2WhcNNDQw NDI2MDg1NzU2WjBhMQswCQYDVQQGEwJUTjE3MDUGA1UECgwuQWdlbmNlIE5hdGlvbmFsZSBkZSBD ZXJ0aWZpY2F0aW9uIEVsZWN0cm9uaXF1ZTEZMBcGA1UEAwwQVHVuVHJ1c3QgUm9vdCBDQTCCAiIw DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMPN0/y9BFPdDCA61YguBUtB9YOCfvdZn56eY+hz 2vYGqU8ftPkLHzmMmiDQfgbU7DTZhrx1W4eI8NLZ1KMKsmwb60ksPqxd2JQDoOw05TDENX37Jk0b bjBU2PWARZw5rZzJJQRNmpA+TkBuimvNKWfGzC3gdOgFVwpIUPp6Q9p+7FuaDmJ2/uqdHYVy7BG7 NegfJ7/Boce7SBbdVtfMTqDhuazb1YMZGoXRlJfXyqNlC/M4+QKu3fZnz8k/9YosRxqZbwUN/dAd gjH8KcwAWJeRTIAAHDOFli/LQcKLEITDCSSJH7UP2dl3RxiSlGBcx5kDPP73lad9UKGAwqmDrViW VSHbhlnUr8a83YFuB9tgYv7sEG7aaAH0gxupPqJbI9dkxt/con3YS7qC0lH4Zr8GRuR5KiY2eY8f Tpkdso8MDhz/yV3A/ZAQprE38806JG60hZC/gLkMjNWb1sjxVj8agIl6qeIbMlEsPvLfe/ZdeikZ juXIvTZxi11Mwh0/rViizz1wTaZQmCXcI/m4WEEIcb9PuISgjwBUFfyRbVinljvrS5YnzWuioYas DXxU5mZMZl+QviGaAkYt5IPCgLnPSz7ofzwB7I9ezX/SKEIBlYrilz0QIX32nRzFNKHsLA4KUiwS VXAkPcvCFDVDXSdOvsC9qnyW5/yeYa1E0wCXAgMBAAGjYzBhMB0GA1UdDgQWBBQGmpsfU33x9aTI 04Y+oXNZtPdEITAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFAaamx9TffH1pMjThj6hc1m0 90QhMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAqgVutt0Vyb+zxiD2BkewhpMl 0425yAA/l/VSJ4hxyXT968pk21vvHl26v9Hr7lxpuhbI87mP0zYuQEkHDVneixCwSQXi/5E/S7fd Ao74gShczNxtr18UnH1YeA32gAm56Q6XKRm4t+v4FstVEuTGfbvE7Pi1HE4+Z7/FXxttbUcoqgRY YdZ2vyJ/0Adqp2RT8JeNnYA/u8EH22Wv5psymsNUk8QcCMNE+3tjEUPRahphanltkE8pjkcFwRJp adbGNjHh/PqAulxPxOu3Mqz4dWEX1xAZufHSCe96Qp1bWgvUxpVOKs7/B9dPfhgGiPEZtdmYu65x xBzndFlY7wyJz4sfdZMaBBSSSFCp61cpABbjNhzI+L/wM9VBD8TMPN3pM0MBkRArHtG5Xc0yGYuP jCB31yLEQtyEFpslbei0VXF/sHyz03FJuc9SpAQ/3D2gu68zngowYI7bnV2UqL1g52KAdoGDDIzM MEZJ4gzSqK/rYXHv5yJiqfdcZGyfFoxnNidF9Ql7v/YQCvGwjVRDjAS6oz/v4jXH+XTgbzRB0L9z ZVcg+ZtnemZoJE6AZb0QmQZZ8mWvuMZHu/2QeItBcy6vVR/cO5JyboTT0GFMDcx2V+IthSIVNg3r AZ3r2OvEhJn7wAzMMujjd9qDRIueVSjAi1jTkD5OGwDxFa2DK5o= -----END CERTIFICATE----- HARICA TLS RSA Root CA 2021 =========================== -----BEGIN CERTIFICATE----- MIIFpDCCA4ygAwIBAgIQOcqTHO9D88aOk8f0ZIk4fjANBgkqhkiG9w0BAQsFADBsMQswCQYDVQQG EwJHUjE3MDUGA1UECgwuSGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9u cyBDQTEkMCIGA1UEAwwbSEFSSUNBIFRMUyBSU0EgUm9vdCBDQSAyMDIxMB4XDTIxMDIxOTEwNTUz OFoXDTQ1MDIxMzEwNTUzN1owbDELMAkGA1UEBhMCR1IxNzA1BgNVBAoMLkhlbGxlbmljIEFjYWRl bWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ0ExJDAiBgNVBAMMG0hBUklDQSBUTFMgUlNB IFJvb3QgQ0EgMjAyMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAIvC569lmwVnlskN JLnQDmT8zuIkGCyEf3dRywQRNrhe7Wlxp57kJQmXZ8FHws+RFjZiPTgE4VGC/6zStGndLuwRo0Xu a2s7TL+MjaQenRG56Tj5eg4MmOIjHdFOY9TnuEFE+2uva9of08WRiFukiZLRgeaMOVig1mlDqa2Y Ulhu2wr7a89o+uOkXjpFc5gH6l8Cct4MpbOfrqkdtx2z/IpZ525yZa31MJQjB/OCFks1mJxTuy/K 5FrZx40d/JiZ+yykgmvwKh+OC19xXFyuQnspiYHLA6OZyoieC0AJQTPb5lh6/a6ZcMBaD9YThnEv dmn8kN3bLW7R8pv1GmuebxWMevBLKKAiOIAkbDakO/IwkfN4E8/BPzWr8R0RI7VDIp4BkrcYAuUR 0YLbFQDMYTfBKnya4dC6s1BG7oKsnTH4+yPiAwBIcKMJJnkVU2DzOFytOOqBAGMUuTNe3QvboEUH GjMJ+E20pwKmafTCWQWIZYVWrkvL4N48fS0ayOn7H6NhStYqE613TBoYm5EPWNgGVMWX+Ko/IIqm haZ39qb8HOLubpQzKoNQhArlT4b4UEV4AIHrW2jjJo3Me1xR9BQsQL4aYB16cmEdH2MtiKrOokWQ CPxrvrNQKlr9qEgYRtaQQJKQCoReaDH46+0N0x3GfZkYVVYnZS6NRcUk7M7jAgMBAAGjQjBAMA8G A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFApII6ZgpJIKM+qTW8VX6iVNvRLuMA4GA1UdDwEB/wQE AwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAPpBIqm5iFSVmewzVjIuJndftTgfvnNAUX15QvWiWkKQU EapobQk1OUAJ2vQJLDSle1mESSmXdMgHHkdt8s4cUCbjnj1AUz/3f5Z2EMVGpdAgS1D0NTsY9FVq QRtHBmg8uwkIYtlfVUKqrFOFrJVWNlar5AWMxajaH6NpvVMPxP/cyuN+8kyIhkdGGvMA9YCRotxD QpSbIPDRzbLrLFPCU3hKTwSUQZqPJzLB5UkZv/HywouoCjkxKLR9YjYsTewfM7Z+d21+UPCfDtcR j88YxeMn/ibvBZ3PzzfF0HvaO7AWhAw6k9a+F9sPPg4ZeAnHqQJyIkv3N3a6dcSFA1pj1bF1BcK5 vZStjBWZp5N99sXzqnTPBIWUmAD04vnKJGW/4GKvyMX6ssmeVkjaef2WdhW+o45WxLM0/L5H9MG0 qPzVMIho7suuyWPEdr6sOBjhXlzPrjoiUevRi7PzKzMHVIf6tLITe7pTBGIBnfHAT+7hOtSLIBD6 Alfm78ELt5BGnBkpjNxvoEppaZS3JGWg/6w/zgH7IS79aPib8qXPMThcFarmlwDB31qlpzmq6YR/ PFGoOtmUW4y/Twhx5duoXNTSpv4Ao8YWxw/ogM4cKGR0GQjTQuPOAF1/sdwTsOEFy9EgqoZ0njnn kf3/W9b3raYvAwtt41dU63ZTGI0RmLo= -----END CERTIFICATE----- HARICA TLS ECC Root CA 2021 =========================== -----BEGIN CERTIFICATE----- MIICVDCCAdugAwIBAgIQZ3SdjXfYO2rbIvT/WeK/zjAKBggqhkjOPQQDAzBsMQswCQYDVQQGEwJH UjE3MDUGA1UECgwuSGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBD QTEkMCIGA1UEAwwbSEFSSUNBIFRMUyBFQ0MgUm9vdCBDQSAyMDIxMB4XDTIxMDIxOTExMDExMFoX DTQ1MDIxMzExMDEwOVowbDELMAkGA1UEBhMCR1IxNzA1BgNVBAoMLkhlbGxlbmljIEFjYWRlbWlj IGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ0ExJDAiBgNVBAMMG0hBUklDQSBUTFMgRUNDIFJv b3QgQ0EgMjAyMTB2MBAGByqGSM49AgEGBSuBBAAiA2IABDgI/rGgltJ6rK9JOtDA4MM7KKrxcm1l AEeIhPyaJmuqS7psBAqIXhfyVYf8MLA04jRYVxqEU+kw2anylnTDUR9YSTHMmE5gEYd103KUkE+b ECUqqHgtvpBBWJAVcqeht6NCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUyRtTgRL+BNUW 0aq8mm+3oJUZbsowDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMDA2cAMGQCMBHervjcToiwqfAi rcJRQO9gcS3ujwLEXQNwSaSS6sUUiHCm0w2wqsosQJz76YJumgIwK0eaB8bRwoF8yguWGEEbo/Qw CZ61IygNnxS2PFOiTAZpffpskcYqSUXm7LcT4Tps -----END CERTIFICATE----- Autoridad de Certificacion Firmaprofesional CIF A62634068 ========================================================= -----BEGIN CERTIFICATE----- MIIGFDCCA/ygAwIBAgIIG3Dp0v+ubHEwDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCRVMxQjBA BgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2 MjYzNDA2ODAeFw0xNDA5MjMxNTIyMDdaFw0zNjA1MDUxNTIyMDdaMFExCzAJBgNVBAYTAkVTMUIw QAYDVQQDDDlBdXRvcmlkYWQgZGUgQ2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBB NjI2MzQwNjgwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDD Utd9thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQMcas9UX4P B99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefGL9ItWY16Ck6WaVICqjaY 7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15iNA9wBj4gGFrO93IbJWyTdBSTo3OxDqqH ECNZXyAFGUftaI6SEspd/NYrspI8IM/hX68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyI plD9amML9ZMWGxmPsu2bm8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctX MbScyJCyZ/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirjaEbsX LZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/TKI8xWVvTyQKmtFLK bpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF6NkBiDkal4ZkQdU7hwxu+g/GvUgU vzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVhOSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMB0GA1Ud DgQWBBRlzeurNR4APn7VdMActHNHDhpkLzASBgNVHRMBAf8ECDAGAQH/AgEBMIGmBgNVHSAEgZ4w gZswgZgGBFUdIAAwgY8wLwYIKwYBBQUHAgEWI2h0dHA6Ly93d3cuZmlybWFwcm9mZXNpb25hbC5j b20vY3BzMFwGCCsGAQUFBwICMFAeTgBQAGEAcwBlAG8AIABkAGUAIABsAGEAIABCAG8AbgBhAG4A bwB2AGEAIAA0ADcAIABCAGEAcgBjAGUAbABvAG4AYQAgADAAOAAwADEANzAOBgNVHQ8BAf8EBAMC AQYwDQYJKoZIhvcNAQELBQADggIBAHSHKAIrdx9miWTtj3QuRhy7qPj4Cx2Dtjqn6EWKB7fgPiDL 4QjbEwj4KKE1soCzC1HA01aajTNFSa9J8OA9B3pFE1r/yJfY0xgsfZb43aJlQ3CTkBW6kN/oGbDb LIpgD7dvlAceHabJhfa9NPhAeGIQcDq+fUs5gakQ1JZBu/hfHAsdCPKxsIl68veg4MSPi3i1O1il I45PVf42O+AMt8oqMEEgtIDNrvx2ZnOorm7hfNoD6JQg5iKj0B+QXSBTFCZX2lSX3xZEEAEeiGaP cjiT3SC3NL7X8e5jjkd5KAb881lFJWAiMxujX6i6KtoaPc1A6ozuBRWV1aUsIC+nmCjuRfzxuIgA LI9C2lHVnOUTaHFFQ4ueCyE8S1wF3BqfmI7avSKecs2tCsvMo2ebKHTEm9caPARYpoKdrcd7b/+A lun4jWq9GJAd/0kakFI3ky88Al2CdgtR5xbHV/g4+afNmyJU72OwFW1TZQNKXkqgsqeOSQBZONXH 9IBk9W6VULgRfhVwOEqwf9DEMnDAGf/JOC0ULGb0QkTmVXYbgBVX/8Cnp6o5qtjTcNAuuuuUavpf NIbnYrX9ivAwhZTJryQCL2/W3Wf+47BVTwSYT6RBVuKT0Gro1vP7ZeDOdcQxWQzugsgMYDNKGbqE ZycPvEJdvSRUDewdcAZfpLz6IHxV -----END CERTIFICATE----- vTrus ECC Root CA ================= -----BEGIN CERTIFICATE----- MIICDzCCAZWgAwIBAgIUbmq8WapTvpg5Z6LSa6Q75m0c1towCgYIKoZIzj0EAwMwRzELMAkGA1UE BhMCQ04xHDAaBgNVBAoTE2lUcnVzQ2hpbmEgQ28uLEx0ZC4xGjAYBgNVBAMTEXZUcnVzIEVDQyBS b290IENBMB4XDTE4MDczMTA3MjY0NFoXDTQzMDczMTA3MjY0NFowRzELMAkGA1UEBhMCQ04xHDAa BgNVBAoTE2lUcnVzQ2hpbmEgQ28uLEx0ZC4xGjAYBgNVBAMTEXZUcnVzIEVDQyBSb290IENBMHYw EAYHKoZIzj0CAQYFK4EEACIDYgAEZVBKrox5lkqqHAjDo6LN/llWQXf9JpRCux3NCNtzslt188+c ToL0v/hhJoVs1oVbcnDS/dtitN9Ti72xRFhiQgnH+n9bEOf+QP3A2MMrMudwpremIFUde4BdS49n TPEQo0IwQDAdBgNVHQ4EFgQUmDnNvtiyjPeyq+GtJK97fKHbH88wDwYDVR0TAQH/BAUwAwEB/zAO BgNVHQ8BAf8EBAMCAQYwCgYIKoZIzj0EAwMDaAAwZQIwV53dVvHH4+m4SVBrm2nDb+zDfSXkV5UT QJtS0zvzQBm8JsctBp61ezaf9SXUY2sAAjEA6dPGnlaaKsyh2j/IZivTWJwghfqrkYpwcBE4YGQL YgmRWAD5Tfs0aNoJrSEGGJTO -----END CERTIFICATE----- vTrus Root CA ============= -----BEGIN CERTIFICATE----- MIIFVjCCAz6gAwIBAgIUQ+NxE9izWRRdt86M/TX9b7wFjUUwDQYJKoZIhvcNAQELBQAwQzELMAkG A1UEBhMCQ04xHDAaBgNVBAoTE2lUcnVzQ2hpbmEgQ28uLEx0ZC4xFjAUBgNVBAMTDXZUcnVzIFJv b3QgQ0EwHhcNMTgwNzMxMDcyNDA1WhcNNDMwNzMxMDcyNDA1WjBDMQswCQYDVQQGEwJDTjEcMBoG A1UEChMTaVRydXNDaGluYSBDby4sTHRkLjEWMBQGA1UEAxMNdlRydXMgUm9vdCBDQTCCAiIwDQYJ KoZIhvcNAQEBBQADggIPADCCAgoCggIBAL1VfGHTuB0EYgWgrmy3cLRB6ksDXhA/kFocizuwZots SKYcIrrVQJLuM7IjWcmOvFjai57QGfIvWcaMY1q6n6MLsLOaXLoRuBLpDLvPbmyAhykUAyyNJJrI ZIO1aqwTLDPxn9wsYTwaP3BVm60AUn/PBLn+NvqcwBauYv6WTEN+VRS+GrPSbcKvdmaVayqwlHeF XgQPYh1jdfdr58tbmnDsPmcF8P4HCIDPKNsFxhQnL4Z98Cfe/+Z+M0jnCx5Y0ScrUw5XSmXX+6KA YPxMvDVTAWqXcoKv8R1w6Jz1717CbMdHflqUhSZNO7rrTOiwCcJlwp2dCZtOtZcFrPUGoPc2BX70 kLJrxLT5ZOrpGgrIDajtJ8nU57O5q4IikCc9Kuh8kO+8T/3iCiSn3mUkpF3qwHYw03dQ+A0Em5Q2 AXPKBlim0zvc+gRGE1WKyURHuFE5Gi7oNOJ5y1lKCn+8pu8fA2dqWSslYpPZUxlmPCdiKYZNpGvu /9ROutW04o5IWgAZCfEF2c6Rsffr6TlP9m8EQ5pV9T4FFL2/s1m02I4zhKOQUqqzApVg+QxMaPnu 1RcN+HFXtSXkKe5lXa/R7jwXC1pDxaWG6iSe4gUH3DRCEpHWOXSuTEGC2/KmSNGzm/MzqvOmwMVO 9fSddmPmAsYiS8GVP1BkLFTltvA8Kc9XAgMBAAGjQjBAMB0GA1UdDgQWBBRUYnBj8XWEQ1iO0RYg scasGrz2iTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOC AgEAKbqSSaet8PFww+SX8J+pJdVrnjT+5hpk9jprUrIQeBqfTNqK2uwcN1LgQkv7bHbKJAs5EhWd nxEt/Hlk3ODg9d3gV8mlsnZwUKT+twpw1aA08XXXTUm6EdGz2OyC/+sOxL9kLX1jbhd47F18iMjr jld22VkE+rxSH0Ws8HqA7Oxvdq6R2xCOBNyS36D25q5J08FsEhvMKar5CKXiNxTKsbhm7xqC5PD4 8acWabfbqWE8n/Uxy+QARsIvdLGx14HuqCaVvIivTDUHKgLKeBRtRytAVunLKmChZwOgzoy8sHJn xDHO2zTlJQNgJXtxmOTAGytfdELSS8VZCAeHvsXDf+eW2eHcKJfWjwXj9ZtOyh1QRwVTsMo554Wg icEFOwE30z9J4nfrI8iIZjs9OXYhRvHsXyO466JmdXTBQPfYaJqT4i2pLr0cox7IdMakLXogqzu4 sEb9b91fUlV1YvCXoHzXOP0l382gmxDPi7g4Xl7FtKYCNqEeXxzP4padKar9mK5S4fNBUvupLnKW nyfjqnN9+BojZns7q2WwMgFLFT49ok8MKzWixtlnEjUwzXYuFrOZnk1PTi07NEPhmg4NpGaXutIc SkwsKouLgU9xGqndXHt7CMUADTdA43x7VF8vhV929vensBxXVsFy6K2ir40zSbofitzmdHxghm+H l3s= -----END CERTIFICATE----- ISRG Root X2 ============ -----BEGIN CERTIFICATE----- MIICGzCCAaGgAwIBAgIQQdKd0XLq7qeAwSxs6S+HUjAKBggqhkjOPQQDAzBPMQswCQYDVQQGEwJV UzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElT UkcgUm9vdCBYMjAeFw0yMDA5MDQwMDAwMDBaFw00MDA5MTcxNjAwMDBaME8xCzAJBgNVBAYTAlVT MSkwJwYDVQQKEyBJbnRlcm5ldCBTZWN1cml0eSBSZXNlYXJjaCBHcm91cDEVMBMGA1UEAxMMSVNS RyBSb290IFgyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEzZvVn4CDCuwJSvMWSj5cz3es3mcFDR0H ttwW+1qLFNvicWDEukWVEYmO6gbf9yoWHKS5xcUy4APgHoIYOIvXRdgKam7mAHf7AlF9ItgKbppb d9/w+kHsOdx1ymgHDB/qo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV HQ4EFgQUfEKWrt5LSDv6kviejM9ti6lyN5UwCgYIKoZIzj0EAwMDaAAwZQIwe3lORlCEwkSHRhtF cP9Ymd70/aTSVaYgLXTWNLxBo1BfASdWtL4ndQavEi51mI38AjEAi/V3bNTIZargCyzuFJ0nN6T5 U6VR5CmD1/iQMVtCnwr1/q4AaOeMSQ+2b1tbFfLn -----END CERTIFICATE----- HiPKI Root CA - G1 ================== -----BEGIN CERTIFICATE----- MIIFajCCA1KgAwIBAgIQLd2szmKXlKFD6LDNdmpeYDANBgkqhkiG9w0BAQsFADBPMQswCQYDVQQG EwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0ZC4xGzAZBgNVBAMMEkhpUEtJ IFJvb3QgQ0EgLSBHMTAeFw0xOTAyMjIwOTQ2MDRaFw0zNzEyMzExNTU5NTlaME8xCzAJBgNVBAYT AlRXMSMwIQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEbMBkGA1UEAwwSSGlQS0kg Um9vdCBDQSAtIEcxMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA9B5/UnMyDHPkvRN0 o9QwqNCuS9i233VHZvR85zkEHmpwINJaR3JnVfSl6J3VHiGh8Ge6zCFovkRTv4354twvVcg3Px+k wJyz5HdcoEb+d/oaoDjq7Zpy3iu9lFc6uux55199QmQ5eiY29yTw1S+6lZgRZq2XNdZ1AYDgr/SE YYwNHl98h5ZeQa/rh+r4XfEuiAU+TCK72h8q3VJGZDnzQs7ZngyzsHeXZJzA9KMuH5UHsBffMNsA GJZMoYFL3QRtU6M9/Aes1MU3guvklQgZKILSQjqj2FPseYlgSGDIcpJQ3AOPgz+yQlda22rpEZfd hSi8MEyr48KxRURHH+CKFgeW0iEPU8DtqX7UTuybCeyvQqww1r/REEXgphaypcXTT3OUM3ECoWqj 1jOXTyFjHluP2cFeRXF3D4FdXyGarYPM+l7WjSNfGz1BryB1ZlpK9p/7qxj3ccC2HTHsOyDry+K4 9a6SsvfhhEvyovKTmiKe0xRvNlS9H15ZFblzqMF8b3ti6RZsR1pl8w4Rm0bZ/W3c1pzAtH2lsN0/ Vm+h+fbkEkj9Bn8SV7apI09bA8PgcSojt/ewsTu8mL3WmKgMa/aOEmem8rJY5AIJEzypuxC00jBF 8ez3ABHfZfjcK0NVvxaXxA/VLGGEqnKG/uY6fsI/fe78LxQ+5oXdUG+3Se0CAwEAAaNCMEAwDwYD VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU8ncX+l6o/vY9cdVouslGDDjYr7AwDgYDVR0PAQH/BAQD AgGGMA0GCSqGSIb3DQEBCwUAA4ICAQBQUfB13HAE4/+qddRxosuej6ip0691x1TPOhwEmSKsxBHi 7zNKpiMdDg1H2DfHb680f0+BazVP6XKlMeJ45/dOlBhbQH3PayFUhuaVevvGyuqcSE5XCV0vrPSl tJczWNWseanMX/mF+lLFjfiRFOs6DRfQUsJ748JzjkZ4Bjgs6FzaZsT0pPBWGTMpWmWSBUdGSquE wx4noR8RkpkndZMPvDY7l1ePJlsMu5wP1G4wB9TcXzZoZjmDlicmisjEOf6aIW/Vcobpf2Lll07Q JNBAsNB1CI69aO4I1258EHBGG3zgiLKecoaZAeO/n0kZtCW+VmWuF2PlHt/o/0elv+EmBYTksMCv 5wiZqAxeJoBF1PhoL5aPruJKHJwWDBNvOIf2u8g0X5IDUXlwpt/L9ZlNec1OvFefQ05rLisY+Gpz jLrFNe85akEez3GoorKGB1s6yeHvP2UEgEcyRHCVTjFnanRbEEV16rCf0OY1/k6fi8wrkkVbbiVg hUbN0aqwdmaTd5a+g744tiROJgvM7XpWGuDpWsZkrUx6AEhEL7lAuxM+vhV4nYWBSipX3tUZQ9rb yltHhoMLP7YNdnhzeSJesYAfz77RP1YQmCuVh6EfnWQUYDksswBVLuT1sw5XxJFBAJw/6KXf6vb/ yPCtbVKoF6ubYfwSUTXkJf2vqmqGOQ== -----END CERTIFICATE----- GlobalSign ECC Root CA - R4 =========================== -----BEGIN CERTIFICATE----- MIIB3DCCAYOgAwIBAgINAgPlfvU/k/2lCSGypjAKBggqhkjOPQQDAjBQMSQwIgYDVQQLExtHbG9i YWxTaWduIEVDQyBSb290IENBIC0gUjQxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkds b2JhbFNpZ24wHhcNMTIxMTEzMDAwMDAwWhcNMzgwMTE5MDMxNDA3WjBQMSQwIgYDVQQLExtHbG9i YWxTaWduIEVDQyBSb290IENBIC0gUjQxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkds b2JhbFNpZ24wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAS4xnnTj2wlDp8uORkcA6SumuU5BwkW ymOxuYb4ilfBV85C+nOh92VC/x7BALJucw7/xyHlGKSq2XE/qNS5zowdo0IwQDAOBgNVHQ8BAf8E BAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUVLB7rUW44kB/+wpu+74zyTyjhNUwCgYI KoZIzj0EAwIDRwAwRAIgIk90crlgr/HmnKAWBVBfw147bmF0774BxL4YSFlhgjICICadVGNA3jdg UM/I2O2dgq43mLyjj0xMqTQrbO/7lZsm -----END CERTIFICATE----- GTS Root R1 =========== -----BEGIN CERTIFICATE----- MIIFVzCCAz+gAwIBAgINAgPlk28xsBNJiGuiFzANBgkqhkiG9w0BAQwFADBHMQswCQYDVQQGEwJV UzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3Qg UjEwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UE ChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwggIiMA0G CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2EQKLHuOhd5s73L+UPreVp0A8of2C+X0yBoJx9vaM f/vo27xqLpeXo4xL+Sv2sfnOhB2x+cWX3u+58qPpvBKJXqeqUqv4IyfLpLGcY9vXmX7wCl7raKb0 xlpHDU0QM+NOsROjyBhsS+z8CZDfnWQpJSMHobTSPS5g4M/SCYe7zUjwTcLCeoiKu7rPWRnWr4+w B7CeMfGCwcDfLqZtbBkOtdh+JhpFAz2weaSUKK0PfyblqAj+lug8aJRT7oM6iCsVlgmy4HqMLnXW nOunVmSPlk9orj2XwoSPwLxAwAtcvfaHszVsrBhQf4TgTM2S0yDpM7xSma8ytSmzJSq0SPly4cpk 9+aCEI3oncKKiPo4Zor8Y/kB+Xj9e1x3+naH+uzfsQ55lVe0vSbv1gHR6xYKu44LtcXFilWr06zq kUspzBmkMiVOKvFlRNACzqrOSbTqn3yDsEB750Orp2yjj32JgfpMpf/VjsPOS+C12LOORc92wO1A K/1TD7Cn1TsNsYqiA94xrcx36m97PtbfkSIS5r762DL8EGMUUXLeXdYWk70paDPvOmbsB4om3xPX V2V4J95eSRQAogB/mqghtqmxlbCluQ0WEdrHbEg8QOB+DVrNVjzRlwW5y0vtOUucxD/SVRNuJLDW cfr0wbrM7Rv1/oFB2ACYPTrIrnqYNxgFlQIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0T AQH/BAUwAwEB/zAdBgNVHQ4EFgQU5K8rJnEaK0gnhS9SZizv8IkTcT4wDQYJKoZIhvcNAQEMBQAD ggIBAJ+qQibbC5u+/x6Wki4+omVKapi6Ist9wTrYggoGxval3sBOh2Z5ofmmWJyq+bXmYOfg6LEe QkEzCzc9zolwFcq1JKjPa7XSQCGYzyI0zzvFIoTgxQ6KfF2I5DUkzps+GlQebtuyh6f88/qBVRRi ClmpIgUxPoLW7ttXNLwzldMXG+gnoot7TiYaelpkttGsN/H9oPM47HLwEXWdyzRSjeZ2axfG34ar J45JK3VmgRAhpuo+9K4l/3wV3s6MJT/KYnAK9y8JZgfIPxz88NtFMN9iiMG1D53Dn0reWVlHxYci NuaCp+0KueIHoI17eko8cdLiA6EfMgfdG+RCzgwARWGAtQsgWSl4vflVy2PFPEz0tv/bal8xa5me LMFrUKTX5hgUvYU/Z6tGn6D/Qqc6f1zLXbBwHSs09dR2CQzreExZBfMzQsNhFRAbd03OIozUhfJF fbdT6u9AWpQKXCBfTkBdYiJ23//OYb2MI3jSNwLgjt7RETeJ9r/tSQdirpLsQBqvFAnZ0E6yove+ 7u7Y/9waLd64NnHi/Hm3lCXRSHNboTXns5lndcEZOitHTtNCjv0xyBZm2tIMPNuzjsmhDYAPexZ3 FL//2wmUspO8IFgV6dtxQ/PeEMMA3KgqlbbC1j+Qa3bbbP6MvPJwNQzcmRk13NfIRmPVNnGuV/u3 gm3c -----END CERTIFICATE----- GTS Root R2 =========== -----BEGIN CERTIFICATE----- MIIFVzCCAz+gAwIBAgINAgPlrsWNBCUaqxElqjANBgkqhkiG9w0BAQwFADBHMQswCQYDVQQGEwJV UzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3Qg UjIwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UE ChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjIwggIiMA0G CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDO3v2m++zsFDQ8BwZabFn3GTXd98GdVarTzTukk3Lv CvptnfbwhYBboUhSnznFt+4orO/LdmgUud+tAWyZH8QiHZ/+cnfgLFuv5AS/T3KgGjSY6Dlo7JUl e3ah5mm5hRm9iYz+re026nO8/4Piy33B0s5Ks40FnotJk9/BW9BuXvAuMC6C/Pq8tBcKSOWIm8Wb a96wyrQD8Nr0kLhlZPdcTK3ofmZemde4wj7I0BOdre7kRXuJVfeKH2JShBKzwkCX44ofR5GmdFrS +LFjKBC4swm4VndAoiaYecb+3yXuPuWgf9RhD1FLPD+M2uFwdNjCaKH5wQzpoeJ/u1U8dgbuak7M kogwTZq9TwtImoS1mKPV+3PBV2HdKFZ1E66HjucMUQkQdYhMvI35ezzUIkgfKtzra7tEscszcTJG r61K8YzodDqs5xoic4DSMPclQsciOzsSrZYuxsN2B6ogtzVJV+mSSeh2FnIxZyuWfoqjx5RWIr9q S34BIbIjMt/kmkRtWVtd9QCgHJvGeJeNkP+byKq0rxFROV7Z+2et1VsRnTKaG73VululycslaVNV J1zgyjbLiGH7HrfQy+4W+9OmTN6SpdTi3/UGVN4unUu0kzCqgc7dGtxRcw1PcOnlthYhGXmy5okL dWTK1au8CcEYof/UVKGFPP0UJAOyh9OktwIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0T AQH/BAUwAwEB/zAdBgNVHQ4EFgQUu//KjiOfT5nK2+JopqUVJxce2Q4wDQYJKoZIhvcNAQEMBQAD ggIBAB/Kzt3HvqGf2SdMC9wXmBFqiN495nFWcrKeGk6c1SuYJF2ba3uwM4IJvd8lRuqYnrYb/oM8 0mJhwQTtzuDFycgTE1XnqGOtjHsB/ncw4c5omwX4Eu55MaBBRTUoCnGkJE+M3DyCB19m3H0Q/gxh swWV7uGugQ+o+MePTagjAiZrHYNSVc61LwDKgEDg4XSsYPWHgJ2uNmSRXbBoGOqKYcl3qJfEycel /FVL8/B/uWU9J2jQzGv6U53hkRrJXRqWbTKH7QMgyALOWr7Z6v2yTcQvG99fevX4i8buMTolUVVn jWQye+mew4K6Ki3pHrTgSAai/GevHyICc/sgCq+dVEuhzf9gR7A/Xe8bVr2XIZYtCtFenTgCR2y5 9PYjJbigapordwj6xLEokCZYCDzifqrXPW+6MYgKBesntaFJ7qBFVHvmJ2WZICGoo7z7GJa7Um8M 7YNRTOlZ4iBgxcJlkoKM8xAfDoqXvneCbT+PHV28SSe9zE8P4c52hgQjxcCMElv924SgJPFI/2R8 0L5cFtHvma3AH/vLrrw4IgYmZNralw4/KBVEqE8AyvCazM90arQ+POuV7LXTWtiBmelDGDfrs7vR WGJB82bSj6p4lVQgw1oudCvV0b4YacCs1aTPObpRhANl6WLAYv7YTVWW4tAR+kg0Eeye7QUd5MjW HYbL -----END CERTIFICATE----- GTS Root R3 =========== -----BEGIN CERTIFICATE----- MIICCTCCAY6gAwIBAgINAgPluILrIPglJ209ZjAKBggqhkjOPQQDAzBHMQswCQYDVQQGEwJVUzEi MCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjMw HhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZ R29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjMwdjAQBgcqhkjO PQIBBgUrgQQAIgNiAAQfTzOHMymKoYTey8chWEGJ6ladK0uFxh1MJ7x/JlFyb+Kf1qPKzEUURout 736GjOyxfi//qXGdGIRFBEFVbivqJn+7kAHjSxm65FSWRQmx1WyRRK2EE46ajA2ADDL24CejQjBA MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTB8Sa6oC2uhYHP0/Eq Er24Cmf9vDAKBggqhkjOPQQDAwNpADBmAjEA9uEglRR7VKOQFhG/hMjqb2sXnh5GmCCbn9MN2azT L818+FsuVbu/3ZL3pAzcMeGiAjEA/JdmZuVDFhOD3cffL74UOO0BzrEXGhF16b0DjyZ+hOXJYKaV 11RZt+cRLInUue4X -----END CERTIFICATE----- GTS Root R4 =========== -----BEGIN CERTIFICATE----- MIICCTCCAY6gAwIBAgINAgPlwGjvYxqccpBQUjAKBggqhkjOPQQDAzBHMQswCQYDVQQGEwJVUzEi MCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjQw HhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZ R29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjQwdjAQBgcqhkjO PQIBBgUrgQQAIgNiAATzdHOnaItgrkO4NcWBMHtLSZ37wWHO5t5GvWvVYRg1rkDdc/eJkTBa6zzu hXyiQHY7qca4R9gq55KRanPpsXI5nymfopjTX15YhmUPoYRlBtHci8nHc8iMai/lxKvRHYqjQjBA MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSATNbrdP9JNqPV2Py1 PsVq8JQdjDAKBggqhkjOPQQDAwNpADBmAjEA6ED/g94D9J+uHXqnLrmvT/aDHQ4thQEd0dlq7A/C r8deVl5c1RxYIigL9zC2L7F8AjEA8GE8p/SgguMh1YQdc4acLa/KNJvxn7kjNuK8YAOdgLOaVsjh 4rsUecrNIdSUtUlD -----END CERTIFICATE----- Telia Root CA v2 ================ -----BEGIN CERTIFICATE----- MIIFdDCCA1ygAwIBAgIPAWdfJ9b+euPkrL4JWwWeMA0GCSqGSIb3DQEBCwUAMEQxCzAJBgNVBAYT AkZJMRowGAYDVQQKDBFUZWxpYSBGaW5sYW5kIE95ajEZMBcGA1UEAwwQVGVsaWEgUm9vdCBDQSB2 MjAeFw0xODExMjkxMTU1NTRaFw00MzExMjkxMTU1NTRaMEQxCzAJBgNVBAYTAkZJMRowGAYDVQQK DBFUZWxpYSBGaW5sYW5kIE95ajEZMBcGA1UEAwwQVGVsaWEgUm9vdCBDQSB2MjCCAiIwDQYJKoZI hvcNAQEBBQADggIPADCCAgoCggIBALLQPwe84nvQa5n44ndp586dpAO8gm2h/oFlH0wnrI4AuhZ7 6zBqAMCzdGh+sq/H1WKzej9Qyow2RCRj0jbpDIX2Q3bVTKFgcmfiKDOlyzG4OiIjNLh9vVYiQJ3q 9HsDrWj8soFPmNB06o3lfc1jw6P23pLCWBnglrvFxKk9pXSW/q/5iaq9lRdU2HhE8Qx3FZLgmEKn pNaqIJLNwaCzlrI6hEKNfdWV5Nbb6WLEWLN5xYzTNTODn3WhUidhOPFZPY5Q4L15POdslv5e2QJl tI5c0BE0312/UqeBAMN/mUWZFdUXyApT7GPzmX3MaRKGwhfwAZ6/hLzRUssbkmbOpFPlob/E2wnW 5olWK8jjfN7j/4nlNW4o6GwLI1GpJQXrSPjdscr6bAhR77cYbETKJuFzxokGgeWKrLDiKca5JLNr RBH0pUPCTEPlcDaMtjNXepUugqD0XBCzYYP2AgWGLnwtbNwDRm41k9V6lS/eINhbfpSQBGq6WT0E BXWdN6IOLj3rwaRSg/7Qa9RmjtzG6RJOHSpXqhC8fF6CfaamyfItufUXJ63RDolUK5X6wK0dmBR4 M0KGCqlztft0DbcbMBnEWg4cJ7faGND/isgFuvGqHKI3t+ZIpEYslOqodmJHixBTB0hXbOKSTbau BcvcwUpej6w9GU7C7WB1K9vBykLVAgMBAAGjYzBhMB8GA1UdIwQYMBaAFHKs5DN5qkWH9v2sHZ7W xy+G2CQ5MB0GA1UdDgQWBBRyrOQzeapFh/b9rB2e1scvhtgkOTAOBgNVHQ8BAf8EBAMCAQYwDwYD VR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAoDtZpwmUPjaE0n4vOaWWl/oRrfxn83EJ 8rKJhGdEr7nv7ZbsnGTbMjBvZ5qsfl+yqwE2foH65IRe0qw24GtixX1LDoJt0nZi0f6X+J8wfBj5 tFJ3gh1229MdqfDBmgC9bXXYfef6xzijnHDoRnkDry5023X4blMMA8iZGok1GTzTyVR8qPAs5m4H eW9q4ebqkYJpCh3DflminmtGFZhb069GHWLIzoBSSRE/yQQSwxN8PzuKlts8oB4KtItUsiRnDe+C y748fdHif64W1lZYudogsYMVoe+KTTJvQS8TUoKU1xrBeKJR3Stwbbca+few4GeXVtt8YVMJAygC QMez2P2ccGrGKMOF6eLtGpOg3kuYooQ+BXcBlj37tCAPnHICehIv1aO6UXivKitEZU61/Qrowc15 h2Er3oBXRb9n8ZuRXqWk7FlIEA04x7D6w0RtBPV4UBySllva9bguulvP5fBqnUsvWHMtTy3EHD70 sz+rFQ47GUGKpMFXEmZxTPpT41frYpUJnlTd0cI8Vzy9OK2YZLe4A5pTVmBds9hCG1xLEooc6+t9 xnppxyd/pPiL8uSUZodL6ZQHCRJ5irLrdATczvREWeAWysUsWNc8e89ihmpQfTU2Zqf7N+cox9jQ raVplI/owd8k+BsHMYeB2F326CjYSlKArBPuUBQemMc= -----END CERTIFICATE----- D-TRUST BR Root CA 1 2020 ========================= -----BEGIN CERTIFICATE----- MIIC2zCCAmCgAwIBAgIQfMmPK4TX3+oPyWWa00tNljAKBggqhkjOPQQDAzBIMQswCQYDVQQGEwJE RTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlELVRSVVNUIEJSIFJvb3QgQ0EgMSAy MDIwMB4XDTIwMDIxMTA5NDUwMFoXDTM1MDIxMTA5NDQ1OVowSDELMAkGA1UEBhMCREUxFTATBgNV BAoTDEQtVHJ1c3QgR21iSDEiMCAGA1UEAxMZRC1UUlVTVCBCUiBSb290IENBIDEgMjAyMDB2MBAG ByqGSM49AgEGBSuBBAAiA2IABMbLxyjR+4T1mu9CFCDhQ2tuda38KwOE1HaTJddZO0Flax7mNCq7 dPYSzuht56vkPE4/RAiLzRZxy7+SmfSk1zxQVFKQhYN4lGdnoxwJGT11NIXe7WB9xwy0QVK5buXu QqOCAQ0wggEJMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFHOREKv/VbNafAkl1bK6CKBrqx9t MA4GA1UdDwEB/wQEAwIBBjCBxgYDVR0fBIG+MIG7MD6gPKA6hjhodHRwOi8vY3JsLmQtdHJ1c3Qu bmV0L2NybC9kLXRydXN0X2JyX3Jvb3RfY2FfMV8yMDIwLmNybDB5oHegdYZzbGRhcDovL2RpcmVj dG9yeS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwQlIlMjBSb290JTIwQ0ElMjAxJTIwMjAyMCxP PUQtVHJ1c3QlMjBHbWJILEM9REU/Y2VydGlmaWNhdGVyZXZvY2F0aW9ubGlzdDAKBggqhkjOPQQD AwNpADBmAjEAlJAtE/rhY/hhY+ithXhUkZy4kzg+GkHaQBZTQgjKL47xPoFWwKrY7RjEsK70Pvom AjEA8yjixtsrmfu3Ubgko6SUeho/5jbiA1czijDLgsfWFBHVdWNbFJWcHwHP2NVypw87 -----END CERTIFICATE----- D-TRUST EV Root CA 1 2020 ========================= -----BEGIN CERTIFICATE----- MIIC2zCCAmCgAwIBAgIQXwJB13qHfEwDo6yWjfv/0DAKBggqhkjOPQQDAzBIMQswCQYDVQQGEwJE RTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlELVRSVVNUIEVWIFJvb3QgQ0EgMSAy MDIwMB4XDTIwMDIxMTEwMDAwMFoXDTM1MDIxMTA5NTk1OVowSDELMAkGA1UEBhMCREUxFTATBgNV BAoTDEQtVHJ1c3QgR21iSDEiMCAGA1UEAxMZRC1UUlVTVCBFViBSb290IENBIDEgMjAyMDB2MBAG ByqGSM49AgEGBSuBBAAiA2IABPEL3YZDIBnfl4XoIkqbz52Yv7QFJsnL46bSj8WeeHsxiamJrSc8 ZRCC/N/DnU7wMyPE0jL1HLDfMxddxfCxivnvubcUyilKwg+pf3VlSSowZ/Rk99Yad9rDwpdhQntJ raOCAQ0wggEJMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFH8QARY3OqQo5FD4pPfsazK2/umL MA4GA1UdDwEB/wQEAwIBBjCBxgYDVR0fBIG+MIG7MD6gPKA6hjhodHRwOi8vY3JsLmQtdHJ1c3Qu bmV0L2NybC9kLXRydXN0X2V2X3Jvb3RfY2FfMV8yMDIwLmNybDB5oHegdYZzbGRhcDovL2RpcmVj dG9yeS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwRVYlMjBSb290JTIwQ0ElMjAxJTIwMjAyMCxP PUQtVHJ1c3QlMjBHbWJILEM9REU/Y2VydGlmaWNhdGVyZXZvY2F0aW9ubGlzdDAKBggqhkjOPQQD AwNpADBmAjEAyjzGKnXCXnViOTYAYFqLwZOZzNnbQTs7h5kXO9XMT8oi96CAy/m0sRtW9XLS/BnR AjEAkfcwkz8QRitxpNA7RJvAKQIFskF3UfN5Wp6OFKBOQtJbgfM0agPnIjhQW+0ZT0MW -----END CERTIFICATE----- DigiCert TLS ECC P384 Root G5 ============================= -----BEGIN CERTIFICATE----- MIICGTCCAZ+gAwIBAgIQCeCTZaz32ci5PhwLBCou8zAKBggqhkjOPQQDAzBOMQswCQYDVQQGEwJV UzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJjAkBgNVBAMTHURpZ2lDZXJ0IFRMUyBFQ0MgUDM4 NCBSb290IEc1MB4XDTIxMDExNTAwMDAwMFoXDTQ2MDExNDIzNTk1OVowTjELMAkGA1UEBhMCVVMx FzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMSYwJAYDVQQDEx1EaWdpQ2VydCBUTFMgRUNDIFAzODQg Um9vdCBHNTB2MBAGByqGSM49AgEGBSuBBAAiA2IABMFEoc8Rl1Ca3iOCNQfN0MsYndLxf3c1Tzvd lHJS7cI7+Oz6e2tYIOyZrsn8aLN1udsJ7MgT9U7GCh1mMEy7H0cKPGEQQil8pQgO4CLp0zVozptj n4S1mU1YoI71VOeVyaNCMEAwHQYDVR0OBBYEFMFRRVBZqz7nLFr6ICISB4CIfBFqMA4GA1UdDwEB /wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMDA2gAMGUCMQCJao1H5+z8blUD2Wds Jk6Dxv3J+ysTvLd6jLRl0mlpYxNjOyZQLgGheQaRnUi/wr4CMEfDFXuxoJGZSZOoPHzoRgaLLPIx AJSdYsiJvRmEFOml+wG4DXZDjC5Ty3zfDBeWUA== -----END CERTIFICATE----- DigiCert TLS RSA4096 Root G5 ============================ -----BEGIN CERTIFICATE----- MIIFZjCCA06gAwIBAgIQCPm0eKj6ftpqMzeJ3nzPijANBgkqhkiG9w0BAQwFADBNMQswCQYDVQQG EwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJTAjBgNVBAMTHERpZ2lDZXJ0IFRMUyBSU0E0 MDk2IFJvb3QgRzUwHhcNMjEwMTE1MDAwMDAwWhcNNDYwMTE0MjM1OTU5WjBNMQswCQYDVQQGEwJV UzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJTAjBgNVBAMTHERpZ2lDZXJ0IFRMUyBSU0E0MDk2 IFJvb3QgRzUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCz0PTJeRGd/fxmgefM1eS8 7IE+ajWOLrfn3q/5B03PMJ3qCQuZvWxX2hhKuHisOjmopkisLnLlvevxGs3npAOpPxG02C+JFvuU AT27L/gTBaF4HI4o4EXgg/RZG5Wzrn4DReW+wkL+7vI8toUTmDKdFqgpwgscONyfMXdcvyej/Ces tyu9dJsXLfKB2l2w4SMXPohKEiPQ6s+d3gMXsUJKoBZMpG2T6T867jp8nVid9E6P/DsjyG244gXa zOvswzH016cpVIDPRFtMbzCe88zdH5RDnU1/cHAN1DrRN/BsnZvAFJNY781BOHW8EwOVfH/jXOnV DdXifBBiqmvwPXbzP6PosMH976pXTayGpxi0KcEsDr9kvimM2AItzVwv8n/vFfQMFawKsPHTDU9q TXeXAaDxZre3zu/O7Oyldcqs4+Fj97ihBMi8ez9dLRYiVu1ISf6nL3kwJZu6ay0/nTvEF+cdLvvy z6b84xQslpghjLSR6Rlgg/IwKwZzUNWYOwbpx4oMYIwo+FKbbuH2TbsGJJvXKyY//SovcfXWJL5/ MZ4PbeiPT02jP/816t9JXkGPhvnxd3lLG7SjXi/7RgLQZhNeXoVPzthwiHvOAbWWl9fNff2C+MIk wcoBOU+NosEUQB+cZtUMCUbW8tDRSHZWOkPLtgoRObqME2wGtZ7P6wIDAQABo0IwQDAdBgNVHQ4E FgQUUTMc7TZArxfTJc1paPKvTiM+s0EwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8w DQYJKoZIhvcNAQEMBQADggIBAGCmr1tfV9qJ20tQqcQjNSH/0GEwhJG3PxDPJY7Jv0Y02cEhJhxw GXIeo8mH/qlDZJY6yFMECrZBu8RHANmfGBg7sg7zNOok992vIGCukihfNudd5N7HPNtQOa27PShN lnx2xlv0wdsUpasZYgcYQF+Xkdycx6u1UQ3maVNVzDl92sURVXLFO4uJ+DQtpBflF+aZfTCIITfN MBc9uPK8qHWgQ9w+iUuQrm0D4ByjoJYJu32jtyoQREtGBzRj7TG5BO6jm5qu5jF49OokYTurWGT/ u4cnYiWB39yhL/btp/96j1EuMPikAdKFOV8BmZZvWltwGUb+hmA+rYAQCd05JS9Yf7vSdPD3Rh9G OUrYU9DzLjtxpdRv/PNn5AeP3SYZ4Y1b+qOTEZvpyDrDVWiakuFSdjjo4bq9+0/V77PnSIMx8IIh 47a+p6tv75/fTM8BuGJqIz3nCU2AG3swpMPdB380vqQmsvZB6Akd4yCYqjdP//fx4ilwMUc/dNAU FvohigLVigmUdy7yWSiLfFCSCmZ4OIN1xLVaqBHG5cGdZlXPU8Sv13WFqUITVuwhd4GTWgzqltlJ yqEI8pc7bZsEGCREjnwB8twl2F6GmrE52/WRMmrRpnCKovfepEWFJqgejF0pW8hL2JpqA15w8oVP bEtoL8pU9ozaMv7Da4M/OMZ+ -----END CERTIFICATE----- Certainly Root R1 ================= -----BEGIN CERTIFICATE----- MIIFRzCCAy+gAwIBAgIRAI4P+UuQcWhlM1T01EQ5t+AwDQYJKoZIhvcNAQELBQAwPTELMAkGA1UE BhMCVVMxEjAQBgNVBAoTCUNlcnRhaW5seTEaMBgGA1UEAxMRQ2VydGFpbmx5IFJvb3QgUjEwHhcN MjEwNDAxMDAwMDAwWhcNNDYwNDAxMDAwMDAwWjA9MQswCQYDVQQGEwJVUzESMBAGA1UEChMJQ2Vy dGFpbmx5MRowGAYDVQQDExFDZXJ0YWlubHkgUm9vdCBSMTCCAiIwDQYJKoZIhvcNAQEBBQADggIP ADCCAgoCggIBANA21B/q3avk0bbm+yLA3RMNansiExyXPGhjZjKcA7WNpIGD2ngwEc/csiu+kr+O 5MQTvqRoTNoCaBZ0vrLdBORrKt03H2As2/X3oXyVtwxwhi7xOu9S98zTm/mLvg7fMbedaFySpvXl 8wo0tf97ouSHocavFwDvA5HtqRxOcT3Si2yJ9HiG5mpJoM610rCrm/b01C7jcvk2xusVtyWMOvwl DbMicyF0yEqWYZL1LwsYpfSt4u5BvQF5+paMjRcCMLT5r3gajLQ2EBAHBXDQ9DGQilHFhiZ5shGI XsXwClTNSaa/ApzSRKft43jvRl5tcdF5cBxGX1HpyTfcX35pe0HfNEXgO4T0oYoKNp43zGJS4YkN KPl6I7ENPT2a/Z2B7yyQwHtETrtJ4A5KVpK8y7XdeReJkd5hiXSSqOMyhb5OhaRLWcsrxXiOcVTQ AjeZjOVJ6uBUcqQRBi8LjMFbvrWhsFNunLhgkR9Za/kt9JQKl7XsxXYDVBtlUrpMklZRNaBA2Cnb rlJ2Oy0wQJuK0EJWtLeIAaSHO1OWzaMWj/Nmqhexx2DgwUMFDO6bW2BvBlyHWyf5QBGenDPBt+U1 VwV/J84XIIwc/PH72jEpSe31C4SnT8H2TsIonPru4K8H+zMReiFPCyEQtkA6qyI6BJyLm4SGcprS p6XEtHWRqSsjAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud DgQWBBTgqj8ljZ9EXME66C6ud0yEPmcM9DANBgkqhkiG9w0BAQsFAAOCAgEAuVevuBLaV4OPaAsz HQNTVfSVcOQrPbA56/qJYv331hgELyE03fFo8NWWWt7CgKPBjcZq91l3rhVkz1t5BXdm6ozTaw3d 8VkswTOlMIAVRQdFGjEitpIAq5lNOo93r6kiyi9jyhXWx8bwPWz8HA2YEGGeEaIi1wrykXprOQ4v MMM2SZ/g6Q8CRFA3lFV96p/2O7qUpUzpvD5RtOjKkjZUbVwlKNrdrRT90+7iIgXr0PK3aBLXWopB GsaSpVo7Y0VPv+E6dyIvXL9G+VoDhRNCX8reU9ditaY1BMJH/5n9hN9czulegChB8n3nHpDYT3Y+ gjwN/KUD+nsa2UUeYNrEjvn8K8l7lcUq/6qJ34IxD3L/DCfXCh5WAFAeDJDBlrXYFIW7pw0WwfgH JBu6haEaBQmAupVjyTrsJZ9/nbqkRxWbRHDxakvWOF5D8xh+UG7pWijmZeZ3Gzr9Hb4DJqPb1OG7 fpYnKx3upPvaJVQTA945xsMfTZDsjxtK0hzthZU4UHlG1sGQUDGpXJpuHfUzVounmdLyyCwzk5Iw x06MZTMQZBf9JBeW0Y3COmor6xOLRPIh80oat3df1+2IpHLlOR+Vnb5nwXARPbv0+Em34yaXOp/S X3z7wJl8OSngex2/DaeP0ik0biQVy96QXr8axGbqwua6OV+KmalBWQewLK8= -----END CERTIFICATE----- Certainly Root E1 ================= -----BEGIN CERTIFICATE----- MIIB9zCCAX2gAwIBAgIQBiUzsUcDMydc+Y2aub/M+DAKBggqhkjOPQQDAzA9MQswCQYDVQQGEwJV UzESMBAGA1UEChMJQ2VydGFpbmx5MRowGAYDVQQDExFDZXJ0YWlubHkgUm9vdCBFMTAeFw0yMTA0 MDEwMDAwMDBaFw00NjA0MDEwMDAwMDBaMD0xCzAJBgNVBAYTAlVTMRIwEAYDVQQKEwlDZXJ0YWlu bHkxGjAYBgNVBAMTEUNlcnRhaW5seSBSb290IEUxMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE3m/4 fxzf7flHh4axpMCK+IKXgOqPyEpeKn2IaKcBYhSRJHpcnqMXfYqGITQYUBsQ3tA3SybHGWCA6TS9 YBk2QNYphwk8kXr2vBMj3VlOBF7PyAIcGFPBMdjaIOlEjeR2o0IwQDAOBgNVHQ8BAf8EBAMCAQYw DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU8ygYy2R17ikq6+2uI1g4hevIIgcwCgYIKoZIzj0E AwMDaAAwZQIxALGOWiDDshliTd6wT99u0nCK8Z9+aozmut6Dacpps6kFtZaSF4fC0urQe87YQVt8 rgIwRt7qy12a7DLCZRawTDBcMPPaTnOGBtjOiQRINzf43TNRnXCve1XYAS59BWQOhriR -----END CERTIFICATE----- Security Communication ECC RootCA1 ================================== -----BEGIN CERTIFICATE----- MIICODCCAb6gAwIBAgIJANZdm7N4gS7rMAoGCCqGSM49BAMDMGExCzAJBgNVBAYTAkpQMSUwIwYD VQQKExxTRUNPTSBUcnVzdCBTeXN0ZW1zIENPLixMVEQuMSswKQYDVQQDEyJTZWN1cml0eSBDb21t dW5pY2F0aW9uIEVDQyBSb290Q0ExMB4XDTE2MDYxNjA1MTUyOFoXDTM4MDExODA1MTUyOFowYTEL MAkGA1UEBhMCSlAxJTAjBgNVBAoTHFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xKzApBgNV BAMTIlNlY3VyaXR5IENvbW11bmljYXRpb24gRUNDIFJvb3RDQTEwdjAQBgcqhkjOPQIBBgUrgQQA IgNiAASkpW9gAwPDvTH00xecK4R1rOX9PVdu12O/5gSJko6BnOPpR27KkBLIE+CnnfdldB9sELLo 5OnvbYUymUSxXv3MdhDYW72ixvnWQuRXdtyQwjWpS4g8EkdtXP9JTxpKULGjQjBAMB0GA1UdDgQW BBSGHOf+LaVKiwj+KBH6vqNm+GBZLzAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAK BggqhkjOPQQDAwNoADBlAjAVXUI9/Lbu9zuxNuie9sRGKEkz0FhDKmMpzE2xtHqiuQ04pV1IKv3L snNdo4gIxwwCMQDAqy0Obe0YottT6SXbVQjgUMzfRGEWgqtJsLKB7HOHeLRMsmIbEvoWTSVLY70e N9k= -----END CERTIFICATE----- BJCA Global Root CA1 ==================== -----BEGIN CERTIFICATE----- MIIFdDCCA1ygAwIBAgIQVW9l47TZkGobCdFsPsBsIDANBgkqhkiG9w0BAQsFADBUMQswCQYDVQQG EwJDTjEmMCQGA1UECgwdQkVJSklORyBDRVJUSUZJQ0FURSBBVVRIT1JJVFkxHTAbBgNVBAMMFEJK Q0EgR2xvYmFsIFJvb3QgQ0ExMB4XDTE5MTIxOTAzMTYxN1oXDTQ0MTIxMjAzMTYxN1owVDELMAkG A1UEBhMCQ04xJjAkBgNVBAoMHUJFSUpJTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZMR0wGwYDVQQD DBRCSkNBIEdsb2JhbCBSb290IENBMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAPFm CL3ZxRVhy4QEQaVpN3cdwbB7+sN3SJATcmTRuHyQNZ0YeYjjlwE8R4HyDqKYDZ4/N+AZspDyRhyS sTphzvq3Rp4Dhtczbu33RYx2N95ulpH3134rhxfVizXuhJFyV9xgw8O558dnJCNPYwpj9mZ9S1Wn P3hkSWkSl+BMDdMJoDIwOvqfwPKcxRIqLhy1BDPapDgRat7GGPZHOiJBhyL8xIkoVNiMpTAK+BcW yqw3/XmnkRd4OJmtWO2y3syJfQOcs4ll5+M7sSKGjwZteAf9kRJ/sGsciQ35uMt0WwfCyPQ10WRj eulumijWML3mG90Vr4TqnMfK9Q7q8l0ph49pczm+LiRvRSGsxdRpJQaDrXpIhRMsDQa4bHlW/KNn MoH1V6XKV0Jp6VwkYe/iMBhORJhVb3rCk9gZtt58R4oRTklH2yiUAguUSiz5EtBP6DF+bHq/pj+b OT0CFqMYs2esWz8sgytnOYFcuX6U1WTdno9uruh8W7TXakdI136z1C2OVnZOz2nxbkRs1CTqjSSh GL+9V/6pmTW12xB3uD1IutbB5/EjPtffhZ0nPNRAvQoMvfXnjSXWgXSHRtQpdaJCbPdzied9v3pK H9MiyRVVz99vfFXQpIsHETdfg6YmV6YBW37+WGgHqel62bno/1Afq8K0wM7o6v0PvY1NuLxxAgMB AAGjQjBAMB0GA1UdDgQWBBTF7+3M2I0hxkjk49cULqcWk+WYATAPBgNVHRMBAf8EBTADAQH/MA4G A1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAUoKsITQfI/Ki2Pm4rzc2IInRNwPWaZ+4 YRC6ojGYWUfo0Q0lHhVBDOAqVdVXUsv45Mdpox1NcQJeXyFFYEhcCY5JEMEE3KliawLwQ8hOnThJ dMkycFRtwUf8jrQ2ntScvd0g1lPJGKm1Vrl2i5VnZu69mP6u775u+2D2/VnGKhs/I0qUJDAnyIm8 60Qkmss9vk/Ves6OF8tiwdneHg56/0OGNFK8YT88X7vZdrRTvJez/opMEi4r89fO4aL/3Xtw+zuh TaRjAv04l5U/BXCga99igUOLtFkNSoxUnMW7gZ/NfaXvCyUeOiDbHPwfmGcCCtRzRBPbUYQaVQNW 4AB+dAb/OMRyHdOoP2gxXdMJxy6MW2Pg6Nwe0uxhHvLe5e/2mXZgLR6UcnHGCyoyx5JO1UbXHfmp GQrI+pXObSOYqgs4rZpWDW+N8TEAiMEXnM0ZNjX+VVOg4DwzX5Ze4jLp3zO7Bkqp2IRzznfSxqxx 4VyjHQy7Ct9f4qNx2No3WqB4K/TUfet27fJhcKVlmtOJNBir+3I+17Q9eVzYH6Eze9mCUAyTF6ps 3MKCuwJXNq+YJyo5UOGwifUll35HaBC07HPKs5fRJNz2YqAo07WjuGS3iGJCz51TzZm+ZGiPTx4S SPfSKcOYKMryMguTjClPPGAyzQWWYezyr/6zcCwupvI= -----END CERTIFICATE----- BJCA Global Root CA2 ==================== -----BEGIN CERTIFICATE----- MIICJTCCAaugAwIBAgIQLBcIfWQqwP6FGFkGz7RK6zAKBggqhkjOPQQDAzBUMQswCQYDVQQGEwJD TjEmMCQGA1UECgwdQkVJSklORyBDRVJUSUZJQ0FURSBBVVRIT1JJVFkxHTAbBgNVBAMMFEJKQ0Eg R2xvYmFsIFJvb3QgQ0EyMB4XDTE5MTIxOTAzMTgyMVoXDTQ0MTIxMjAzMTgyMVowVDELMAkGA1UE BhMCQ04xJjAkBgNVBAoMHUJFSUpJTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZMR0wGwYDVQQDDBRC SkNBIEdsb2JhbCBSb290IENBMjB2MBAGByqGSM49AgEGBSuBBAAiA2IABJ3LgJGNU2e1uVCxA/jl SR9BIgmwUVJY1is0j8USRhTFiy8shP8sbqjV8QnjAyEUxEM9fMEsxEtqSs3ph+B99iK++kpRuDCK /eHeGBIK9ke35xe/J4rUQUyWPGCWwf0VHKNCMEAwHQYDVR0OBBYEFNJKsVF/BvDRgh9Obl+rg/xI 1LCRMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMAoGCCqGSM49BAMDA2gAMGUCMBq8 W9f+qdJUDkpd0m2xQNz0Q9XSSpkZElaA94M04TVOSG0ED1cxMDAtsaqdAzjbBgIxAMvMh1PLet8g UXOQwKhbYdDFUDn9hf7B43j4ptZLvZuHjw/l1lOWqzzIQNph91Oj9w== -----END CERTIFICATE----- Sectigo Public Server Authentication Root E46 ============================================= -----BEGIN CERTIFICATE----- MIICOjCCAcGgAwIBAgIQQvLM2htpN0RfFf51KBC49DAKBggqhkjOPQQDAzBfMQswCQYDVQQGEwJH QjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1TZWN0aWdvIFB1YmxpYyBTZXJ2 ZXIgQXV0aGVudGljYXRpb24gUm9vdCBFNDYwHhcNMjEwMzIyMDAwMDAwWhcNNDYwMzIxMjM1OTU5 WjBfMQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1TZWN0 aWdvIFB1YmxpYyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBFNDYwdjAQBgcqhkjOPQIBBgUr gQQAIgNiAAR2+pmpbiDt+dd34wc7qNs9Xzjoq1WmVk/WSOrsfy2qw7LFeeyZYX8QeccCWvkEN/U0 NSt3zn8gj1KjAIns1aeibVvjS5KToID1AZTc8GgHHs3u/iVStSBDHBv+6xnOQ6OjQjBAMB0GA1Ud DgQWBBTRItpMWfFLXyY4qp3W7usNw/upYTAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB /zAKBggqhkjOPQQDAwNnADBkAjAn7qRaqCG76UeXlImldCBteU/IvZNeWBj7LRoAasm4PdCkT0RH lAFWovgzJQxC36oCMB3q4S6ILuH5px0CMk7yn2xVdOOurvulGu7t0vzCAxHrRVxgED1cf5kDW21U SAGKcw== -----END CERTIFICATE----- Sectigo Public Server Authentication Root R46 ============================================= -----BEGIN CERTIFICATE----- MIIFijCCA3KgAwIBAgIQdY39i658BwD6qSWn4cetFDANBgkqhkiG9w0BAQwFADBfMQswCQYDVQQG EwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1TZWN0aWdvIFB1YmxpYyBT ZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBSNDYwHhcNMjEwMzIyMDAwMDAwWhcNNDYwMzIxMjM1 OTU5WjBfMQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1T ZWN0aWdvIFB1YmxpYyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBSNDYwggIiMA0GCSqGSIb3 DQEBAQUAA4ICDwAwggIKAoICAQCTvtU2UnXYASOgHEdCSe5jtrch/cSV1UgrJnwUUxDaef0rty2k 1Cz66jLdScK5vQ9IPXtamFSvnl0xdE8H/FAh3aTPaE8bEmNtJZlMKpnzSDBh+oF8HqcIStw+Kxwf GExxqjWMrfhu6DtK2eWUAtaJhBOqbchPM8xQljeSM9xfiOefVNlI8JhD1mb9nxc4Q8UBUQvX4yMP FF1bFOdLvt30yNoDN9HWOaEhUTCDsG3XME6WW5HwcCSrv0WBZEMNvSE6Lzzpng3LILVCJ8zab5vu ZDCQOc2TZYEhMbUjUDM3IuM47fgxMMxF/mL50V0yeUKH32rMVhlATc6qu/m1dkmU8Sf4kaWD5Qaz Yw6A3OASVYCmO2a0OYctyPDQ0RTp5A1NDvZdV3LFOxxHVp3i1fuBYYzMTYCQNFu31xR13NgESJ/A wSiItOkcyqex8Va3e0lMWeUgFaiEAin6OJRpmkkGj80feRQXEgyDet4fsZfu+Zd4KKTIRJLpfSYF plhym3kT2BFfrsU4YjRosoYwjviQYZ4ybPUHNs2iTG7sijbt8uaZFURww3y8nDnAtOFr94MlI1fZ EoDlSfB1D++N6xybVCi0ITz8fAr/73trdf+LHaAZBav6+CuBQug4urv7qv094PPK306Xlynt8xhW 6aWWrL3DkJiy4Pmi1KZHQ3xtzwIDAQABo0IwQDAdBgNVHQ4EFgQUVnNYZJX5khqwEioEYnmhQBWI IUkwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAC9c mTz8Bl6MlC5w6tIyMY208FHVvArzZJ8HXtXBc2hkeqK5Duj5XYUtqDdFqij0lgVQYKlJfp/imTYp E0RHap1VIDzYm/EDMrraQKFz6oOht0SmDpkBm+S8f74TlH7Kph52gDY9hAaLMyZlbcp+nv4fjFg4 exqDsQ+8FxG75gbMY/qB8oFM2gsQa6H61SilzwZAFv97fRheORKkU55+MkIQpiGRqRxOF3yEvJ+M 0ejf5lG5Nkc/kLnHvALcWxxPDkjBJYOcCj+esQMzEhonrPcibCTRAUH4WAP+JWgiH5paPHxsnnVI 84HxZmduTILA7rpXDhjvLpr3Etiga+kFpaHpaPi8TD8SHkXoUsCjvxInebnMMTzD9joiFgOgyY9m pFuiTdaBJQbpdqQACj7LzTWb4OE4y2BThihCQRxEV+ioratF4yUQvNs+ZUH7G6aXD+u5dHn5Hrwd Vw1Hr8Mvn4dGp+smWg9WY7ViYG4A++MnESLn/pmPNPW56MORcr3Ywx65LvKRRFHQV80MNNVIIb/b E/FmJUNS0nAiNs2fxBx1IK1jcmMGDw4nztJqDby1ORrp0XZ60Vzk50lJLVU3aPAaOpg+VBeHVOmm J1CJeyAvP/+/oYtKR5j/K3tJPsMpRmAYQqszKbrAKbkTidOIijlBO8n9pu0f9GBj39ItVQGL -----END CERTIFICATE----- SSL.com TLS RSA Root CA 2022 ============================ -----BEGIN CERTIFICATE----- MIIFiTCCA3GgAwIBAgIQb77arXO9CEDii02+1PdbkTANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQG EwJVUzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSUwIwYDVQQDDBxTU0wuY29tIFRMUyBSU0Eg Um9vdCBDQSAyMDIyMB4XDTIyMDgyNTE2MzQyMloXDTQ2MDgxOTE2MzQyMVowTjELMAkGA1UEBhMC VVMxGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjElMCMGA1UEAwwcU1NMLmNvbSBUTFMgUlNBIFJv b3QgQ0EgMjAyMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANCkCXJPQIgSYT41I57u 9nTPL3tYPc48DRAokC+X94xI2KDYJbFMsBFMF3NQ0CJKY7uB0ylu1bUJPiYYf7ISf5OYt6/wNr/y 7hienDtSxUcZXXTzZGbVXcdotL8bHAajvI9AI7YexoS9UcQbOcGV0insS657Lb85/bRi3pZ7Qcac oOAGcvvwB5cJOYF0r/c0WRFXCsJbwST0MXMwgsadugL3PnxEX4MN8/HdIGkWCVDi1FW24IBydm5M R7d1VVm0U3TZlMZBrViKMWYPHqIbKUBOL9975hYsLfy/7PO0+r4Y9ptJ1O4Fbtk085zx7AGL0SDG D6C1vBdOSHtRwvzpXGk3R2azaPgVKPC506QVzFpPulJwoxJF3ca6TvvC0PeoUidtbnm1jPx7jMEW TO6Af77wdr5BUxIzrlo4QqvXDz5BjXYHMtWrifZOZ9mxQnUjbvPNQrL8VfVThxc7wDNY8VLS+YCk 8OjwO4s4zKTGkH8PnP2L0aPP2oOnaclQNtVcBdIKQXTbYxE3waWglksejBYSd66UNHsef8JmAOSq g+qKkK3ONkRN0VHpvB/zagX9wHQfJRlAUW7qglFA35u5CCoGAtUjHBPW6dvbxrB6y3snm/vg1UYk 7RBLY0ulBY+6uB0rpvqR4pJSvezrZ5dtmi2fgTIFZzL7SAg/2SW4BCUvAgMBAAGjYzBhMA8GA1Ud EwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAU+y437uOEeicuzRk1sTN8/9REQrkwHQYDVR0OBBYEFPsu N+7jhHonLs0ZNbEzfP/UREK5MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAjYlt hEUY8U+zoO9opMAdrDC8Z2awms22qyIZZtM7QbUQnRC6cm4pJCAcAZli05bg4vsMQtfhWsSWTVTN j8pDU/0quOr4ZcoBwq1gaAafORpR2eCNJvkLTqVTJXojpBzOCBvfR4iyrT7gJ4eLSYwfqUdYe5by iB0YrrPRpgqU+tvT5TgKa3kSM/tKWTcWQA673vWJDPFs0/dRa1419dvAJuoSc06pkZCmF8NsLzjU o3KUQyxi4U5cMj29TH0ZR6LDSeeWP4+a0zvkEdiLA9z2tmBVGKaBUfPhqBVq6+AL8BQx1rmMRTqo ENjwuSfr98t67wVylrXEj5ZzxOhWc5y8aVFjvO9nHEMaX3cZHxj4HCUp+UmZKbaSPaKDN7Egkaib MOlqbLQjk2UEqxHzDh1TJElTHaE/nUiSEeJ9DU/1172iWD54nR4fK/4huxoTtrEoZP2wAgDHbICi vRZQIA9ygV/MlP+7mea6kMvq+cYMwq7FGc4zoWtcu358NFcXrfA/rs3qr5nsLFR+jM4uElZI7xc7 P0peYNLcdDa8pUNjyw9bowJWCZ4kLOGGgYz+qxcs+sjiMho6/4UIyYOf8kpIEFR3N+2ivEC+5BB0 9+Rbu7nzifmPQdjH5FCQNYA+HLhNkNPU98OwoX6EyneSMSy4kLGCenROmxMmtNVQZlR4rmA= -----END CERTIFICATE----- SSL.com TLS ECC Root CA 2022 ============================ -----BEGIN CERTIFICATE----- MIICOjCCAcCgAwIBAgIQFAP1q/s3ixdAW+JDsqXRxDAKBggqhkjOPQQDAzBOMQswCQYDVQQGEwJV UzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSUwIwYDVQQDDBxTU0wuY29tIFRMUyBFQ0MgUm9v dCBDQSAyMDIyMB4XDTIyMDgyNTE2MzM0OFoXDTQ2MDgxOTE2MzM0N1owTjELMAkGA1UEBhMCVVMx GDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjElMCMGA1UEAwwcU1NMLmNvbSBUTFMgRUNDIFJvb3Qg Q0EgMjAyMjB2MBAGByqGSM49AgEGBSuBBAAiA2IABEUpNXP6wrgjzhR9qLFNoFs27iosU8NgCTWy JGYmacCzldZdkkAZDsalE3D07xJRKF3nzL35PIXBz5SQySvOkkJYWWf9lCcQZIxPBLFNSeR7T5v1 5wj4A4j3p8OSSxlUgaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBSJjy+j6CugFFR7 81a4Jl9nOAuc0DAdBgNVHQ4EFgQUiY8vo+groBRUe/NWuCZfZzgLnNAwDgYDVR0PAQH/BAQDAgGG MAoGCCqGSM49BAMDA2gAMGUCMFXjIlbp15IkWE8elDIPDAI2wv2sdDJO4fscgIijzPvX6yv/N33w 7deedWo1dlJF4AIxAMeNb0Igj762TVntd00pxCAgRWSGOlDGxK0tk/UYfXLtqc/ErFc2KAhl3zx5 Zn6g6g== -----END CERTIFICATE----- Atos TrustedRoot Root CA ECC TLS 2021 ===================================== -----BEGIN CERTIFICATE----- MIICFTCCAZugAwIBAgIQPZg7pmY9kGP3fiZXOATvADAKBggqhkjOPQQDAzBMMS4wLAYDVQQDDCVB dG9zIFRydXN0ZWRSb290IFJvb3QgQ0EgRUNDIFRMUyAyMDIxMQ0wCwYDVQQKDARBdG9zMQswCQYD VQQGEwJERTAeFw0yMTA0MjIwOTI2MjNaFw00MTA0MTcwOTI2MjJaMEwxLjAsBgNVBAMMJUF0b3Mg VHJ1c3RlZFJvb3QgUm9vdCBDQSBFQ0MgVExTIDIwMjExDTALBgNVBAoMBEF0b3MxCzAJBgNVBAYT AkRFMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEloZYKDcKZ9Cg3iQZGeHkBQcfl+3oZIK59sRxUM6K DP/XtXa7oWyTbIOiaG6l2b4siJVBzV3dscqDY4PMwL502eCdpO5KTlbgmClBk1IQ1SQ4AjJn8ZQS b+/Xxd4u/RmAo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR2KCXWfeBmmnoJsmo7jjPX NtNPojAOBgNVHQ8BAf8EBAMCAYYwCgYIKoZIzj0EAwMDaAAwZQIwW5kp85wxtolrbNa9d+F851F+ uDrNozZffPc8dz7kUK2o59JZDCaOMDtuCCrCp1rIAjEAmeMM56PDr9NJLkaCI2ZdyQAUEv049OGY a3cpetskz2VAv9LcjBHo9H1/IISpQuQo -----END CERTIFICATE----- Atos TrustedRoot Root CA RSA TLS 2021 ===================================== -----BEGIN CERTIFICATE----- MIIFZDCCA0ygAwIBAgIQU9XP5hmTC/srBRLYwiqipDANBgkqhkiG9w0BAQwFADBMMS4wLAYDVQQD DCVBdG9zIFRydXN0ZWRSb290IFJvb3QgQ0EgUlNBIFRMUyAyMDIxMQ0wCwYDVQQKDARBdG9zMQsw CQYDVQQGEwJERTAeFw0yMTA0MjIwOTIxMTBaFw00MTA0MTcwOTIxMDlaMEwxLjAsBgNVBAMMJUF0 b3MgVHJ1c3RlZFJvb3QgUm9vdCBDQSBSU0EgVExTIDIwMjExDTALBgNVBAoMBEF0b3MxCzAJBgNV BAYTAkRFMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAtoAOxHm9BYx9sKOdTSJNy/BB l01Z4NH+VoyX8te9j2y3I49f1cTYQcvyAh5x5en2XssIKl4w8i1mx4QbZFc4nXUtVsYvYe+W/CBG vevUez8/fEc4BKkbqlLfEzfTFRVOvV98r61jx3ncCHvVoOX3W3WsgFWZkmGbzSoXfduP9LVq6hdK ZChmFSlsAvFr1bqjM9xaZ6cF4r9lthawEO3NUDPJcFDsGY6wx/J0W2tExn2WuZgIWWbeKQGb9Cpt 0xU6kGpn8bRrZtkh68rZYnxGEFzedUlnnkL5/nWpo63/dgpnQOPF943HhZpZnmKaau1Fh5hnstVK PNe0OwANwI8f4UDErmwh3El+fsqyjW22v5MvoVw+j8rtgI5Y4dtXz4U2OLJxpAmMkokIiEjxQGMY sluMWuPD0xeqqxmjLBvk1cbiZnrXghmmOxYsL3GHX0WelXOTwkKBIROW1527k2gV+p2kHYzygeBY Br3JtuP2iV2J+axEoctr+hbxx1A9JNr3w+SH1VbxT5Aw+kUJWdo0zuATHAR8ANSbhqRAvNncTFd+ rrcztl524WWLZt+NyteYr842mIycg5kDcPOvdO3GDjbnvezBc6eUWsuSZIKmAMFwoW4sKeFYV+xa fJlrJaSQOoD0IJ2azsct+bJLKZWD6TWNp0lIpw9MGZHQ9b8Q4HECAwEAAaNCMEAwDwYDVR0TAQH/ BAUwAwEB/zAdBgNVHQ4EFgQUdEmZ0f+0emhFdcN+tNzMzjkz2ggwDgYDVR0PAQH/BAQDAgGGMA0G CSqGSIb3DQEBDAUAA4ICAQAjQ1MkYlxt/T7Cz1UAbMVWiLkO3TriJQ2VSpfKgInuKs1l+NsW4AmS 4BjHeJi78+xCUvuppILXTdiK/ORO/auQxDh1MoSf/7OwKwIzNsAQkG8dnK/haZPso0UvFJ/1TCpl Q3IM98P4lYsU84UgYt1UU90s3BiVaU+DR3BAM1h3Egyi61IxHkzJqM7F78PRreBrAwA0JrRUITWX AdxfG/F851X6LWh3e9NpzNMOa7pNdkTWwhWaJuywxfW70Xp0wmzNxbVe9kzmWy2B27O3Opee7c9G slA9hGCZcbUztVdF5kJHdWoOsAgMrr3e97sPWD2PAzHoPYJQyi9eDF20l74gNAf0xBLh7tew2Vkt afcxBPTy+av5EzH4AXcOPUIjJsyacmdRIXrMPIWo6iFqO9taPKU0nprALN+AnCng33eU0aKAQv9q TFsR0PXNor6uzFFcw9VUewyu1rkGd4Di7wcaaMxZUa1+XGdrudviB0JbuAEFWDlN5LuYo7Ey7Nmj 1m+UI/87tyll5gfp77YZ6ufCOB0yiJA8EytuzO+rdwY0d4RPcuSBhPm5dDTedk+SKlOxJTnbPP/l PqYO5Wue/9vsL3SD3460s6neFE3/MaNFcyT6lSnMEpcEoji2jbDwN/zIIX8/syQbPYtuzE2wFg2W HYMfRsCbvUOZ58SWLs5fyQ== -----END CERTIFICATE----- TrustAsia Global Root CA G3 =========================== -----BEGIN CERTIFICATE----- MIIFpTCCA42gAwIBAgIUZPYOZXdhaqs7tOqFhLuxibhxkw8wDQYJKoZIhvcNAQEMBQAwWjELMAkG A1UEBhMCQ04xJTAjBgNVBAoMHFRydXN0QXNpYSBUZWNobm9sb2dpZXMsIEluYy4xJDAiBgNVBAMM G1RydXN0QXNpYSBHbG9iYWwgUm9vdCBDQSBHMzAeFw0yMTA1MjAwMjEwMTlaFw00NjA1MTkwMjEw MTlaMFoxCzAJBgNVBAYTAkNOMSUwIwYDVQQKDBxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMu MSQwIgYDVQQDDBtUcnVzdEFzaWEgR2xvYmFsIFJvb3QgQ0EgRzMwggIiMA0GCSqGSIb3DQEBAQUA A4ICDwAwggIKAoICAQDAMYJhkuSUGwoqZdC+BqmHO1ES6nBBruL7dOoKjbmzTNyPtxNST1QY4Sxz lZHFZjtqz6xjbYdT8PfxObegQ2OwxANdV6nnRM7EoYNl9lA+sX4WuDqKAtCWHwDNBSHvBm3dIZwZ Q0WhxeiAysKtQGIXBsaqvPPW5vxQfmZCHzyLpnl5hkA1nyDvP+uLRx+PjsXUjrYsyUQE49RDdT/V P68czH5GX6zfZBCK70bwkPAPLfSIC7Epqq+FqklYqL9joDiR5rPmd2jE+SoZhLsO4fWvieylL1Ag dB4SQXMeJNnKziyhWTXAyB1GJ2Faj/lN03J5Zh6fFZAhLf3ti1ZwA0pJPn9pMRJpxx5cynoTi+jm 9WAPzJMshH/x/Gr8m0ed262IPfN2dTPXS6TIi/n1Q1hPy8gDVI+lhXgEGvNz8teHHUGf59gXzhqc D0r83ERoVGjiQTz+LISGNzzNPy+i2+f3VANfWdP3kXjHi3dqFuVJhZBFcnAvkV34PmVACxmZySYg WmjBNb9Pp1Hx2BErW+Canig7CjoKH8GB5S7wprlppYiU5msTf9FkPz2ccEblooV7WIQn3MSAPmea mseaMQ4w7OYXQJXZRe0Blqq/DPNL0WP3E1jAuPP6Z92bfW1K/zJMtSU7/xxnD4UiWQWRkUF3gdCF TIcQcf+eQxuulXUtgQIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFEDk5PIj 7zjKsK5Xf/IhMBY027ySMB0GA1UdDgQWBBRA5OTyI+84yrCuV3/yITAWNNu8kjAOBgNVHQ8BAf8E BAMCAQYwDQYJKoZIhvcNAQEMBQADggIBACY7UeFNOPMyGLS0XuFlXsSUT9SnYaP4wM8zAQLpw6o1 D/GUE3d3NZ4tVlFEbuHGLige/9rsR82XRBf34EzC4Xx8MnpmyFq2XFNFV1pF1AWZLy4jVe5jaN/T G3inEpQGAHUNcoTpLrxaatXeL1nHo+zSh2bbt1S1JKv0Q3jbSwTEb93mPmY+KfJLaHEih6D4sTNj duMNhXJEIlU/HHzp/LgV6FL6qj6jITk1dImmasI5+njPtqzn59ZW/yOSLlALqbUHM/Q4X6RJpstl cHboCoWASzY9M/eVVHUl2qzEc4Jl6VL1XP04lQJqaTDFHApXB64ipCz5xUG3uOyfT0gA+QEEVcys +TIxxHWVBqB/0Y0n3bOppHKH/lmLmnp0Ft0WpWIp6zqW3IunaFnT63eROfjXy9mPX1onAX1daBli 2MjN9LdyR75bl87yraKZk62Uy5P2EgmVtqvXO9A/EcswFi55gORngS1d7XB4tmBZrOFdRWOPyN9y aFvqHbgB8X7754qz41SgOAngPN5C8sLtLpvzHzW2NtjjgKGLzZlkD8Kqq7HK9W+eQ42EVJmzbsAS ZthwEPEGNTNDqJwuuhQxzhB/HIbjj9LV+Hfsm6vxL2PZQl/gZ4FkkfGXL/xuJvYz+NO1+MRiqzFR JQJ6+N1rZdVtTTDIZbpoFGWsJwt0ivKH -----END CERTIFICATE----- TrustAsia Global Root CA G4 =========================== -----BEGIN CERTIFICATE----- MIICVTCCAdygAwIBAgIUTyNkuI6XY57GU4HBdk7LKnQV1tcwCgYIKoZIzj0EAwMwWjELMAkGA1UE BhMCQ04xJTAjBgNVBAoMHFRydXN0QXNpYSBUZWNobm9sb2dpZXMsIEluYy4xJDAiBgNVBAMMG1Ry dXN0QXNpYSBHbG9iYWwgUm9vdCBDQSBHNDAeFw0yMTA1MjAwMjEwMjJaFw00NjA1MTkwMjEwMjJa MFoxCzAJBgNVBAYTAkNOMSUwIwYDVQQKDBxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMuMSQw IgYDVQQDDBtUcnVzdEFzaWEgR2xvYmFsIFJvb3QgQ0EgRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNi AATxs8045CVD5d4ZCbuBeaIVXxVjAd7Cq92zphtnS4CDr5nLrBfbK5bKfFJV4hrhPVbwLxYI+hW8 m7tH5j/uqOFMjPXTNvk4XatwmkcN4oFBButJ+bAp3TPsUKV/eSm4IJijYzBhMA8GA1UdEwEB/wQF MAMBAf8wHwYDVR0jBBgwFoAUpbtKl86zK3+kMd6Xg1mDpm9xy94wHQYDVR0OBBYEFKW7SpfOsyt/ pDHel4NZg6ZvccveMA4GA1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNnADBkAjBe8usGzEkxn0AA bbd+NvBNEU/zy4k6LHiRUKNbwMp1JvK/kF0LgoxgKJ/GcJpo5PECMFxYDlZ2z1jD1xCMuo6u47xk dUfFVZDj/bpV6wfEU6s3qe4hsiFbYI89MvHVI5TWWA== -----END CERTIFICATE----- CommScope Public Trust ECC Root-01 ================================== -----BEGIN CERTIFICATE----- MIICHTCCAaOgAwIBAgIUQ3CCd89NXTTxyq4yLzf39H91oJ4wCgYIKoZIzj0EAwMwTjELMAkGA1UE BhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwiQ29tbVNjb3BlIFB1YmxpYyBUcnVz dCBFQ0MgUm9vdC0wMTAeFw0yMTA0MjgxNzM1NDNaFw00NjA0MjgxNzM1NDJaME4xCzAJBgNVBAYT AlVTMRIwEAYDVQQKDAlDb21tU2NvcGUxKzApBgNVBAMMIkNvbW1TY29wZSBQdWJsaWMgVHJ1c3Qg RUNDIFJvb3QtMDEwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAARLNumuV16ocNfQj3Rid8NeeqrltqLx eP0CflfdkXmcbLlSiFS8LwS+uM32ENEp7LXQoMPwiXAZu1FlxUOcw5tjnSCDPgYLpkJEhRGnSjot 6dZoL0hOUysHP029uax3OVejQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G A1UdDgQWBBSOB2LAUN3GGQYARnQE9/OufXVNMDAKBggqhkjOPQQDAwNoADBlAjEAnDPfQeMjqEI2 Jpc1XHvr20v4qotzVRVcrHgpD7oh2MSg2NED3W3ROT3Ek2DS43KyAjB8xX6I01D1HiXo+k515liW pDVfG2XqYZpwI7UNo5uSUm9poIyNStDuiw7LR47QjRE= -----END CERTIFICATE----- CommScope Public Trust ECC Root-02 ================================== -----BEGIN CERTIFICATE----- MIICHDCCAaOgAwIBAgIUKP2ZYEFHpgE6yhR7H+/5aAiDXX0wCgYIKoZIzj0EAwMwTjELMAkGA1UE BhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwiQ29tbVNjb3BlIFB1YmxpYyBUcnVz dCBFQ0MgUm9vdC0wMjAeFw0yMTA0MjgxNzQ0NTRaFw00NjA0MjgxNzQ0NTNaME4xCzAJBgNVBAYT AlVTMRIwEAYDVQQKDAlDb21tU2NvcGUxKzApBgNVBAMMIkNvbW1TY29wZSBQdWJsaWMgVHJ1c3Qg RUNDIFJvb3QtMDIwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAR4MIHoYx7l63FRD/cHB8o5mXxO1Q/M MDALj2aTPs+9xYa9+bG3tD60B8jzljHz7aRP+KNOjSkVWLjVb3/ubCK1sK9IRQq9qEmUv4RDsNuE SgMjGWdqb8FuvAY5N9GIIvejQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G A1UdDgQWBBTmGHX/72DehKT1RsfeSlXjMjZ59TAKBggqhkjOPQQDAwNnADBkAjAmc0l6tqvmSfR9 Uj/UQQSugEODZXW5hYA4O9Zv5JOGq4/nich/m35rChJVYaoR4HkCMHfoMXGsPHED1oQmHhS48zs7 3u1Z/GtMMH9ZzkXpc2AVmkzw5l4lIhVtwodZ0LKOag== -----END CERTIFICATE----- CommScope Public Trust RSA Root-01 ================================== -----BEGIN CERTIFICATE----- MIIFbDCCA1SgAwIBAgIUPgNJgXUWdDGOTKvVxZAplsU5EN0wDQYJKoZIhvcNAQELBQAwTjELMAkG A1UEBhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwiQ29tbVNjb3BlIFB1YmxpYyBU cnVzdCBSU0EgUm9vdC0wMTAeFw0yMTA0MjgxNjQ1NTRaFw00NjA0MjgxNjQ1NTNaME4xCzAJBgNV BAYTAlVTMRIwEAYDVQQKDAlDb21tU2NvcGUxKzApBgNVBAMMIkNvbW1TY29wZSBQdWJsaWMgVHJ1 c3QgUlNBIFJvb3QtMDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCwSGWjDR1C45Ft nYSkYZYSwu3D2iM0GXb26v1VWvZVAVMP8syMl0+5UMuzAURWlv2bKOx7dAvnQmtVzslhsuitQDy6 uUEKBU8bJoWPQ7VAtYXR1HHcg0Hz9kXHgKKEUJdGzqAMxGBWBB0HW0alDrJLpA6lfO741GIDuZNq ihS4cPgugkY4Iw50x2tBt9Apo52AsH53k2NC+zSDO3OjWiE260f6GBfZumbCk6SP/F2krfxQapWs vCQz0b2If4b19bJzKo98rwjyGpg/qYFlP8GMicWWMJoKz/TUyDTtnS+8jTiGU+6Xn6myY5QXjQ/c Zip8UlF1y5mO6D1cv547KI2DAg+pn3LiLCuz3GaXAEDQpFSOm117RTYm1nJD68/A6g3czhLmfTif BSeolz7pUcZsBSjBAg/pGG3svZwG1KdJ9FQFa2ww8esD1eo9anbCyxooSU1/ZOD6K9pzg4H/kQO9 lLvkuI6cMmPNn7togbGEW682v3fuHX/3SZtS7NJ3Wn2RnU3COS3kuoL4b/JOHg9O5j9ZpSPcPYeo KFgo0fEbNttPxP/hjFtyjMcmAyejOQoBqsCyMWCDIqFPEgkBEa801M/XrmLTBQe0MXXgDW1XT2mH +VepuhX2yFJtocucH+X8eKg1mp9BFM6ltM6UCBwJrVbl2rZJmkrqYxhTnCwuwwIDAQABo0IwQDAP BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUN12mmnQywsL5x6YVEFm4 5P3luG0wDQYJKoZIhvcNAQELBQADggIBAK+nz97/4L1CjU3lIpbfaOp9TSp90K09FlxD533Ahuh6 NWPxzIHIxgvoLlI1pKZJkGNRrDSsBTtXAOnTYtPZKdVUvhwQkZyybf5Z/Xn36lbQnmhUQo8mUuJM 3y+Xpi/SB5io82BdS5pYV4jvguX6r2yBS5KPQJqTRlnLX3gWsWc+QgvfKNmwrZggvkN80V4aCRck jXtdlemrwWCrWxhkgPut4AZ9HcpZuPN4KWfGVh2vtrV0KnahP/t1MJ+UXjulYPPLXAziDslg+Mkf Foom3ecnf+slpoq9uC02EJqxWE2aaE9gVOX2RhOOiKy8IUISrcZKiX2bwdgt6ZYD9KJ0DLwAHb/W NyVntHKLr4W96ioDj8z7PEQkguIBpQtZtjSNMgsSDesnwv1B10A8ckYpwIzqug/xBpMu95yo9GA+ o/E4Xo4TwbM6l4c/ksp4qRyv0LAbJh6+cOx69TOY6lz/KwsETkPdY34Op054A5U+1C0wlREQKC6/ oAI+/15Z0wUOlV9TRe9rh9VIzRamloPh37MG88EU26fsHItdkJANclHnYfkUyq+Dj7+vsQpZXdxc 1+SWrVtgHdqul7I52Qb1dgAT+GhMIbA1xNxVssnBQVocicCMb3SgazNNtQEo/a2tiRc7ppqEvOuM 6sRxJKi6KfkIsidWNTJf6jn7MZrVGczw -----END CERTIFICATE----- CommScope Public Trust RSA Root-02 ================================== -----BEGIN CERTIFICATE----- MIIFbDCCA1SgAwIBAgIUVBa/O345lXGN0aoApYYNK496BU4wDQYJKoZIhvcNAQELBQAwTjELMAkG A1UEBhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwiQ29tbVNjb3BlIFB1YmxpYyBU cnVzdCBSU0EgUm9vdC0wMjAeFw0yMTA0MjgxNzE2NDNaFw00NjA0MjgxNzE2NDJaME4xCzAJBgNV BAYTAlVTMRIwEAYDVQQKDAlDb21tU2NvcGUxKzApBgNVBAMMIkNvbW1TY29wZSBQdWJsaWMgVHJ1 c3QgUlNBIFJvb3QtMDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDh+g77aAASyE3V rCLENQE7xVTlWXZjpX/rwcRqmL0yjReA61260WI9JSMZNRTpf4mnG2I81lDnNJUDMrG0kyI9p+Kx 7eZ7Ti6Hmw0zdQreqjXnfuU2mKKuJZ6VszKWpCtYHu8//mI0SFHRtI1CrWDaSWqVcN3SAOLMV2MC e5bdSZdbkk6V0/nLKR8YSvgBKtJjCW4k6YnS5cciTNxzhkcAqg2Ijq6FfUrpuzNPDlJwnZXjfG2W Wy09X6GDRl224yW4fKcZgBzqZUPckXk2LHR88mcGyYnJ27/aaL8j7dxrrSiDeS/sOKUNNwFnJ5rp M9kzXzehxfCrPfp4sOcsn/Y+n2Dg70jpkEUeBVF4GiwSLFworA2iI540jwXmojPOEXcT1A6kHkIf hs1w/tkuFT0du7jyU1fbzMZ0KZwYszZ1OC4PVKH4kh+Jlk+71O6d6Ts2QrUKOyrUZHk2EOH5kQMr eyBUzQ0ZGshBMjTRsJnhkB4BQDa1t/qp5Xd1pCKBXbCL5CcSD1SIxtuFdOa3wNemKfrb3vOTlycE VS8KbzfFPROvCgCpLIscgSjX74Yxqa7ybrjKaixUR9gqiC6vwQcQeKwRoi9C8DfF8rhW3Q5iLc4t Vn5V8qdE9isy9COoR+jUKgF4z2rDN6ieZdIs5fq6M8EGRPbmz6UNp2YINIos8wIDAQABo0IwQDAP BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUR9DnsSL/nSz12Vdgs7Gx cJXvYXowDQYJKoZIhvcNAQELBQADggIBAIZpsU0v6Z9PIpNojuQhmaPORVMbc0RTAIFhzTHjCLqB KCh6krm2qMhDnscTJk3C2OVVnJJdUNjCK9v+5qiXz1I6JMNlZFxHMaNlNRPDk7n3+VGXu6TwYofF 1gbTl4MgqX67tiHCpQ2EAOHyJxCDut0DgdXdaMNmEMjRdrSzbymeAPnCKfWxkxlSaRosTKCL4BWa MS/TiJVZbuXEs1DIFAhKm4sTg7GkcrI7djNB3NyqpgdvHSQSn8h2vS/ZjvQs7rfSOBAkNlEv41xd gSGn2rtO/+YHqP65DSdsu3BaVXoT6fEqSWnHX4dXTEN5bTpl6TBcQe7rd6VzEojov32u5cSoHw2O HG1QAk8mGEPej1WFsQs3BWDJVTkSBKEqz3EWnzZRSb9wO55nnPt7eck5HHisd5FUmrh1CoFSl+Nm YWvtPjgelmFV4ZFUjO2MJB+ByRCac5krFk5yAD9UG/iNuovnFNa2RU9g7Jauwy8CTl2dlklyALKr dVwPaFsdZcJfMw8eD/A7hvWwTruc9+olBdytoptLFwG+Qt81IR2tq670v64fG9PiO/yzcnMcmyiQ iRM9HcEARwmWmjgb3bHPDcK0RPOWlc4yOo80nOAXx17Org3bhzjlP1v9mxnhMUF6cKojawHhRUzN lM47ni3niAIi9G7oyOzWPPO5std3eqx7 -----END CERTIFICATE----- Telekom Security TLS ECC Root 2020 ================================== -----BEGIN CERTIFICATE----- MIICQjCCAcmgAwIBAgIQNjqWjMlcsljN0AFdxeVXADAKBggqhkjOPQQDAzBjMQswCQYDVQQGEwJE RTEnMCUGA1UECgweRGV1dHNjaGUgVGVsZWtvbSBTZWN1cml0eSBHbWJIMSswKQYDVQQDDCJUZWxl a29tIFNlY3VyaXR5IFRMUyBFQ0MgUm9vdCAyMDIwMB4XDTIwMDgyNTA3NDgyMFoXDTQ1MDgyNTIz NTk1OVowYzELMAkGA1UEBhMCREUxJzAlBgNVBAoMHkRldXRzY2hlIFRlbGVrb20gU2VjdXJpdHkg R21iSDErMCkGA1UEAwwiVGVsZWtvbSBTZWN1cml0eSBUTFMgRUNDIFJvb3QgMjAyMDB2MBAGByqG SM49AgEGBSuBBAAiA2IABM6//leov9Wq9xCazbzREaK9Z0LMkOsVGJDZos0MKiXrPk/OtdKPD/M1 2kOLAoC+b1EkHQ9rK8qfwm9QMuU3ILYg/4gND21Ju9sGpIeQkpT0CdDPf8iAC8GXs7s1J8nCG6NC MEAwHQYDVR0OBBYEFONyzG6VmUex5rNhTNHLq+O6zd6fMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0P AQH/BAQDAgEGMAoGCCqGSM49BAMDA2cAMGQCMHVSi7ekEE+uShCLsoRbQuHmKjYC2qBuGT8lv9pZ Mo7k+5Dck2TOrbRBR2Diz6fLHgIwN0GMZt9Ba9aDAEH9L1r3ULRn0SyocddDypwnJJGDSA3PzfdU ga/sf+Rn27iQ7t0l -----END CERTIFICATE----- Telekom Security TLS RSA Root 2023 ================================== -----BEGIN CERTIFICATE----- MIIFszCCA5ugAwIBAgIQIZxULej27HF3+k7ow3BXlzANBgkqhkiG9w0BAQwFADBjMQswCQYDVQQG EwJERTEnMCUGA1UECgweRGV1dHNjaGUgVGVsZWtvbSBTZWN1cml0eSBHbWJIMSswKQYDVQQDDCJU ZWxla29tIFNlY3VyaXR5IFRMUyBSU0EgUm9vdCAyMDIzMB4XDTIzMDMyODEyMTY0NVoXDTQ4MDMy NzIzNTk1OVowYzELMAkGA1UEBhMCREUxJzAlBgNVBAoMHkRldXRzY2hlIFRlbGVrb20gU2VjdXJp dHkgR21iSDErMCkGA1UEAwwiVGVsZWtvbSBTZWN1cml0eSBUTFMgUlNBIFJvb3QgMjAyMzCCAiIw DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAO01oYGA88tKaVvC+1GDrib94W7zgRJ9cUD/h3VC KSHtgVIs3xLBGYSJwb3FKNXVS2xE1kzbB5ZKVXrKNoIENqil/Cf2SfHVcp6R+SPWcHu79ZvB7JPP GeplfohwoHP89v+1VmLhc2o0mD6CuKyVU/QBoCcHcqMAU6DksquDOFczJZSfvkgdmOGjup5czQRx UX11eKvzWarE4GC+j4NSuHUaQTXtvPM6Y+mpFEXX5lLRbtLevOP1Czvm4MS9Q2QTps70mDdsipWo l8hHD/BeEIvnHRz+sTugBTNoBUGCwQMrAcjnj02r6LX2zWtEtefdi+zqJbQAIldNsLGyMcEWzv/9 FIS3R/qy8XDe24tsNlikfLMR0cN3f1+2JeANxdKz+bi4d9s3cXFH42AYTyS2dTd4uaNir73Jco4v zLuu2+QVUhkHM/tqty1LkCiCc/4YizWN26cEar7qwU02OxY2kTLvtkCJkUPg8qKrBC7m8kwOFjQg rIfBLX7JZkcXFBGk8/ehJImr2BrIoVyxo/eMbcgByU/J7MT8rFEz0ciD0cmfHdRHNCk+y7AO+oML KFjlKdw/fKifybYKu6boRhYPluV75Gp6SG12mAWl3G0eQh5C2hrgUve1g8Aae3g1LDj1H/1Joy7S WWO/gLCMk3PLNaaZlSJhZQNg+y+TS/qanIA7AgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBBjAdBgNV HQ4EFgQUtqeXgj10hZv3PJ+TmpV5dVKMbUcwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBS2 p5eCPXSFm/c8n5OalXl1UoxtRzANBgkqhkiG9w0BAQwFAAOCAgEAqMxhpr51nhVQpGv7qHBFfLp+ sVr8WyP6Cnf4mHGCDG3gXkaqk/QeoMPhk9tLrbKmXauw1GLLXrtm9S3ul0A8Yute1hTWjOKWi0Fp kzXmuZlrYrShF2Y0pmtjxrlO8iLpWA1WQdH6DErwM807u20hOq6OcrXDSvvpfeWxm4bu4uB9tPcy /SKE8YXJN3nptT+/XOR0so8RYgDdGGah2XsjX/GO1WfoVNpbOms2b/mBsTNHM3dA+VKq3dSDz4V4 mZqTuXNnQkYRIer+CqkbGmVps4+uFrb2S1ayLfmlyOw7YqPta9BO1UAJpB+Y1zqlklkg5LB9zVtz aL1txKITDmcZuI1CfmwMmm6gJC3VRRvcxAIU/oVbZZfKTpBQCHpCNfnqwmbU+AGuHrS+w6jv/naa oqYfRvaE7fzbzsQCzndILIyy7MMAo+wsVRjBfhnu4S/yrYObnqsZ38aKL4x35bcF7DvB7L6Gs4a8 wPfc5+pbrrLMtTWGS9DiP7bY+A4A7l3j941Y/8+LN+ljX273CXE2whJdV/LItM3z7gLfEdxquVeE HVlNjM7IDiPCtyaaEBRx/pOyiriA8A4QntOoUAw3gi/q4Iqd4Sw5/7W0cwDk90imc6y/st53BIe0 o82bNSQ3+pCTE4FCxpgmdTdmQRCsu/WU48IxK63nI1bMNSWSs1A= -----END CERTIFICATE----- FIRMAPROFESIONAL CA ROOT-A WEB ============================== -----BEGIN CERTIFICATE----- MIICejCCAgCgAwIBAgIQMZch7a+JQn81QYehZ1ZMbTAKBggqhkjOPQQDAzBuMQswCQYDVQQGEwJF UzEcMBoGA1UECgwTRmlybWFwcm9mZXNpb25hbCBTQTEYMBYGA1UEYQwPVkFURVMtQTYyNjM0MDY4 MScwJQYDVQQDDB5GSVJNQVBST0ZFU0lPTkFMIENBIFJPT1QtQSBXRUIwHhcNMjIwNDA2MDkwMTM2 WhcNNDcwMzMxMDkwMTM2WjBuMQswCQYDVQQGEwJFUzEcMBoGA1UECgwTRmlybWFwcm9mZXNpb25h bCBTQTEYMBYGA1UEYQwPVkFURVMtQTYyNjM0MDY4MScwJQYDVQQDDB5GSVJNQVBST0ZFU0lPTkFM IENBIFJPT1QtQSBXRUIwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAARHU+osEaR3xyrq89Zfe9MEkVz6 iMYiuYMQYneEMy3pA4jU4DP37XcsSmDq5G+tbbT4TIqk5B/K6k84Si6CcyvHZpsKjECcfIr28jlg st7L7Ljkb+qbXbdTkBgyVcUgt5SjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUk+FD Y1w8ndYn81LsF7Kpryz3dvgwHQYDVR0OBBYEFJPhQ2NcPJ3WJ/NS7Beyqa8s93b4MA4GA1UdDwEB /wQEAwIBBjAKBggqhkjOPQQDAwNoADBlAjAdfKR7w4l1M+E7qUW/Runpod3JIha3RxEL2Jq68cgL cFBTApFwhVmpHqTm6iMxoAACMQD94vizrxa5HnPEluPBMBnYfubDl94cT7iJLzPrSA8Z94dGXSaQ pYXFuXqUPoeovQA= -----END CERTIFICATE----- TWCA CYBER Root CA ================== -----BEGIN CERTIFICATE----- MIIFjTCCA3WgAwIBAgIQQAE0jMIAAAAAAAAAATzyxjANBgkqhkiG9w0BAQwFADBQMQswCQYDVQQG EwJUVzESMBAGA1UEChMJVEFJV0FOLUNBMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJUV0NB IENZQkVSIFJvb3QgQ0EwHhcNMjIxMTIyMDY1NDI5WhcNNDcxMTIyMTU1OTU5WjBQMQswCQYDVQQG EwJUVzESMBAGA1UEChMJVEFJV0FOLUNBMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJUV0NB IENZQkVSIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDG+Moe2Qkgfh1s Ts6P40czRJzHyWmqOlt47nDSkvgEs1JSHWdyKKHfi12VCv7qze33Kc7wb3+szT3vsxxFavcokPFh V8UMxKNQXd7UtcsZyoC5dc4pztKFIuwCY8xEMCDa6pFbVuYdHNWdZsc/34bKS1PE2Y2yHer43CdT o0fhYcx9tbD47nORxc5zb87uEB8aBs/pJ2DFTxnk684iJkXXYJndzk834H/nY62wuFm40AZoNWDT Nq5xQwTxaWV4fPMf88oon1oglWa0zbfuj3ikRRjpJi+NmykosaS3Om251Bw4ckVYsV7r8Cibt4LK /c/WMw+f+5eesRycnupfXtuq3VTpMCEobY5583WSjCb+3MX2w7DfRFlDo7YDKPYIMKoNM+HvnKkH IuNZW0CP2oi3aQiotyMuRAlZN1vH4xfyIutuOVLF3lSnmMlLIJXcRolftBL5hSmO68gnFSDAS9TM fAxsNAwmmyYxpjyn9tnQS6Jk/zuZQXLB4HCX8SS7K8R0IrGsayIyJNN4KsDAoS/xUgXJP+92ZuJF 2A09rZXIx4kmyA+upwMu+8Ff+iDhcK2wZSA3M2Cw1a/XDBzCkHDXShi8fgGwsOsVHkQGzaRP6AzR wyAQ4VRlnrZR0Bp2a0JaWHY06rc3Ga4udfmW5cFZ95RXKSWNOkyrTZpB0F8mAwIDAQABo2MwYTAO BgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBSdhWEUfMFib5do5E83 QOGt4A1WNzAdBgNVHQ4EFgQUnYVhFHzBYm+XaORPN0DhreANVjcwDQYJKoZIhvcNAQEMBQADggIB AGSPesRiDrWIzLjHhg6hShbNcAu3p4ULs3a2D6f/CIsLJc+o1IN1KriWiLb73y0ttGlTITVX1olN c79pj3CjYcya2x6a4CD4bLubIp1dhDGaLIrdaqHXKGnK/nZVekZn68xDiBaiA9a5F/gZbG0jAn/x X9AKKSM70aoK7akXJlQKTcKlTfjF/biBzysseKNnTKkHmvPfXvt89YnNdJdhEGoHK4Fa0o635yDR IG4kqIQnoVesqlVYL9zZyvpoBJ7tRCT5dEA7IzOrg1oYJkK2bVS1FmAwbLGg+LhBoF1JSdJlBTrq /p1hvIbZv97Tujqxf36SNI7JAG7cmL3c7IAFrQI932XtCwP39xaEBDG6k5TY8hL4iuO/Qq+n1M0R FxbIQh0UqEL20kCGoE8jypZFVmAGzbdVAaYBlGX+bgUJurSkquLvWL69J1bY73NxW0Qz8ppy6rBe Pm6pUlvscG21h483XjyMnM7k8M4MZ0HMzvaAq07MTFb1wWFZk7Q+ptq4NxKfKjLji7gh7MMrZQzv It6IKTtM1/r+t+FHvpw+PoP7UV31aPcuIYXcv/Fa4nzXxeSDwWrruoBa3lwtcHb4yOWHh8qgnaHl IhInD0Q9HWzq1MKLL295q39QpsQZp6F6t5b5wR9iWqJDB0BeJsas7a5wFsWqynKKTbDPAYsDP27X -----END CERTIFICATE----- SecureSign Root CA12 ==================== -----BEGIN CERTIFICATE----- MIIDcjCCAlqgAwIBAgIUZvnHwa/swlG07VOX5uaCwysckBYwDQYJKoZIhvcNAQELBQAwUTELMAkG A1UEBhMCSlAxIzAhBgNVBAoTGkN5YmVydHJ1c3QgSmFwYW4gQ28uLCBMdGQuMR0wGwYDVQQDExRT ZWN1cmVTaWduIFJvb3QgQ0ExMjAeFw0yMDA0MDgwNTM2NDZaFw00MDA0MDgwNTM2NDZaMFExCzAJ BgNVBAYTAkpQMSMwIQYDVQQKExpDeWJlcnRydXN0IEphcGFuIENvLiwgTHRkLjEdMBsGA1UEAxMU U2VjdXJlU2lnbiBSb290IENBMTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6OcE3 emhFKxS06+QT61d1I02PJC0W6K6OyX2kVzsqdiUzg2zqMoqUm048luT9Ub+ZyZN+v/mtp7JIKwcc J/VMvHASd6SFVLX9kHrko+RRWAPNEHl57muTH2SOa2SroxPjcf59q5zdJ1M3s6oYwlkm7Fsf0uZl fO+TvdhYXAvA42VvPMfKWeP+bl+sg779XSVOKik71gurFzJ4pOE+lEa+Ym6b3kaosRbnhW70CEBF EaCeVESE99g2zvVQR9wsMJvuwPWW0v4JhscGWa5Pro4RmHvzC1KqYiaqId+OJTN5lxZJjfU+1Uef NzFJM3IFTQy2VYzxV4+Kh9GtxRESOaCtAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0P AQH/BAQDAgEGMB0GA1UdDgQWBBRXNPN0zwRL1SXm8UC2LEzZLemgrTANBgkqhkiG9w0BAQsFAAOC AQEAPrvbFxbS8hQBICw4g0utvsqFepq2m2um4fylOqyttCg6r9cBg0krY6LdmmQOmFxv3Y67ilQi LUoT865AQ9tPkbeGGuwAtEGBpE/6aouIs3YIcipJQMPTw4WJmBClnW8Zt7vPemVV2zfrPIpyMpce mik+rY3moxtt9XUa5rBouVui7mlHJzWhhpmA8zNL4WukJsPvdFlseqJkth5Ew1DgDzk9qTPxpfPS vWKErI4cqc1avTc7bgoitPQV55FYxTpE05Uo2cBl6XLK0A+9H7MV2anjpEcJnuDLN/v9vZfVvhga aaI5gdka9at/yOPiZwud9AzqVN/Ssq+xIvEg37xEHA== -----END CERTIFICATE----- SecureSign Root CA14 ==================== -----BEGIN CERTIFICATE----- MIIFcjCCA1qgAwIBAgIUZNtaDCBO6Ncpd8hQJ6JaJ90t8sswDQYJKoZIhvcNAQEMBQAwUTELMAkG A1UEBhMCSlAxIzAhBgNVBAoTGkN5YmVydHJ1c3QgSmFwYW4gQ28uLCBMdGQuMR0wGwYDVQQDExRT ZWN1cmVTaWduIFJvb3QgQ0ExNDAeFw0yMDA0MDgwNzA2MTlaFw00NTA0MDgwNzA2MTlaMFExCzAJ BgNVBAYTAkpQMSMwIQYDVQQKExpDeWJlcnRydXN0IEphcGFuIENvLiwgTHRkLjEdMBsGA1UEAxMU U2VjdXJlU2lnbiBSb290IENBMTQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDF0nqh 1oq/FjHQmNE6lPxauG4iwWL3pwon71D2LrGeaBLwbCRjOfHw3xDG3rdSINVSW0KZnvOgvlIfX8xn bacuUKLBl422+JX1sLrcneC+y9/3OPJH9aaakpUqYllQC6KxNedlsmGy6pJxaeQp8E+BgQQ8sqVb 1MWoWWd7VRxJq3qdwudzTe/NCcLEVxLbAQ4jeQkHO6Lo/IrPj8BGJJw4J+CDnRugv3gVEOuGTgpa /d/aLIJ+7sr2KeH6caH3iGicnPCNvg9JkdjqOvn90Ghx2+m1K06Ckm9mH+Dw3EzsytHqunQG+bOE kJTRX45zGRBdAuVwpcAQ0BB8b8VYSbSwbprafZX1zNoCr7gsfXmPvkPx+SgojQlD+Ajda8iLLCSx jVIHvXiby8posqTdDEx5YMaZ0ZPxMBoH064iwurO8YQJzOAUbn8/ftKChazcqRZOhaBgy/ac18iz ju3Gm5h1DVXoX+WViwKkrkMpKBGk5hIwAUt1ax5mnXkvpXYvHUC0bcl9eQjs0Wq2XSqypWa9a4X0 dFbD9ed1Uigspf9mR6XU/v6eVL9lfgHWMI+lNpyiUBzuOIABSMbHdPTGrMNASRZhdCyvjG817XsY AFs2PJxQDcqSMxDxJklt33UkN4Ii1+iW/RVLApY+B3KVfqs9TC7XyvDf4Fg/LS8EmjijAQIDAQAB o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUBpOjCl4oaTeq YR3r6/wtbyPk86AwDQYJKoZIhvcNAQEMBQADggIBAJaAcgkGfpzMkwQWu6A6jZJOtxEaCnFxEM0E rX+lRVAQZk5KQaID2RFPeje5S+LGjzJmdSX7684/AykmjbgWHfYfM25I5uj4V7Ibed87hwriZLoA ymzvftAj63iP/2SbNDefNWWipAA9EiOWWF3KY4fGoweITedpdopTzfFP7ELyk+OZpDc8h7hi2/Ds Hzc/N19DzFGdtfCXwreFamgLRB7lUe6TzktuhsHSDCRZNhqfLJGP4xjblJUK7ZGqDpncllPjYYPG FrojutzdfhrGe0K22VoF3Jpf1d+42kd92jjbrDnVHmtsKheMYc2xbXIBw8MgAGJoFjHVdqqGuw6q nsb58Nn4DSEC5MUoFlkRudlpcyqSeLiSV5sI8jrlL5WwWLdrIBRtFO8KvH7YVdiI2i/6GaX7i+B/ OfVyK4XELKzvGUWSTLNhB9xNH27SgRNcmvMSZ4PPmz+Ln52kuaiWA3rF7iDeM9ovnhp6dB7h7sxa OgTdsxoEqBRjrLdHEoOabPXm6RUVkRqEGQ6UROcSjiVbgGcZ3GOTEAtlLor6CZpO2oYofaphNdgO pygau1LgePhsumywbrmHXumZNTfxPWQrqaA0k89jL9WB365jJ6UeTo3cKXhZ+PmhIIynJkBugnLN eLLIjzwec+fBH7/PzqUqm9tEZDKgu39cJRNItX+S -----END CERTIFICATE----- SecureSign Root CA15 ==================== -----BEGIN CERTIFICATE----- MIICIzCCAamgAwIBAgIUFhXHw9hJp75pDIqI7fBw+d23PocwCgYIKoZIzj0EAwMwUTELMAkGA1UE BhMCSlAxIzAhBgNVBAoTGkN5YmVydHJ1c3QgSmFwYW4gQ28uLCBMdGQuMR0wGwYDVQQDExRTZWN1 cmVTaWduIFJvb3QgQ0ExNTAeFw0yMDA0MDgwODMyNTZaFw00NTA0MDgwODMyNTZaMFExCzAJBgNV BAYTAkpQMSMwIQYDVQQKExpDeWJlcnRydXN0IEphcGFuIENvLiwgTHRkLjEdMBsGA1UEAxMUU2Vj dXJlU2lnbiBSb290IENBMTUwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQLUHSNZDKZmbPSYAi4Io5G dCx4wCtELW1fHcmuS1Iggz24FG1Th2CeX2yF2wYUleDHKP+dX+Sq8bOLbe1PL0vJSpSRZHX+AezB 2Ot6lHhWGENfa4HL9rzatAy2KZMIaY+jQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD AgEGMB0GA1UdDgQWBBTrQciu/NWeUUj1vYv0hyCTQSvT9DAKBggqhkjOPQQDAwNoADBlAjEA2S6J fl5OpBEHvVnCB96rMjhTKkZEBhd6zlHp4P9mLQlO4E/0BdGF9jVg3PVys0Z9AjBEmEYagoUeYWmJ SwdLZrWeqrqgHkHZAXQ6bkU6iYAZezKYVWOr62Nuk22rGwlgMU4= -----END CERTIFICATE----- D-TRUST BR Root CA 2 2023 ========================= -----BEGIN CERTIFICATE----- MIIFqTCCA5GgAwIBAgIQczswBEhb2U14LnNLyaHcZjANBgkqhkiG9w0BAQ0FADBIMQswCQYDVQQG EwJERTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlELVRSVVNUIEJSIFJvb3QgQ0Eg MiAyMDIzMB4XDTIzMDUwOTA4NTYzMVoXDTM4MDUwOTA4NTYzMFowSDELMAkGA1UEBhMCREUxFTAT BgNVBAoTDEQtVHJ1c3QgR21iSDEiMCAGA1UEAxMZRC1UUlVTVCBCUiBSb290IENBIDIgMjAyMzCC AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK7/CVmRgApKaOYkP7in5Mg6CjoWzckjYaCT cfKri3OPoGdlYNJUa2NRb0kz4HIHE304zQaSBylSa053bATTlfrdTIzZXcFhfUvnKLNEgXtRr90z sWh81k5M/itoucpmacTsXld/9w3HnDY25QdgrMBM6ghs7wZ8T1soegj8k12b9py0i4a6Ibn08OhZ WiihNIQaJZG2tY/vsvmA+vk9PBFy2OMvhnbFeSzBqZCTRphny4NqoFAjpzv2gTng7fC5v2Xx2Mt6 ++9zA84A9H3X4F07ZrjcjrqDy4d2A/wl2ecjbwb9Z/Pg/4S8R7+1FhhGaRTMBffb00msa8yr5LUL QyReS2tNZ9/WtT5PeB+UcSTq3nD88ZP+npNa5JRal1QMNXtfbO4AHyTsA7oC9Xb0n9Sa7YUsOCIv x9gvdhFP/Wxc6PWOJ4d/GUohR5AdeY0cW/jPSoXk7bNbjb7EZChdQcRurDhaTyN0dKkSw/bSuREV MweR2Ds3OmMwBtHFIjYoYiMQ4EbMl6zWK11kJNXuHA7e+whadSr2Y23OC0K+0bpwHJwh5Q8xaRfX /Aq03u2AnMuStIv13lmiWAmlY0cL4UEyNEHZmrHZqLAbWt4NDfTisl01gLmB1IRpkQLLddCNxbU9 CZEJjxShFHR5PtbJFR2kWVki3PaKRT08EtY+XTIvAgMBAAGjgY4wgYswDwYDVR0TAQH/BAUwAwEB /zAdBgNVHQ4EFgQUZ5Dw1t61GNVGKX5cq/ieCLxklRAwDgYDVR0PAQH/BAQDAgEGMEkGA1UdHwRC MEAwPqA8oDqGOGh0dHA6Ly9jcmwuZC10cnVzdC5uZXQvY3JsL2QtdHJ1c3RfYnJfcm9vdF9jYV8y XzIwMjMuY3JsMA0GCSqGSIb3DQEBDQUAA4ICAQA097N3U9swFrktpSHxQCF16+tIFoE9c+CeJyrr d6kTpGoKWloUMz1oH4Guaf2Mn2VsNELZLdB/eBaxOqwjMa1ef67nriv6uvw8l5VAk1/DLQOj7aRv U9f6QA4w9QAgLABMjDu0ox+2v5Eyq6+SmNMW5tTRVFxDWy6u71cqqLRvpO8NVhTaIasgdp4D/Ca4 nj8+AybmTNudX0KEPUUDAxxZiMrcLmEkWqTqJwtzEr5SswrPMhfiHocaFpVIbVrg0M8JkiZmkdij YQ6qgYF/6FKC0ULn4B0Y+qSFNueG4A3rvNTJ1jxD8V1Jbn6Bm2m1iWKPiFLY1/4nwSPFyysCu7Ff /vtDhQNGvl3GyiEm/9cCnnRK3PgTFbGBVzbLZVzRHTF36SXDw7IyN9XxmAnkbWOACKsGkoHU6XCP pz+y7YaMgmo1yEJagtFSGkUPFaUA8JR7ZSdXOUPPfH/mvTWze/EZTN46ls/pdu4D58JDUjxqgejB WoC9EV2Ta/vH5mQ/u2kc6d0li690yVRAysuTEwrt+2aSEcr1wPrYg1UDfNPFIkZ1cGt5SAYqgpq/ 5usWDiJFAbzdNpQ0qTUmiteXue4Icr80knCDgKs4qllo3UCkGJCy89UDyibK79XH4I9TjvAA46jt n/mtd+ArY0+ew+43u3gJhJ65bvspmZDogNOfJA== -----END CERTIFICATE----- TrustAsia TLS ECC Root CA ========================= -----BEGIN CERTIFICATE----- MIICMTCCAbegAwIBAgIUNnThTXxlE8msg1UloD5Sfi9QaMcwCgYIKoZIzj0EAwMwWDELMAkGA1UE BhMCQ04xJTAjBgNVBAoTHFRydXN0QXNpYSBUZWNobm9sb2dpZXMsIEluYy4xIjAgBgNVBAMTGVRy dXN0QXNpYSBUTFMgRUNDIFJvb3QgQ0EwHhcNMjQwNTE1MDU0MTU2WhcNNDQwNTE1MDU0MTU1WjBY MQswCQYDVQQGEwJDTjElMCMGA1UEChMcVHJ1c3RBc2lhIFRlY2hub2xvZ2llcywgSW5jLjEiMCAG A1UEAxMZVHJ1c3RBc2lhIFRMUyBFQ0MgUm9vdCBDQTB2MBAGByqGSM49AgEGBSuBBAAiA2IABLh/ pVs/AT598IhtrimY4ZtcU5nb9wj/1WrgjstEpvDBjL1P1M7UiFPoXlfXTr4sP/MSpwDpguMqWzJ8 S5sUKZ74LYO1644xST0mYekdcouJtgq7nDM1D9rs3qlKH8kzsaNCMEAwDwYDVR0TAQH/BAUwAwEB /zAdBgNVHQ4EFgQULIVTu7FDzTLqnqOH/qKYqKaT6RAwDgYDVR0PAQH/BAQDAgEGMAoGCCqGSM49 BAMDA2gAMGUCMFRH18MtYYZI9HlaVQ01L18N9mdsd0AaRuf4aFtOJx24mH1/k78ITcTaRTChD15K eAIxAKORh/IRM4PDwYqROkwrULG9IpRdNYlzg8WbGf60oenUoWa2AaU2+dhoYSi3dOGiMQ== -----END CERTIFICATE----- TrustAsia TLS RSA Root CA ========================= -----BEGIN CERTIFICATE----- MIIFgDCCA2igAwIBAgIUHBjYz+VTPyI1RlNUJDxsR9FcSpwwDQYJKoZIhvcNAQEMBQAwWDELMAkG A1UEBhMCQ04xJTAjBgNVBAoTHFRydXN0QXNpYSBUZWNobm9sb2dpZXMsIEluYy4xIjAgBgNVBAMT GVRydXN0QXNpYSBUTFMgUlNBIFJvb3QgQ0EwHhcNMjQwNTE1MDU0MTU3WhcNNDQwNTE1MDU0MTU2 WjBYMQswCQYDVQQGEwJDTjElMCMGA1UEChMcVHJ1c3RBc2lhIFRlY2hub2xvZ2llcywgSW5jLjEi MCAGA1UEAxMZVHJ1c3RBc2lhIFRMUyBSU0EgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIP ADCCAgoCggIBAMMWuBtqpERz5dZO9LnPWwvB0ZqB9WOwj0PBuwhaGnrhB3YmH49pVr7+NmDQDIPN lOrnxS1cLwUWAp4KqC/lYCZUlviYQB2srp10Zy9U+5RjmOMmSoPGlbYJQ1DNDX3eRA5gEk9bNb2/ mThtfWza4mhzH/kxpRkQcwUqwzIZheo0qt1CHjCNP561HmHVb70AcnKtEj+qpklz8oYVlQwQX1Fk zv93uMltrOXVmPGZLmzjyUT5tUMnCE32ft5EebuyjBza00tsLtbDeLdM1aTk2tyKjg7/D8OmYCYo zza/+lcK7Fs/6TAWe8TbxNRkoDD75f0dcZLdKY9BWN4ArTr9PXwaqLEX8E40eFgl1oUh63kd0Nyr z2I8sMeXi9bQn9P+PN7F4/w6g3CEIR0JwqH8uyghZVNgepBtljhb//HXeltt08lwSUq6HTrQUNoy IBnkiz/r1RYmNzz7dZ6wB3C4FGB33PYPXFIKvF1tjVEK2sUYyJtt3LCDs3+jTnhMmCWr8n4uIF6C FabW2I+s5c0yhsj55NqJ4js+k8UTav/H9xj8Z7XvGCxUq0DTbE3txci3OE9kxJRMT6DNrqXGJyV1 J23G2pyOsAWZ1SgRxSHUuPzHlqtKZFlhaxP8S8ySpg+kUb8OWJDZgoM5pl+z+m6Ss80zDoWo8SnT q1mt1tve1CuBAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFLgHkXlcBvRG/XtZ ylomkadFK/hTMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQwFAAOCAgEAIZtqBSBdGBanEqT3 Rz/NyjuujsCCztxIJXgXbODgcMTWltnZ9r96nBO7U5WS/8+S4PPFJzVXqDuiGev4iqME3mmL5Dw8 veWv0BIb5Ylrc5tvJQJLkIKvQMKtuppgJFqBTQUYo+IzeXoLH5Pt7DlK9RME7I10nYEKqG/odv6L TytpEoYKNDbdgptvT+Bz3Ul/KD7JO6NXBNiT2Twp2xIQaOHEibgGIOcberyxk2GaGUARtWqFVwHx tlotJnMnlvm5P1vQiJ3koP26TpUJg3933FEFlJ0gcXax7PqJtZwuhfG5WyRasQmr2soaB82G39tp 27RIGAAtvKLEiUUjpQ7hRGU+isFqMB3iYPg6qocJQrmBktwliJiJ8Xw18WLK7nn4GS/+X/jbh87q qA8MpugLoDzga5SYnH+tBuYc6kIQX+ImFTw3OffXvO645e8D7r0i+yiGNFjEWn9hongPXvPKnbwb PKfILfanIhHKA9jnZwqKDss1jjQ52MjqjZ9k4DewbNfFj8GQYSbbJIweSsCI3zWQzj8C9GRh3sfI B5XeMhg6j6JCQCTl1jNdfK7vsU1P1FeQNWrcrgSXSYk0ly4wBOeY99sLAZDBHwo/+ML+TvrbmnNz FrwFuHnYWa8G5z9nODmxfKuU4CkUpijy323imttUQ/hHWKNddBWcwauwxzQ= -----END CERTIFICATE----- D-TRUST EV Root CA 2 2023 ========================= -----BEGIN CERTIFICATE----- MIIFqTCCA5GgAwIBAgIQaSYJfoBLTKCnjHhiU19abzANBgkqhkiG9w0BAQ0FADBIMQswCQYDVQQG EwJERTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlELVRSVVNUIEVWIFJvb3QgQ0Eg MiAyMDIzMB4XDTIzMDUwOTA5MTAzM1oXDTM4MDUwOTA5MTAzMlowSDELMAkGA1UEBhMCREUxFTAT BgNVBAoTDEQtVHJ1c3QgR21iSDEiMCAGA1UEAxMZRC1UUlVTVCBFViBSb290IENBIDIgMjAyMzCC AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANiOo4mAC7JXUtypU0w3uX9jFxPvp1sjW2l1 sJkKF8GLxNuo4MwxusLyzV3pt/gdr2rElYfXR8mV2IIEUD2BCP/kPbOx1sWy/YgJ25yE7CUXFId/ MHibaljJtnMoPDT3mfd/06b4HEV8rSyMlD/YZxBTfiLNTiVR8CUkNRFeEMbsh2aJgWi6zCudR3Mf vc2RpHJqnKIbGKBv7FD0fUDCqDDPvXPIEysQEx6Lmqg6lHPTGGkKSv/BAQP/eX+1SH977ugpbzZM lWGG2Pmic4ruri+W7mjNPU0oQvlFKzIbRlUWaqZLKfm7lVa/Rh3sHZMdwGWyH6FDrlaeoLGPaxK3 YG14C8qKXO0elg6DpkiVjTujIcSuWMYAsoS0I6SWhjW42J7YrDRJmGOVxcttSEfi8i4YHtAxq910 7PncjLgcjmgjutDzUNzPZY9zOjLHfP7KgiJPvo5iR2blzYfi6NUPGJ/lBHJLRjwQ8kTCZFZxTnXo nMkmdMV9WdEKWw9t/p51HBjGGjp82A0EzM23RWV6sY+4roRIPrN6TagD4uJ+ARZZaBhDM7DS3LAa QzXupdqpRlyuhoFBAUp0JuyfBr/CBTdkdXgpaP3F9ev+R/nkhbDhezGdpn9yo7nELC7MmVcOIQxF AZRl62UJxmMiCzNJkkg8/M3OsD6Onov4/knFNXJHAgMBAAGjgY4wgYswDwYDVR0TAQH/BAUwAwEB /zAdBgNVHQ4EFgQUqvyREBuHkV8Wub9PS5FeAByxMoAwDgYDVR0PAQH/BAQDAgEGMEkGA1UdHwRC MEAwPqA8oDqGOGh0dHA6Ly9jcmwuZC10cnVzdC5uZXQvY3JsL2QtdHJ1c3RfZXZfcm9vdF9jYV8y XzIwMjMuY3JsMA0GCSqGSIb3DQEBDQUAA4ICAQCTy6UfmRHsmg1fLBWTxj++EI14QvBukEdHjqOS Mo1wj/Zbjb6JzkcBahsgIIlbyIIQbODnmaprxiqgYzWRaoUlrRc4pZt+UPJ26oUFKidBK7GB0aL2 QHWpDsvxVUjY7NHss+jOFKE17MJeNRqrphYBBo7q3C+jisosketSjl8MmxfPy3MHGcRqwnNU73xD UmPBEcrCRbH0O1P1aa4846XerOhUt7KR/aypH/KH5BfGSah82ApB9PI+53c0BFLd6IHyTS9URZ0V 4U/M5d40VxDJI3IXcI1QcB9WbMy5/zpaT2N6w25lBx2Eof+pDGOJbbJAiDnXH3dotfyc1dZnaVuo dNv8ifYbMvekJKZ2t0dT741Jj6m2g1qllpBFYfXeA08mD6iL8AOWsKwV0HFaanuU5nCT2vFp4LJi TZ6P/4mdm13NRemUAiKN4DV/6PEEeXFsVIP4M7kFMhtYVRFP0OUnR3Hs7dpn1mKmS00PaaLJvOwi S5THaJQXfuKOKD62xur1NGyfN4gHONuGcfrNlUhDbqNPgofXNJhuS5N5YHVpD/Aa1VP6IQzCP+k/ HxiMkl14p3ZnGbuy6n/pcAlWVqOwDAstNl7F6cTVg8uGF5csbBNvh1qvSaYd2804BC5f4ko1Di1L +KIkBI3Y4WNeApI02phhXBxvWHZks/wCuPWdCg== -----END CERTIFICATE----- SwissSign RSA TLS Root CA 2022 - 1 ================================== -----BEGIN CERTIFICATE----- MIIFkzCCA3ugAwIBAgIUQ/oMX04bgBhE79G0TzUfRPSA7cswDQYJKoZIhvcNAQELBQAwUTELMAkG A1UEBhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzErMCkGA1UEAxMiU3dpc3NTaWduIFJTQSBU TFMgUm9vdCBDQSAyMDIyIC0gMTAeFw0yMjA2MDgxMTA4MjJaFw00NzA2MDgxMTA4MjJaMFExCzAJ BgNVBAYTAkNIMRUwEwYDVQQKEwxTd2lzc1NpZ24gQUcxKzApBgNVBAMTIlN3aXNzU2lnbiBSU0Eg VExTIFJvb3QgQ0EgMjAyMiAtIDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDLKmji C8NXvDVjvHClO/OMPE5Xlm7DTjak9gLKHqquuN6orx122ro10JFwB9+zBvKK8i5VUXu7LCTLf5Im gKO0lPaCoaTo+nUdWfMHamFk4saMla+ju45vVs9xzF6BYQ1t8qsCLqSX5XH8irCRIFucdFJtrhUn WXjyCcplDn/L9Ovn3KlMd/YrFgSVrpxxpT8q2kFC5zyEEPThPYxr4iuRR1VPuFa+Rd4iUU1OKNlf GUEGjw5NBuBwQCMBauTLE5tzrE0USJIt/m2n+IdreXXhvhCxqohAWVTXz8TQm0SzOGlkjIHRI36q OTw7D59Ke4LKa2/KIj4x0LDQKhySio/YGZxH5D4MucLNvkEM+KRHBdvBFzA4OmnczcNpI/2aDwLO EGrOyvi5KaM2iYauC8BPY7kGWUleDsFpswrzd34unYyzJ5jSmY0lpx+Gs6ZUcDj8fV3oT4MM0ZPl EuRU2j7yrTrePjxF8CgPBrnh25d7mUWe3f6VWQQvdT/TromZhqwUtKiE+shdOxtYk8EXlFXIC+OC eYSf8wCENO7cMdWP8vpPlkwGqnj73mSiI80fPsWMvDdUDrtaclXvyFu1cvh43zcgTFeRc5JzrBh3 Q4IgaezprClG5QtO+DdziZaKHG29777YtvTKwP1H8K4LWCDFyB02rpeNUIMmJCn3nTsPBQIDAQAB o2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBRvjmKLk0Ow 4UD2p8P98Q+4DxU4pTAdBgNVHQ4EFgQUb45ii5NDsOFA9qfD/fEPuA8VOKUwDQYJKoZIhvcNAQEL BQADggIBAKwsKUF9+lz1GpUYvyypiqkkVHX1uECry6gkUSsYP2OprphWKwVDIqO310aewCoSPY6W lkDfDDOLazeROpW7OSltwAJsipQLBwJNGD77+3v1dj2b9l4wBlgzHqp41eZUBDqyggmNzhYzWUUo 8aWjlw5DI/0LIICQ/+Mmz7hkkeUFjxOgdg3XNwwQiJb0Pr6VvfHDffCjw3lHC1ySFWPtUnWK50Zp y1FVCypM9fJkT6lc/2cyjlUtMoIcgC9qkfjLvH4YoiaoLqNTKIftV+Vlek4ASltOU8liNr3Cjlvr zG4ngRhZi0Rjn9UMZfQpZX+RLOV/fuiJz48gy20HQhFRJjKKLjpHE7iNvUcNCfAWpO2Whi4Z2L6M OuhFLhG6rlrnub+xzI/goP+4s9GFe3lmozm1O2bYQL7Pt2eLSMkZJVX8vY3PXtpOpvJpzv1/THfQ wUY1mFwjmwJFQ5Ra3bxHrSL+ul4vkSkphnsh3m5kt8sNjzdbowhq6/TdAo9QAwKxuDdollDruF/U KIqlIgyKhPBZLtU30WHlQnNYKoH3dtvi4k0NX/a3vgW0rk4N3hY9A4GzJl5LuEsAz/+MF7psYC0n hzck5npgL7XTgwSqT0N1osGDsieYK7EOgLrAhV5Cud+xYJHT6xh+cHiudoO+cVrQkOPKwRYlZ0rw tnu64ZzZ -----END CERTIFICATE----- ================================================ FILE: app/resources/i18n/aifilesorter_de.ts ================================================ CategorizationDialog Tip: Click %1 cells to rename them. Tipp: Klicken Sie auf die %1-Zellen, um sie umzubenennen. No items selected Keine Elemente ausgewählt Highlight one or more rows to select them for processing. Markieren Sie eine oder mehrere Zeilen, um sie für die Verarbeitung auszuwählen. Bulk edit unavailable Sammelbearbeitung nicht verfügbar Bulk editing categories is unavailable while picture rename-only mode is active. Die Sammelbearbeitung von Kategorien ist nicht verfügbar, solange der Nur-Umbenennen-Modus für Bilder aktiv ist. Highlight one or more rows to edit their categories. Markieren Sie eine oder mehrere Zeilen, um deren Kategorien zu bearbeiten. Preview Vorschau Review and Confirm Prüfen und bestätigen Select all Alle auswählen Select highlighted Markierte auswählen Edit selected... Ausgewählte bearbeiten... Create subcategory folders Unterkategorie-Ordner erstellen Dry run (preview only, do not move files) Probelauf (nur Vorschau, keine Dateien verschieben) Do not categorize picture files (only rename) Bilddateien nicht kategorisieren (nur umbenennen) Do not categorize document files (only rename) Dokumentdateien nicht kategorisieren (nur umbenennen) Confirm and Process Bestätigen und verarbeiten Continue Later Später fortsetzen Undo this change Diese Änderung rückgängig machen Close Schließen Mark highlighted rows for processing (Ctrl+Space). Markieren Sie hervorgehobene Zeilen zur Verarbeitung (Strg+Leertaste). Apply category/subcategory values to highlighted rows. Wenden Sie Kategorie-/Unterkategorie-Werte auf die markierten Zeilen an. Process Verarbeiten File Datei Type Typ Suggested filename Vorgeschlagener Dateiname Category Kategorie Subcategory Unterkategorie Status Status Planned destination Geplantes Ziel Moved Verschoben Renamed Umbenannt Renamed & Moved Umbenannt und verschoben Skipped Übersprungen Not selected Nicht ausgewählt CategorizationProgressDialog [STOP] Analysis will stop after the current item is processed. [STOPP] Analyse wird nach dem aktuellen Element beendet. Image analysis Bildanalyse Document analysis Dokumentanalyse Categorization Kategorisierung Directory Ordner Image Bild Document Dokument File Datei Type Typ Stage %1: %2 Phase %1: %2 Pending Ausstehend In progress In Bearbeitung Complete Abgeschlossen Processed 0/0 | In progress: 0 | Pending: 0 Verarbeitet 0/0 | In Bearbeitung: 0 | Ausstehend: 0 Processed %1/%2 | In progress: %3 | Pending: %4 Verarbeitet %1/%2 | In Bearbeitung: %3 | Ausstehend: %4 Analyzing Files Dateien analysieren Stop Analysis Analyse stoppen Activity log Aktivitätsprotokoll CustomApiDialog Custom OpenAI-compatible API Benutzerdefinierte OpenAI-kompatible API e.g. http://localhost:1234/v1 z. B. http://localhost:1234/v1 e.g. llama-3.1, gpt-4o-mini z. B. llama-3.1, gpt-4o-mini Show Anzeigen Display name Anzeigename Description Beschreibung Base URL or endpoint Basis-URL oder Endpunkt Model Modell API key (optional) API-Schlüssel (optional) Enter a base URL (e.g. http://localhost:1234/v1) or a full /chat/completions endpoint. Geben Sie eine Basis-URL ein (z. B. http://localhost:1234/v1) oder einen vollständigen Endpunkt für /chat/completions. CustomLLMDialog Custom local LLM Benutzerdefiniertes lokales LLM Browse… Durchsuchen… Display name Anzeigename Description Beschreibung Model file (.gguf) Modelldatei (.gguf) Select .gguf model .gguf-Modell auswählen GGUF models (*.gguf);;All files (*.*) GGUF-Modelle (*.gguf);;Alle Dateien (*.*) DryRunPreviewDialog Dry run preview Vorschau Probelauf From Von To Nach Close Schließen LLMSelectionDialog Choose LLM Mode LLM-Modus auswählen Select LLM Mode LLM-Modus auswählen Larger local model. Slower on CPU, but performs much better with GPU acceleration. Supports: Nvidia (CUDA), Apple (Metal), CPU. Größeres lokales Modell. Auf der CPU langsamer, mit GPU-Beschleunigung jedoch deutlich besser. Unterstützt: Nvidia (CUDA), Apple (Metal), CPU. Recommended Empfohlen Smaller local model that works quickly even on CPUs. Good for lightweight local use. Kleineres lokales Modell, das auch auf CPUs schnell arbeitet. Gut für leichte lokale Nutzung. Legacy model kept for existing downloads. Altes Modell wird für bestehende Downloads beibehalten. Gemini (Google AI Studio API key) Gemini (Google AI Studio API-Schlüssel) Use Google's Gemini models with your AI Studio API key (internet required). Verwenden Sie Googles Gemini-Modelle mit Ihrem AI Studio API-Schlüssel (Internet erforderlich). AIza... AIza... Show Anzeigen Gemini API key Gemini-API-Schlüssel e.g. gemini-2.5-flash-lite, gemini-2.5-flash, gemini-2.5-pro z. B. gemini-2.5-flash-lite, gemini-2.5-flash, gemini-2.5-pro Model Modell Your key is stored locally in the config file for this device. Ihr Schlüssel wird lokal in der Konfigurationsdatei dieses Geräts gespeichert. <a href="https://aistudio.google.com/app/apikey">Get a Gemini API key</a> <a href="https://aistudio.google.com/app/apikey">Gemini-API-Schlüssel abrufen</a> ChatGPT (OpenAI API key) ChatGPT (OpenAI API-Schlüssel) Use your own OpenAI API key to access ChatGPT models (internet required). Verwenden Sie Ihren eigenen OpenAI API-Schlüssel, um auf ChatGPT-Modelle zuzugreifen (Internet erforderlich). sk-... sk-... OpenAI API key OpenAI-API-Schlüssel e.g. gpt-4o-mini, gpt-4.1, o3-mini z. B. gpt-4o-mini, gpt-4.1, o3-mini <a href="https://platform.openai.com/api-keys">Get an OpenAI API key</a> <a href="https://platform.openai.com/api-keys">OpenAI-API-Schlüssel abrufen</a> Custom OpenAI-compatible API (advanced) Benutzerdefinierte OpenAI-kompatible API (erweitert) Use OpenAI-compatible endpoints such as LM Studio or Ollama (local or remote). Verwenden Sie OpenAI-kompatible Endpunkte wie LM Studio oder Ollama (lokal oder remote). Add… Hinzufügen… Edit… Bearbeiten… Delete Löschen Custom local LLM (gguf) Benutzerdefiniertes lokales LLM (gguf) Downloads Downloads Download Download Image analysis models (LLaVA) Bildanalyse-Modelle (LLaVA) Download the visual LLM files required for image analysis. Laden Sie die für die Bildanalyse erforderlichen visuellen LLM-Dateien herunter. LLaVA 1.6 Mistral 7B (text model) LLaVA 1.6 Mistral 7B (Textmodell) LLaVA mmproj (vision encoder) LLaVA mmproj (Vision-Encoder) Choose or add a custom model. Wählen Sie ein benutzerdefiniertes Modell aus oder fügen Sie eines hinzu. Custom model selected. Benutzerdefiniertes Modell ausgewählt. Selection ready. Auswahl bereit. Choose or add a custom API endpoint. Wählen Sie einen benutzerdefinierten API-Endpunkt aus oder fügen Sie einen hinzu. Custom API selected. Benutzerdefinierte API ausgewählt. ChatGPT will use your API key and model. ChatGPT verwendet Ihren API-Schlüssel und Ihr Modell. Enter your OpenAI API key and model to continue. Geben Sie Ihren OpenAI API-Schlüssel und Ihr Modell ein, um fortzufahren. Gemini will use your API key and model. Gemini verwendet Ihren API-Schlüssel und Ihr Modell. Enter your Gemini API key and model to continue. Geben Sie Ihren Gemini API-Schlüssel und Ihr Modell ein, um fortzufahren. Model ready. Modell bereit. Resume download Download fortsetzen Partial download detected. You can resume. Teilweiser Download erkannt. Sie können fortsetzen. Download required. Download erforderlich. Unsupported LLM selection. Nicht unterstützte LLM-Auswahl. Missing download URL environment variable (%1). Umgebungsvariable für die Download-URL fehlt (%1). Delete downloaded model? Heruntergeladenes Modell löschen? Delete the downloaded model %1? Heruntergeladenes Modell %1 löschen? Failed to delete downloaded model. Heruntergeladenes Modell konnte nicht gelöscht werden. Deleted downloaded model. Heruntergeladenes Modell gelöscht. No downloaded model found to delete. Kein heruntergeladenes Modell zum Löschen gefunden. Remote URL Remote-URL Local path Lokaler Pfad File size Dateigröße File size: unknown Dateigröße: unbekannt Delete custom model Benutzerdefiniertes Modell löschen Remove '%1' from your custom LLMs? This does not delete the file on disk. '%1' aus Ihren benutzerdefinierten LLMs entfernen? Dadurch wird die Datei auf der Festplatte nicht gelöscht. Delete custom API Benutzerdefinierte API löschen Remove '%1' from your custom API list? This does not affect the server. '%1' aus Ihrer Liste benutzerdefinierter APIs entfernen? Dies hat keine Auswirkungen auf den Server. Missing download URL environment variable. Umgebungsvariable für die Download-URL fehlt. Downloading… Download läuft… Download complete. Download abgeschlossen. Download cancelled. Download abgebrochen. Download error: %1 Download-Fehler: %1 MainApp File Explorer Datei-Explorer Select Directory Ordner auswählen Loaded folder %1 Ordner %1 geladen Analysis cancelled Analyse abgebrochen Folder selected: %1 Ordner ausgewählt: %1 More consistent Einheitlicher More refined Ausführlicher Recategorize folder? Ordner neu kategorisieren? This folder was categorized using the %1 mode. Do you want to recategorize it now using the %2 mode? Dieser Ordner wurde im Modus %1 kategorisiert. Möchten Sie ihn jetzt im Modus %2 neu kategorisieren? Recategorize Neu kategorisieren Keep existing Beibehalten Failed to reset cached categorization for this folder. Zurücksetzen der zwischengespeicherten Kategorisierung für diesen Ordner fehlgeschlagen. Download required Download erforderlich Image analysis requires visual LLM files. Download them now? Die Bildanalyse erfordert visuelle LLM-Dateien. Jetzt herunterladen? OK OK Stop analyzing Analyse stoppen Analyzing… Analysiere… Analyze folder Ordner analysieren Ready Bereit Undo last run Letzten Durchlauf rückgängig machen This will attempt to move files back to their original locations based on the last run. Plan file: %1 Dadurch wird versucht, Dateien basierend auf dem letzten Durchlauf an ihre ursprünglichen Speicherorte zurückzuverschieben. Plandatei: %1 Restored %1 file(s). Skipped %2. %1 Datei(en) wiederhergestellt. %2 übersprungen. Undo complete Rückgängig abgeschlossen Thank you for using AI File Sorter! You have categorized %1 files thus far. I, the author, really hope this app was useful for you. Vielen Dank, dass du AI File Sorter verwendest! Du hast bisher %1 Dateien kategorisiert. Ich, der Autor, hoffe wirklich, dass dir die App geholfen hat. AI File Sorter takes hundreds of hours of development, feature work, support replies, and ongoing costs such as servers and remote-model infrastructure. If the app saves you time or brings value, please consider supporting it so it can keep improving. AI File Sorter erfordert Hunderte Stunden Entwicklungsarbeit, Funktionsarbeit, Supportantworten und laufende Kosten wie Server sowie Infrastruktur für Remote-Modelle. Wenn die App Ihnen Zeit spart oder einen Mehrwert bietet, ziehen Sie bitte eine Unterstützung in Betracht, damit sie weiter verbessert werden kann. Already donated? Click "I have already donated" to enter your donation code and permanently disable this reminder. Bereits gespendet? Klicken Sie auf „Ich habe bereits gespendet“, um Ihren Spendencode einzugeben und diese Erinnerung dauerhaft zu deaktivieren. Donate to permanently hide the donation dialog Spenden, um den Spendendialog dauerhaft auszublenden I'm not yet sure Ich bin mir noch nicht sicher I have already donated Ich habe bereits gespendet Donation code Spendencode Enter the donation code generated after your donation. A valid code will permanently hide the donation dialog. Geben Sie den nach Ihrer Spende erzeugten Spendencode ein. Ein gültiger Code blendet den Spendendialog dauerhaft aus. Invalid donation code Ungültiger Spendencode The donation code is invalid. Please try again or press Cancel. Der Spendencode ist ungültig. Bitte versuchen Sie es erneut oder klicken Sie auf Abbrechen. Open donation page Spendenseite öffnen Could not open your browser automatically. Please open this link manually: %1 Der Browser konnte nicht automatisch geöffnet werden. Bitte öffnen Sie diesen Link manuell: %1 Directory Ordner File Datei [ARCHIVE] Already categorized highlights: [ARCHIV] Bereits kategorisierte Einträge: [DONE] No files to categorize. [FERTIG] Keine Dateien zu kategorisieren. [QUEUE] Items waiting for categorization: [WARTESCHLANGE] Elemente warten auf Kategorisierung: [SCAN] Exploring %1 [SCAN] Durchsuche %1 [PROCESS] Letting the AI do its magic... [VERARBEITUNG] Die KI macht ihre Magie... [VISION] Decoding image batch %1/%2 (%3%) [VISION] Bildbatch %1/%2 wird decodiert (%3%) Switch image analysis to CPU? Bildanalyse auf CPU umschalten? Image analysis ran out of GPU memory. Der Bildanalyse ist der GPU-Speicher ausgegangen. Retry on CPU instead? Cancel will skip visual analysis and fall back to filename-based categorization. Stattdessen auf der CPU erneut versuchen? Bei Abbrechen wird die visuelle Analyse übersprungen und auf dateinamenbasierte Kategorisierung zurückgegriffen. [VISION-ERROR] %1 (%2) [VISION-FEHLER] %1 (%2) [VISION] Switching visual analysis to CPU. [VISION] Visuelle Analyse wird auf CPU umgeschaltet. [VISION-ERROR] %1 [VISION-ERROR] %1 [VISION] Visual analysis disabled; falling back to filenames. [VISION] Visuelle Analyse deaktiviert; Rückfall auf Dateinamen. [VISION] Using cached suggestion for %1 [VISION] Verwende zwischengespeicherten Vorschlag für %1 [VISION] Analyzing %1 [VISION] Analysiere %1 [VISION] GPU memory issue detected. Switching to CPU. [VISION] GPU-Speicherproblem erkannt. Es wird auf CPU umgeschaltet. [VISION] Visual analysis disabled for remaining images. [VISION] Visuelle Analyse für die verbleibenden Bilder deaktiviert. [DOC-ERROR] %1 (%2) [DOK-FEHLER] %1 (%2) [DOC] Using cached suggestion for %1 [DOC] Verwende zwischengespeicherten Vorschlag für %1 [DOC] Analyzing %1 [DOC] Analysiere %1 [SORT] %1 (%2) [SORTIEREN] %1 (%2) Cancelling analysis… Analyse wird abgebrochen… Switch local AI to CPU? Lokale KI auf CPU umschalten? The local model encountered a GPU error or ran out of memory. Das lokale Modell hat einen GPU-Fehler festgestellt oder es ist der Speicher ausgegangen. Retry on CPU instead? Cancel will stop this analysis. Stattdessen auf der CPU erneut versuchen? Abbrechen beendet diese Analyse. [WARN] GPU fallback to CPU declined. Cancelling analysis. [WARN] GPU-Rückfall auf CPU abgelehnt. Analyse wird abgebrochen. [WARN] GPU acceleration failed to initialize. Continuing on CPU (slower). [WARNUNG] GPU-Beschleunigung konnte nicht initialisiert werden. Fortsetzung auf der CPU (langsamer). [WARN] %1 will be re-categorized: %2 [WARNUNG] %1 wird neu kategorisiert: %2 QObject Edit selected items Ausgewählte Elemente bearbeiten Leave empty to keep existing Leer lassen, um vorhandene Werte beizubehalten Category Kategorie Subcategory Unterkategorie About %1 Über %1 About Über Credits Danksagungen About the AGPL License Über die AGPL-Lizenz AI File Sorter is distributed under the GNU Affero General Public License v3.0.<br><br>You can access the full source code at <a href="https://github.com/hyperfield/ai-file-sorter">github.com/hyperfield/ai-file-sorter</a>.<br><br>A full copy of the license is provided with this application and available online at <a href="https://www.gnu.org/licenses/agpl-3.0.html">gnu.org</a>. AI File Sorter wird unter der GNU Affero General Public License v3.0 vertrieben.<br><br>Den vollständigen Quellcode finden Sie unter <a href="https://github.com/hyperfield/ai-file-sorter">github.com/hyperfield/ai-file-sorter</a>.<br><br>Eine vollständige Lizenzkopie liegt bei und ist online verfügbar unter <a href="https://www.gnu.org/licenses/agpl-3.0.html">gnu.org</a>. CPU CPU Metal Metal CUDA CUDA Vulkan Vulkan Metal (auto) Metal (automatisch) Vulkan (auto) Vulkan (automatisch) %1 (auto) %1 (automatisch) Auto Automatisch CPU (%1) CPU (%1) GPU (target: %1) GPU (Ziel: %1) GPU via Vulkan unavailable GPU über Vulkan nicht verfügbar GPU via CUDA unavailable GPU über CUDA nicht verfügbar Vulkan unavailable Vulkan nicht verfügbar GPU via Metal unavailable GPU über Metal nicht verfügbar GPU init failed GPU-Initialisierung fehlgeschlagen Default model: %1 Standardmodell: %1 Measuring categorization (warm-up + %1 run(s))... Kategorisierung wird gemessen (Aufwärmen + %1 Lauf/Läufe)... Measuring document analysis (warm-up + %1 run(s))... Dokumentanalyse wird gemessen (Aufwärmen + %1 Lauf/Läufe)... Categorization: %1 Kategorisierung: %1 done abgeschlossen failed fehlgeschlagen Warm-up: %1 Aufwärmen: %1 Init: %1 Initialisierung: %1 Per-item (median of %1): %2 Pro Element (Median von %1): %2 Per-item runs: %1 Läufe pro Element: %1 Details: %1 Details: %1 Backend used: %1 Backend verwendet: %1 Document analysis: %1 Dokumentanalyse: %1 Model failed to load: %1 Modell konnte nicht geladen werden: %1 optimal optimal acceptable akzeptabel a bit long ziemlich lang n/a k. A. Result Ergebnis Categorization speed: unavailable Kategorisierungsgeschwindigkeit: nicht verfügbar Document analysis speed: unavailable Dokumentanalysegeschwindigkeit: nicht verfügbar Categorization speed: %1 Kategorisierungsgeschwindigkeit: %1 Document analysis speed: %1 Dokumentanalysegeschwindigkeit: %1 Image analysis speed: unavailable Bildanalysegeschwindigkeit: nicht verfügbar Image analysis speed: %1 Bildanalysegeschwindigkeit: %1 Recommended Local LLM choice: %1 Empfohlene lokale LLM-Auswahl: %1 You can toggle LLMs in Settings -> Select LLM Sie können LLMs unter Einstellungen -> LLM auswählen wechseln Compatibility Benchmark Kompatibilitäts-Benchmark Run a quick performance check to estimate how image analysis, document analysis, and file categorization will perform on your system. Führt eine kurze Leistungsprüfung aus, um abzuschätzen, wie Bildanalyse, Dokumentanalyse und Dateikategorisierung auf diesem System funktionieren werden. It is recommended to quit any CPU- and GPU-intensive applications before running this test. Es wird empfohlen, vor dem Ausführen dieses Tests alle CPU- und GPU-intensiven Anwendungen zu schließen. Run benchmark Benchmark starten Do not auto-show this dialog again Diesen Dialog nicht automatisch anzeigen Stop Benchmark Benchmark stoppen Close Schließen No previous results yet. Noch keine vorherigen Ergebnisse. Last run: %1 Letzte Ausführung: %1 Previous results: Vorherige Ergebnisse: No downloaded LLM files detected. Download a categorization or visual model to run the benchmark. Keine heruntergeladenen LLM-Dateien erkannt. Laden Sie ein Kategorisierungs- oder visuelles Modell herunter, um den Benchmark auszuführen. Starting system compatibility check... Starte Systemkompatibilitätsprüfung... CPU threads detected: %1 CPU-Threads erkannt: %1 GPU backend override: %1 GPU-Backend-Override: %1 Metal available: %1 Metal verfügbar: %1 yes ja no nein GPU memory allocation (Metal): %1 free / %2 total GPU-Speicherzuweisung (Metal): %1 frei / %2 gesamt GPU memory allocation (Metal): unavailable GPU-Speicherzuweisung (Metal): nicht verfügbar CUDA available: %1 CUDA verfügbar: %1 CUDA memory (allocatable): %1 free / %2 total CUDA-Speicher (zuweisbar): %1 frei / %2 gesamt (device total: %1) (Gerät gesamt: %1) GPU memory allocation (Vulkan): %1 free / %2 total GPU-Speicherzuweisung (Vulkan): %1 frei / %2 gesamt GPU memory allocation (Vulkan): unavailable GPU-Speicherzuweisung (Vulkan): nicht verfügbar Temporary directory setup failed; benchmark sample file creation may fail. Die Einrichtung des temporären Verzeichnisses ist fehlgeschlagen; das Erstellen der Benchmark-Beispieldatei kann fehlschlagen. No default models downloaded; skipping categorization and document checks. Keine Standardmodelle heruntergeladen; Kategorisierung und Dokumentenprüfungen werden übersprungen. Default models detected: %1 Standardmodelle erkannt: %1 Benchmark stopped. Benchmark gestoppt. Running image analysis test... Bildanalyse-Test wird ausgeführt... unavailable nicht verfügbar Image analysis: skipped (%1) Bildanalyse: übersprungen (%1) Image analysis: %1 Bildanalyse: %1 Time: %1 Zeit: %1 GPU disabled by backend override GPU durch Backend-Override deaktiviert Backend used (image analysis): %1 Backend verwendet (Bildanalyse): %1 Benchmark failed: %1 Benchmark fehlgeschlagen: %1 [STOP] Benchmark will stop after the current step is processed. [STOP] Der Benchmark stoppt nach dem aktuellen Schritt. Error Fehler Local LLM (%1) Lokales LLM (%1) Local LLM Lokales LLM Support %1 Unterstütze %1 Required Update Available Erforderliches Update verfügbar A required update is available. Please update to continue. If you choose to quit, the application will close. Ein erforderliches Update ist verfügbar. Bitte aktualisieren Sie, um fortzufahren. Wenn Sie Beenden wählen, wird die Anwendung geschlossen. Update Now Jetzt aktualisieren Quit Beenden Optional Update Available Optionales Update verfügbar An optional update is available. Would you like to update now? Ein optionales Update ist verfügbar. Möchten Sie jetzt aktualisieren? Skip This Version Diese Version überspringen Cancel Abbrechen Downloading Update Update wird heruntergeladen Downloading the update installer... Das Update-Installationsprogramm wird heruntergeladen... Failed to prepare the update installer. %1 Das Update-Installationsprogramm konnte nicht vorbereitet werden. %1 Installer Ready Installationsprogramm bereit Quit the app and launch the installer to update Beenden Sie die App und starten Sie das Installationsprogramm, um zu aktualisieren Quit and Launch Installer Beenden und Installationsprogramm starten The installer could not be launched. Das Installationsprogramm konnte nicht gestartet werden. No download target is available for this update. Für dieses Update ist kein Download-Ziel verfügbar. Update Failed Update fehlgeschlagen Update manually Manuell aktualisieren Edit whitelist Whitelist bearbeiten Name: Name: Categories (comma separated): Kategorien (durch Kommas getrennt): Subcategories (comma separated): Unterkategorien (durch Kommas getrennt): CUDA Toolkit Missing CUDA Toolkit fehlt A compatible NVIDIA GPU was detected, but the CUDA Toolkit is missing. CUDA is required for GPU acceleration in this application. Would you like to download and install it now? Eine kompatible NVIDIA-GPU wurde erkannt, aber das CUDA Toolkit fehlt. CUDA ist für die GPU-Beschleunigung in dieser Anwendung erforderlich. Möchten Sie es jetzt herunterladen und installieren? Launch Error Startfehler Cannot enable both CUDA and Vulkan simultaneously. CUDA und Vulkan können nicht gleichzeitig aktiviert werden. Missing GGML Runtime GGML-Laufzeit fehlt Could not locate the backend runtime DLLs. Tried: %1 %2 Die Laufzeit-DLLs des Backends konnten nicht gefunden werden. Versucht: %1 %2 Launch Failed Start fehlgeschlagen Failed to launch the main application executable: %1 Die Hauptanwendung konnte nicht gestartet werden: %1 UiTranslator Folder: Ordner: Browse… Durchsuchen… Use subcategories Unterkategorien verwenden Create subcategory folders within each category. Unterordner innerhalb jeder Kategorie anlegen. Categorization type Kategorisierungstyp Choose how strict the category labels should be. Festlegen, wie strikt die Kategoriebezeichnungen sein sollen. More refined Ausführlicher Favor detailed labels even if similar items vary. Bevorzugt detaillierte Bezeichnungen, auch wenn ähnliche Elemente variieren. More consistent Einheitlicher Favor consistent labels across similar items. Bevorzugt konsistente Bezeichnungen für ähnliche Elemente. Use a whitelist Whitelist verwenden Restrict categories and subcategories to the selected whitelist. Kategorien und Unterkategorien auf die ausgewählte Whitelist beschränken. Select the whitelist used for this run. Whitelist für diesen Lauf auswählen. Categorize files Dateien kategorisieren Include files in the categorization pass. Dateien in die Kategorisierung einbeziehen. Categorize folders Ordner kategorisieren Include directories in the categorization pass. Ordner in die Kategorisierung einbeziehen. Scan subfolders Unterordner scannen Scan files inside subfolders and treat them as part of the main folder. Dateien in Unterordnern scannen und so behandeln, als wären sie im Hauptordner. Analyze picture files by content (can be slow) Bilddateien nach Inhalt analysieren (kann langsam sein) Run the visual LLM on supported picture files. Visuelles LLM auf unterstützte Bilddateien anwenden. Process picture files only (ignore any other files) Nur Bilddateien verarbeiten (alle anderen Dateien ignorieren) Ignore non-picture files in this run. Nicht-Bilddateien in diesem Lauf ignorieren. Add image creation date (if available) to category name Erstellungsdatum des Bildes (falls verfügbar) zum Kategorienamen hinzufügen Append the image creation date from metadata to the category label. Erstellungsdatum des Bildes aus Metadaten an die Kategoriebezeichnung anhängen. Add photo date and place to filename (if available) Fotodatum und Ort zum Dateinamen hinzufügen (falls verfügbar) Date comes from photo EXIF metadata. Place names are resolved online from GPS coordinates, so network access is required for place prefixes. Das Datum stammt aus den EXIF-Metadaten des Fotos. Ortsnamen werden online aus GPS-Koordinaten ermittelt, daher ist für Ortspräfixe eine Netzwerkverbindung erforderlich. Add audio/video metadata to file name (if available) Audio-/Video-Metadaten zum Dateinamen hinzufügen (falls verfügbar) Use embedded media tags (for example year, artist, album, title) to build suggested audio/video filenames. Eingebettete Medientags (z. B. Jahr, Interpret, Album, Titel) verwenden, um vorgeschlagene Audio-/Video-Dateinamen zu erstellen. Offer to rename picture files Umbenennen von Bilddateien anbieten Show suggested filenames for picture files. Vorgeschlagene Dateinamen für Bilddateien anzeigen. Do not categorize picture files (only rename) Bilddateien nicht kategorisieren (nur umbenennen) Skip categorization for picture files and only rename them. Bilddateien nicht kategorisieren und nur umbenennen. Show or hide picture analysis options Optionen für die Bildanalyse anzeigen oder ausblenden Analyze document files by content Dokumentdateien nach Inhalt analysieren Summarize document contents with the selected LLM. Dokumentinhalte mit dem ausgewählten LLM zusammenfassen. Process document files only (ignore any other files) Nur Dokumentdateien verarbeiten (alle anderen Dateien ignorieren) Ignore non-document files in this run. Nicht-Dokumentdateien in diesem Lauf ignorieren. Offer to rename document files Umbenennen von Dokumentdateien anbieten Show suggested filenames for document files. Vorgeschlagene Dateinamen für Dokumentdateien anzeigen. Do not categorize document files (only rename) Dokumentdateien nicht kategorisieren (nur umbenennen) Skip categorization for document files and only rename them. Dokumentdateien nicht kategorisieren und nur umbenennen. Add document creation date (if available) to category name Erstellungsdatum des Dokuments (falls verfügbar) zum Kategorienamen hinzufügen Append the document creation date from metadata to the category label. Erstellungsdatum des Dokuments aus Metadaten an die Kategoriebezeichnung anhängen. Show or hide document analysis options Optionen für die Dokumentanalyse anzeigen oder ausblenden Stop analyzing Analyse stoppen Analyze folder Ordner analysieren File Datei Type Typ Category Kategorie Subcategory Unterkategorie Status Status Directory Ordner Ready Bereit &Help &Hilfe File Explorer Datei-Explorer Cancelling analysis… Analyse wird abgebrochen… Analyzing… Analysiere… WhitelistManagerDialog Category whitelists Kategorie-Whitelists Add Hinzufügen Edit Bearbeiten Remove Entfernen Cannot remove Kann nicht entfernt werden The default list cannot be removed. Die Standardliste kann nicht entfernt werden. ================================================ FILE: app/resources/i18n/aifilesorter_es.ts ================================================ CategorizationDialog Tip: Click %1 cells to rename them. Consejo: haz clic en las celdas %1 para renombrarlas. No items selected No hay elementos seleccionados Highlight one or more rows to select them for processing. Resalta una o más filas para seleccionarlas para su procesamiento. Bulk edit unavailable Edición masiva no disponible Bulk editing categories is unavailable while picture rename-only mode is active. La edición masiva de categorías no está disponible mientras el modo de solo renombrar imágenes esté activo. Highlight one or more rows to edit their categories. Resalta una o más filas para editar sus categorías. Preview Vista previa Review and Confirm Revisar y confirmar Select all Seleccionar todo Select highlighted Seleccionar resaltados Edit selected... Editar seleccionados... Create subcategory folders Crear carpetas de subcategorías Dry run (preview only, do not move files) Prueba (solo vista previa, no mover archivos) Do not categorize picture files (only rename) No categorizar archivos de imagen (solo renombrar) Do not categorize document files (only rename) No categorizar archivos de documentos (solo renombrar) Confirm and Process Confirmar y procesar Continue Later Continuar más tarde Undo this change Deshacer este cambio Close Cerrar Mark highlighted rows for processing (Ctrl+Space). Marca las filas resaltadas para procesarlas (Ctrl+Espacio). Apply category/subcategory values to highlighted rows. Aplica los valores de categoría/subcategoría a las filas resaltadas. Process Procesar File Archivo Type Tipo Suggested filename Nombre de archivo sugerido Category Categoría Subcategory Subcategoría Status Estado Planned destination Destino previsto Moved Movido Renamed Renombrado Renamed & Moved Renombrado y movido Skipped Omitido Not selected No seleccionado CategorizationProgressDialog [STOP] Analysis will stop after the current item is processed. [DETENER] El análisis se detendrá después del elemento actual. Image analysis Análisis de imágenes Document analysis Análisis de documentos Categorization Categorización Directory Carpeta Image Imagen Document Documento File Archivo Type Tipo Stage %1: %2 Etapa %1: %2 Pending Pendiente In progress En curso Complete Completado Processed 0/0 | In progress: 0 | Pending: 0 Procesados 0/0 | En curso: 0 | Pendientes: 0 Processed %1/%2 | In progress: %3 | Pending: %4 Procesados %1/%2 | En curso: %3 | Pendientes: %4 Analyzing Files Analizando archivos Stop Analysis Detener análisis Activity log Registro de actividad CustomApiDialog Custom OpenAI-compatible API API personalizada compatible con OpenAI e.g. http://localhost:1234/v1 p. ej. http://localhost:1234/v1 e.g. llama-3.1, gpt-4o-mini p. ej. llama-3.1, gpt-4o-mini Show Mostrar Display name Nombre para mostrar Description Descripción Base URL or endpoint URL base o endpoint Model Modelo API key (optional) Clave API (opcional) Enter a base URL (e.g. http://localhost:1234/v1) or a full /chat/completions endpoint. Introduce una URL base (p. ej. http://localhost:1234/v1) o un endpoint completo de /chat/completions. CustomLLMDialog Custom local LLM LLM local personalizado Browse… Explorar… Display name Nombre para mostrar Description Descripción Model file (.gguf) Archivo del modelo (.gguf) Select .gguf model Seleccionar modelo .gguf GGUF models (*.gguf);;All files (*.*) Modelos GGUF (*.gguf);;Todos los archivos (*.*) DryRunPreviewDialog Dry run preview Vista previa de la prueba From De To A Close Cerrar LLMSelectionDialog Choose LLM Mode Elegir modo de LLM Select LLM Mode Seleccionar modo de LLM Larger local model. Slower on CPU, but performs much better with GPU acceleration. Supports: Nvidia (CUDA), Apple (Metal), CPU. Modelo local más grande. Es más lento en CPU, pero funciona mucho mejor con aceleración por GPU. Compatible con: Nvidia (CUDA), Apple (Metal), CPU. Recommended Recomendado Smaller local model that works quickly even on CPUs. Good for lightweight local use. Modelo local más pequeño que funciona rápido incluso en CPU. Bueno para un uso local ligero. Legacy model kept for existing downloads. Modelo heredado conservado para descargas existentes. Gemini (Google AI Studio API key) Gemini (clave API de Google AI Studio) Use Google's Gemini models with your AI Studio API key (internet required). Usa los modelos Gemini de Google con tu clave API de AI Studio (se requiere internet). AIza... AIza... Show Mostrar Gemini API key Clave API de Gemini e.g. gemini-2.5-flash-lite, gemini-2.5-flash, gemini-2.5-pro p. ej. gemini-2.5-flash-lite, gemini-2.5-flash, gemini-2.5-pro Model Modelo Your key is stored locally in the config file for this device. Tu clave se guarda localmente en el archivo de configuración de este dispositivo. <a href="https://aistudio.google.com/app/apikey">Get a Gemini API key</a> <a href="https://aistudio.google.com/app/apikey">Obtener una clave API de Gemini</a> ChatGPT (OpenAI API key) ChatGPT (clave API de OpenAI) Use your own OpenAI API key to access ChatGPT models (internet required). Usa tu propia clave API de OpenAI para acceder a los modelos de ChatGPT (se requiere internet). sk-... sk-... OpenAI API key Clave API de OpenAI e.g. gpt-4o-mini, gpt-4.1, o3-mini p. ej. gpt-4o-mini, gpt-4.1, o3-mini <a href="https://platform.openai.com/api-keys">Get an OpenAI API key</a> <a href="https://platform.openai.com/api-keys">Obtener una clave API de OpenAI</a> Custom OpenAI-compatible API (advanced) API personalizada compatible con OpenAI (avanzada) Use OpenAI-compatible endpoints such as LM Studio or Ollama (local or remote). Usa endpoints compatibles con OpenAI, como LM Studio u Ollama (locales o remotos). Add… Añadir… Edit… Editar… Delete Eliminar Custom local LLM (gguf) LLM local personalizado (gguf) Downloads Descargas Download Descargar Image analysis models (LLaVA) Modelos de análisis de imágenes (LLaVA) Download the visual LLM files required for image analysis. Descarga los archivos LLM visuales necesarios para el análisis de imágenes. LLaVA 1.6 Mistral 7B (text model) LLaVA 1.6 Mistral 7B (modelo de texto) LLaVA mmproj (vision encoder) LLaVA mmproj (codificador de visión) Choose or add a custom model. Elige o añade un modelo personalizado. Custom model selected. Modelo personalizado seleccionado. Selection ready. Selección lista. Choose or add a custom API endpoint. Elige o añade un endpoint de API personalizado. Custom API selected. API personalizada seleccionada. ChatGPT will use your API key and model. ChatGPT usará tu clave API y tu modelo. Enter your OpenAI API key and model to continue. Introduce tu clave API de OpenAI y el modelo para continuar. Gemini will use your API key and model. Gemini usará tu clave API y tu modelo. Enter your Gemini API key and model to continue. Introduce tu clave API de Gemini y el modelo para continuar. Model ready. Modelo listo. Resume download Reanudar descarga Partial download detected. You can resume. Descarga parcial detectada. Puedes reanudar. Download required. Descarga requerida. Unsupported LLM selection. Selección de LLM no compatible. Missing download URL environment variable (%1). Falta la variable de entorno de la URL de descarga (%1). Delete downloaded model? ¿Eliminar el modelo descargado? Delete the downloaded model %1? ¿Eliminar el modelo descargado %1? Failed to delete downloaded model. No se pudo eliminar el modelo descargado. Deleted downloaded model. Modelo descargado eliminado. No downloaded model found to delete. No se encontró ningún modelo descargado para eliminar. Remote URL URL remota Local path Ruta local File size Tamaño del archivo File size: unknown Tamaño del archivo: desconocido Delete custom model Eliminar modelo personalizado Remove '%1' from your custom LLMs? This does not delete the file on disk. ¿Quitar '%1' de tus LLM personalizados? Esto no elimina el archivo del disco. Delete custom API Eliminar API personalizada Remove '%1' from your custom API list? This does not affect the server. ¿Quitar '%1' de tu lista de API personalizadas? Esto no afecta al servidor. Missing download URL environment variable. Falta la variable de entorno de la URL de descarga. Downloading… Descargando… Download complete. Descarga completa. Download cancelled. Descarga cancelada. Download error: %1 Error de descarga: %1 MainApp File Explorer Explorador de archivos Select Directory Seleccionar carpeta Loaded folder %1 Carpeta %1 cargada Analysis cancelled Análisis cancelado Folder selected: %1 Carpeta seleccionada: %1 More consistent Más coherente More refined Más detallada Recategorize folder? ¿Recategorizar la carpeta? This folder was categorized using the %1 mode. Do you want to recategorize it now using the %2 mode? Esta carpeta se categorizó con el modo %1. ¿Quieres recategorizarla ahora con el modo %2? Recategorize Recategorizar Keep existing Mantener existente Failed to reset cached categorization for this folder. No se pudo restablecer la categorización en caché para esta carpeta. Download required Descarga requerida Image analysis requires visual LLM files. Download them now? El análisis de imágenes requiere archivos LLM visuales. ¿Descargarlos ahora? OK Aceptar Stop analyzing Detener análisis Analyzing… Analizando… Analyze folder Analizar carpeta Ready Listo Undo last run Deshacer la última ejecución This will attempt to move files back to their original locations based on the last run. Plan file: %1 Esto intentará mover los archivos de vuelta a sus ubicaciones originales según la última ejecución. Archivo del plan: %1 Restored %1 file(s). Skipped %2. Se restauraron %1 archivo(s). Se omitieron %2. Undo complete Reversión completada Thank you for using AI File Sorter! You have categorized %1 files thus far. I, the author, really hope this app was useful for you. Gracias por usar AI File Sorter. Has categorizado %1 archivos hasta ahora. Yo, el autor, realmente espero que esta aplicación te haya sido útil. AI File Sorter takes hundreds of hours of development, feature work, support replies, and ongoing costs such as servers and remote-model infrastructure. If the app saves you time or brings value, please consider supporting it so it can keep improving. AI File Sorter requiere cientos de horas de desarrollo, trabajo en funciones, respuestas de soporte y costes continuos como servidores e infraestructura de modelos remotos. Si la aplicación te ahorra tiempo o te aporta valor, considera apoyarla para que pueda seguir mejorando. Already donated? Click "I have already donated" to enter your donation code and permanently disable this reminder. ¿Ya has donado? Haz clic en "Ya he donado" para introducir tu código de donación y desactivar este recordatorio de forma permanente. Donate to permanently hide the donation dialog Donar para ocultar permanentemente el cuadro de diálogo de donación I'm not yet sure Aún no estoy seguro I have already donated Ya he donado Donation code Código de donación Enter the donation code generated after your donation. A valid code will permanently hide the donation dialog. Introduce el código de donación generado después de tu donación. Un código válido ocultará permanentemente el cuadro de diálogo de donación. Invalid donation code Código de donación no válido The donation code is invalid. Please try again or press Cancel. El código de donación no es válido. Inténtalo de nuevo o pulsa Cancelar. Open donation page Abrir página de donación Could not open your browser automatically. Please open this link manually: %1 No se pudo abrir el navegador automáticamente. Abre este enlace manualmente: %1 Directory Carpeta File Archivo [ARCHIVE] Already categorized highlights: [ARCHIVO] Elementos ya categorizados: [DONE] No files to categorize. [LISTO] No hay archivos para categorizar. [QUEUE] Items waiting for categorization: [COLA] Elementos en espera de categorización: [SCAN] Exploring %1 [ESCANEO] Explorando %1 [PROCESS] Letting the AI do its magic... [PROCESO] La IA hace su magia... [VISION] Decoding image batch %1/%2 (%3%) [VISIÓN] Decodificando lote de imágenes %1/%2 (%3%) Switch image analysis to CPU? ¿Cambiar el análisis de imágenes a CPU? Image analysis ran out of GPU memory. El análisis de imágenes se quedó sin memoria de GPU. Retry on CPU instead? Cancel will skip visual analysis and fall back to filename-based categorization. ¿Reintentar en la CPU? Cancelar omitirá el análisis visual y volverá a la categorización basada en nombres de archivo. [VISION-ERROR] %1 (%2) [ERROR-VISIÓN] %1 (%2) [VISION] Switching visual analysis to CPU. [VISION] Cambiando el análisis visual a la CPU. [VISION-ERROR] %1 [VISION-ERROR] %1 [VISION] Visual analysis disabled; falling back to filenames. [VISION] Análisis visual desactivado; se vuelve a los nombres de archivo. [VISION] Using cached suggestion for %1 [VISIÓN] Usando sugerencia en caché para %1 [VISION] Analyzing %1 [VISIÓN] Analizando %1 [VISION] GPU memory issue detected. Switching to CPU. [VISION] Se detectó un problema de memoria de GPU. Cambiando a CPU. [VISION] Visual analysis disabled for remaining images. [VISION] Análisis visual desactivado para las imágenes restantes. [DOC-ERROR] %1 (%2) [ERROR-DOC] %1 (%2) [DOC] Using cached suggestion for %1 [DOC] Usando sugerencia en caché para %1 [DOC] Analyzing %1 [DOC] Analizando %1 [SORT] %1 (%2) [ORDENAR] %1 (%2) Cancelling analysis… Cancelando análisis… Switch local AI to CPU? ¿Cambiar la IA local a CPU? The local model encountered a GPU error or ran out of memory. El modelo local encontró un error de GPU o se quedó sin memoria. Retry on CPU instead? Cancel will stop this analysis. ¿Reintentar en la CPU? Cancelar detendrá este análisis. [WARN] GPU fallback to CPU declined. Cancelling analysis. [WARN] Se rechazó el cambio de GPU a CPU. Cancelando análisis. [WARN] GPU acceleration failed to initialize. Continuing on CPU (slower). [ADVERTENCIA] No se pudo inicializar la aceleración GPU. Continuando en CPU (más lento). [WARN] %1 will be re-categorized: %2 [ADVERTENCIA] %1 se recategorizará: %2 QObject Edit selected items Editar elementos seleccionados Leave empty to keep existing Déjalo vacío para mantener los valores existentes Category Categoría Subcategory Subcategoría About %1 Acerca de %1 About Acerca de Credits Créditos About the AGPL License Acerca de la licencia AGPL AI File Sorter is distributed under the GNU Affero General Public License v3.0.<br><br>You can access the full source code at <a href="https://github.com/hyperfield/ai-file-sorter">github.com/hyperfield/ai-file-sorter</a>.<br><br>A full copy of the license is provided with this application and available online at <a href="https://www.gnu.org/licenses/agpl-3.0.html">gnu.org</a>. AI File Sorter se distribuye bajo la GNU Affero General Public License v3.0.<br><br>Puedes acceder al código fuente completo en <a href="https://github.com/hyperfield/ai-file-sorter">github.com/hyperfield/ai-file-sorter</a>.<br><br>Se incluye una copia completa de la licencia y está disponible en línea en <a href="https://www.gnu.org/licenses/agpl-3.0.html">gnu.org</a>. CPU CPU Metal Metal CUDA CUDA Vulkan Vulkan Metal (auto) Metal (automático) Vulkan (auto) Vulkan (automático) %1 (auto) %1 (automático) Auto Automático CPU (%1) CPU (%1) GPU (target: %1) GPU (objetivo: %1) GPU via Vulkan unavailable GPU vía Vulkan no disponible GPU via CUDA unavailable GPU vía CUDA no disponible Vulkan unavailable Vulkan no disponible GPU via Metal unavailable GPU vía Metal no disponible GPU init failed Falló la inicialización de la GPU Default model: %1 Modelo predeterminado: %1 Measuring categorization (warm-up + %1 run(s))... Midiendo la categorización (calentamiento + %1 ejecución(es))... Measuring document analysis (warm-up + %1 run(s))... Midiendo el análisis de documentos (calentamiento + %1 ejecución(es))... Categorization: %1 Categorización: %1 done completado failed fallido Warm-up: %1 Calentamiento: %1 Init: %1 Inicialización: %1 Per-item (median of %1): %2 Por elemento (mediana de %1): %2 Per-item runs: %1 Ejecuciones por elemento: %1 Details: %1 Detalles: %1 Backend used: %1 Backend utilizado: %1 Document analysis: %1 Análisis de documentos: %1 Model failed to load: %1 No se pudo cargar el modelo: %1 optimal óptimo acceptable aceptable a bit long bastante largo n/a n/d Result Resultado Categorization speed: unavailable Velocidad de categorización: no disponible Document analysis speed: unavailable Velocidad de análisis de documentos: no disponible Categorization speed: %1 Velocidad de categorización: %1 Document analysis speed: %1 Velocidad de análisis de documentos: %1 Image analysis speed: unavailable Velocidad de análisis de imágenes: no disponible Image analysis speed: %1 Velocidad de análisis de imágenes: %1 Recommended Local LLM choice: %1 LLM local recomendado: %1 You can toggle LLMs in Settings -> Select LLM Puedes cambiar los LLM en Configuración -> Seleccionar LLM Compatibility Benchmark Benchmark de compatibilidad Run a quick performance check to estimate how image analysis, document analysis, and file categorization will perform on your system. Ejecuta una comprobación rápida de rendimiento para estimar cómo funcionarán el análisis de imágenes, el análisis de documentos y la categorización de archivos en tu sistema. It is recommended to quit any CPU- and GPU-intensive applications before running this test. Se recomienda cerrar cualquier aplicación intensiva de CPU y GPU antes de ejecutar esta prueba. Run benchmark Ejecutar benchmark Do not auto-show this dialog again No mostrar automáticamente este diálogo otra vez Stop Benchmark Detener benchmark Close Cerrar No previous results yet. No hay resultados anteriores. Last run: %1 Última ejecución: %1 Previous results: Resultados anteriores: No downloaded LLM files detected. Download a categorization or visual model to run the benchmark. No se detectaron archivos LLM descargados. Descarga un modelo de categorización o visual para ejecutar el benchmark. Starting system compatibility check... Iniciando la comprobación de compatibilidad del sistema... CPU threads detected: %1 Hilos de CPU detectados: %1 GPU backend override: %1 Forzado del backend GPU: %1 Metal available: %1 Metal disponible: %1 yes no no GPU memory allocation (Metal): %1 free / %2 total Asignación de memoria GPU (Metal): %1 libres / %2 totales GPU memory allocation (Metal): unavailable Asignación de memoria GPU (Metal): no disponible CUDA available: %1 CUDA disponible: %1 CUDA memory (allocatable): %1 free / %2 total Memoria CUDA (asignable): %1 libres / %2 totales (device total: %1) (total del dispositivo: %1) GPU memory allocation (Vulkan): %1 free / %2 total Asignación de memoria GPU (Vulkan): %1 libres / %2 totales GPU memory allocation (Vulkan): unavailable Asignación de memoria GPU (Vulkan): no disponible Temporary directory setup failed; benchmark sample file creation may fail. Falló la configuración del directorio temporal; la creación del archivo de muestra para el benchmark puede fallar. No default models downloaded; skipping categorization and document checks. No se han descargado modelos predeterminados; se omiten la categorización y las comprobaciones de documentos. Default models detected: %1 Modelos predeterminados detectados: %1 Benchmark stopped. Benchmark detenido. Running image analysis test... Ejecutando prueba de análisis de imágenes... unavailable no disponible Image analysis: skipped (%1) Análisis de imágenes: omitido (%1) Image analysis: %1 Análisis de imágenes: %1 Time: %1 Tiempo: %1 GPU disabled by backend override GPU deshabilitada por el forzado del backend Backend used (image analysis): %1 Backend utilizado (análisis de imágenes): %1 Benchmark failed: %1 Benchmark fallido: %1 [STOP] Benchmark will stop after the current step is processed. [STOP] El benchmark se detendrá después del paso actual. Error Error Local LLM (%1) LLM local (%1) Local LLM LLM local Support %1 Apoya %1 Required Update Available Hay una actualización obligatoria disponible A required update is available. Please update to continue. If you choose to quit, the application will close. Hay una actualización obligatoria disponible. Actualiza para continuar. Si eliges salir, la aplicación se cerrará. Update Now Actualizar ahora Quit Salir Optional Update Available Hay una actualización opcional disponible An optional update is available. Would you like to update now? Hay una actualización opcional disponible. ¿Quieres actualizar ahora? Skip This Version Omitir esta versión Cancel Cancelar Downloading Update Descargando actualización Downloading the update installer... Descargando el instalador de la actualización... Failed to prepare the update installer. %1 No se pudo preparar el instalador de la actualización. %1 Installer Ready Instalador listo Quit the app and launch the installer to update Cierra la aplicación y ejecuta el instalador para actualizar Quit and Launch Installer Cerrar y ejecutar instalador The installer could not be launched. No se pudo ejecutar el instalador. No download target is available for this update. No hay un destino de descarga disponible para esta actualización. Update Failed La actualización falló Update manually Actualizar manualmente Edit whitelist Editar lista blanca Name: Nombre: Categories (comma separated): Categorías (separadas por comas): Subcategories (comma separated): Subcategorías (separadas por comas): CUDA Toolkit Missing Falta el CUDA Toolkit A compatible NVIDIA GPU was detected, but the CUDA Toolkit is missing. CUDA is required for GPU acceleration in this application. Would you like to download and install it now? Se detectó una GPU NVIDIA compatible, pero falta el CUDA Toolkit. CUDA es necesario para la aceleración por GPU en esta aplicación. ¿Quieres descargarlo e instalarlo ahora? Launch Error Error de inicio Cannot enable both CUDA and Vulkan simultaneously. No se pueden activar CUDA y Vulkan al mismo tiempo. Missing GGML Runtime Falta el runtime de GGML Could not locate the backend runtime DLLs. Tried: %1 %2 No se pudieron encontrar las DLL de tiempo de ejecución del backend. Intentado: %1 %2 Launch Failed Error al iniciar Failed to launch the main application executable: %1 No se pudo iniciar el ejecutable principal de la aplicación: %1 UiTranslator Folder: Carpeta: Browse… Explorar… Use subcategories Usar subcategorías Create subcategory folders within each category. Crear subcarpetas dentro de cada categoría. Categorization type Tipo de categorización Choose how strict the category labels should be. Elegir cuán estrictas deben ser las etiquetas de categoría. More refined Más detallada Favor detailed labels even if similar items vary. Prioriza etiquetas detalladas aunque elementos similares varíen. More consistent Más coherente Favor consistent labels across similar items. Prioriza etiquetas coherentes entre elementos similares. Use a whitelist Usar lista blanca Restrict categories and subcategories to the selected whitelist. Restringir categorías y subcategorías a la lista blanca seleccionada. Select the whitelist used for this run. Selecciona la lista blanca usada en esta ejecución. Categorize files Categorizar archivos Include files in the categorization pass. Incluir archivos en la categorización. Categorize folders Categorizar directorios Include directories in the categorization pass. Incluir directorios en la categorización. Scan subfolders Escanear subcarpetas Scan files inside subfolders and treat them as part of the main folder. Escanear archivos en subcarpetas y tratarlos como si estuvieran en la carpeta principal. Analyze picture files by content (can be slow) Analizar archivos de imagen por contenido (puede ser lento) Run the visual LLM on supported picture files. Ejecutar el LLM visual en archivos de imagen compatibles. Process picture files only (ignore any other files) Procesar solo archivos de imagen (ignorar cualquier otro archivo) Ignore non-picture files in this run. Ignorar archivos que no sean de imagen en esta ejecución. Add image creation date (if available) to category name Agregar la fecha de creación de la imagen (si está disponible) al nombre de la categoría Append the image creation date from metadata to the category label. Agregar la fecha de creación de la imagen desde los metadatos a la etiqueta de la categoría. Add photo date and place to filename (if available) Agregar fecha y lugar de la foto al nombre de archivo (si están disponibles) Date comes from photo EXIF metadata. Place names are resolved online from GPS coordinates, so network access is required for place prefixes. La fecha proviene de los metadatos EXIF de la foto. Los nombres de lugares se resuelven en línea a partir de coordenadas GPS, por lo que se requiere acceso a la red para los prefijos de lugar. Add audio/video metadata to file name (if available) Agregar metadatos de audio/video al nombre de archivo (si están disponibles) Use embedded media tags (for example year, artist, album, title) to build suggested audio/video filenames. Usar etiquetas de medios incrustadas (por ejemplo año, artista, álbum, título) para crear nombres de archivo sugeridos de audio/video. Offer to rename picture files Ofrecer renombrar archivos de imagen Show suggested filenames for picture files. Mostrar nombres sugeridos para archivos de imagen. Do not categorize picture files (only rename) No categorizar archivos de imagen (solo renombrar) Skip categorization for picture files and only rename them. Omitir la categorización de archivos de imagen y solo renombrarlos. Show or hide picture analysis options Mostrar u ocultar opciones de análisis de imágenes Analyze document files by content Analizar archivos de documentos por contenido Summarize document contents with the selected LLM. Resumir el contenido de los documentos con el LLM seleccionado. Process document files only (ignore any other files) Procesar solo archivos de documentos (ignorar cualquier otro archivo) Ignore non-document files in this run. Ignorar archivos que no sean documentos en esta ejecución. Offer to rename document files Ofrecer renombrar archivos de documentos Show suggested filenames for document files. Mostrar nombres sugeridos para archivos de documentos. Do not categorize document files (only rename) No categorizar archivos de documentos (solo renombrar) Skip categorization for document files and only rename them. Omitir la categorización de archivos de documentos y solo renombrarlos. Add document creation date (if available) to category name Agregar la fecha de creación del documento (si está disponible) al nombre de la categoría Append the document creation date from metadata to the category label. Agregar la fecha de creación del documento desde los metadatos a la etiqueta de la categoría. Show or hide document analysis options Mostrar u ocultar opciones de análisis de documentos Stop analyzing Detener análisis Analyze folder Analizar carpeta File Archivo Type Tipo Category Categoría Subcategory Subcategoría Status Estado Directory Carpeta Ready Listo &Help &Ayuda File Explorer Explorador de archivos Cancelling analysis… Cancelando análisis… Analyzing… Analizando… WhitelistManagerDialog Category whitelists Listas blancas de categorías Add Añadir Edit Editar Remove Quitar Cannot remove No se puede quitar The default list cannot be removed. La lista predeterminada no se puede quitar. ================================================ FILE: app/resources/i18n/aifilesorter_fr.ts ================================================ CategorizationDialog Tip: Click %1 cells to rename them. Astuce : cliquez sur les cellules %1 pour les renommer. No items selected Aucun élément sélectionné Highlight one or more rows to select them for processing. Surlignez une ou plusieurs lignes pour les sélectionner pour le traitement. Bulk edit unavailable Modification groupée indisponible Bulk editing categories is unavailable while picture rename-only mode is active. La modification groupée des catégories n'est pas disponible lorsque le mode de renommage seul des images est actif. Highlight one or more rows to edit their categories. Surlignez une ou plusieurs lignes pour modifier leurs catégories. Preview Aperçu Review and Confirm Vérifier et confirmer Select all Tout sélectionner Select highlighted Sélectionner les lignes surlignées Edit selected... Modifier la sélection... Create subcategory folders Créer des dossiers de sous-catégories Dry run (preview only, do not move files) Simulation (aperçu uniquement, ne déplace pas les fichiers) Do not categorize picture files (only rename) Ne pas catégoriser les fichiers image (renommer uniquement) Do not categorize document files (only rename) Ne pas catégoriser les fichiers de documents (renommer uniquement) Confirm and Process Confirmer et traiter Continue Later Continuer plus tard Undo this change Annuler cette modification Close Fermer Mark highlighted rows for processing (Ctrl+Space). Marquez les lignes surlignées pour le traitement (Ctrl+Espace). Apply category/subcategory values to highlighted rows. Appliquez les valeurs de catégorie/sous-catégorie aux lignes surlignées. Process Traiter File Fichier Type Type Suggested filename Nom de fichier suggéré Category Catégorie Subcategory Sous-catégorie Status Statut Planned destination Destination prévue Moved Déplacé Renamed Renommé Renamed & Moved Renommé et déplacé Skipped Ignoré Not selected Non sélectionné CategorizationProgressDialog [STOP] Analysis will stop after the current item is processed. [ARRÊT] L'analyse s'arrêtera après le traitement de l'élément en cours. Image analysis Analyse d'image Document analysis Analyse de documents Categorization Catégorisation Directory Dossier Image Image Document Document File Fichier Type Type Stage %1: %2 Étape %1 : %2 Pending En attente In progress En cours Complete Terminé Processed 0/0 | In progress: 0 | Pending: 0 Traités 0/0 | En cours : 0 | En attente : 0 Processed %1/%2 | In progress: %3 | Pending: %4 Traités %1/%2 | En cours : %3 | En attente : %4 Analyzing Files Analyse des fichiers Stop Analysis Arrêter l'analyse Activity log Journal d'activité CustomApiDialog Custom OpenAI-compatible API API personnalisée compatible OpenAI e.g. http://localhost:1234/v1 p. ex. http://localhost:1234/v1 e.g. llama-3.1, gpt-4o-mini p. ex. llama-3.1, gpt-4o-mini Show Afficher Display name Nom d'affichage Description Description Base URL or endpoint URL de base ou point de terminaison Model Modèle API key (optional) Clé API (facultative) Enter a base URL (e.g. http://localhost:1234/v1) or a full /chat/completions endpoint. Saisissez une URL de base (p. ex. http://localhost:1234/v1) ou un point de terminaison /chat/completions complet. CustomLLMDialog Custom local LLM LLM local personnalisé Browse… Parcourir… Display name Nom d'affichage Description Description Model file (.gguf) Fichier modèle (.gguf) Select .gguf model Sélectionner un modèle .gguf GGUF models (*.gguf);;All files (*.*) Modèles GGUF (*.gguf);;Tous les fichiers (*.*) DryRunPreviewDialog Dry run preview Aperçu de la simulation From De To Vers Close Fermer LLMSelectionDialog Choose LLM Mode Choisir le mode LLM Select LLM Mode Sélectionner le mode LLM Larger local model. Slower on CPU, but performs much better with GPU acceleration. Supports: Nvidia (CUDA), Apple (Metal), CPU. Modèle local plus grand. Plus lent sur CPU, mais nettement plus performant avec l'accélération GPU. Prend en charge : Nvidia (CUDA), Apple (Metal), CPU. Recommended Recommandé Smaller local model that works quickly even on CPUs. Good for lightweight local use. Modèle local plus petit, qui fonctionne rapidement même sur CPU. Bien adapté à un usage local léger. Legacy model kept for existing downloads. Modèle hérité conservé pour les téléchargements existants. Gemini (Google AI Studio API key) Gemini (clé API Google AI Studio) Use Google's Gemini models with your AI Studio API key (internet required). Utilisez les modèles Gemini de Google avec votre clé API AI Studio (connexion Internet requise). AIza... AIza... Show Afficher Gemini API key Clé API Gemini e.g. gemini-2.5-flash-lite, gemini-2.5-flash, gemini-2.5-pro p. ex. gemini-2.5-flash-lite, gemini-2.5-flash, gemini-2.5-pro Model Modèle Your key is stored locally in the config file for this device. Votre clé est stockée localement dans le fichier de configuration de cet appareil. <a href="https://aistudio.google.com/app/apikey">Get a Gemini API key</a> <a href="https://aistudio.google.com/app/apikey">Obtenir une clé API Gemini</a> ChatGPT (OpenAI API key) ChatGPT (clé API OpenAI) Use your own OpenAI API key to access ChatGPT models (internet required). Utilisez votre propre clé API OpenAI pour accéder aux modèles ChatGPT (connexion Internet requise). sk-... sk-... OpenAI API key Clé API OpenAI e.g. gpt-4o-mini, gpt-4.1, o3-mini p. ex. gpt-4o-mini, gpt-4.1, o3-mini <a href="https://platform.openai.com/api-keys">Get an OpenAI API key</a> <a href="https://platform.openai.com/api-keys">Obtenir une clé API OpenAI</a> Custom OpenAI-compatible API (advanced) API personnalisée compatible OpenAI (avancée) Use OpenAI-compatible endpoints such as LM Studio or Ollama (local or remote). Utilisez des points de terminaison compatibles OpenAI tels que LM Studio ou Ollama (locaux ou distants). Add… Ajouter… Edit… Modifier… Delete Supprimer Custom local LLM (gguf) LLM local personnalisé (gguf) Downloads Téléchargements Download Télécharger Image analysis models (LLaVA) Modèles d'analyse d'images (LLaVA) Download the visual LLM files required for image analysis. Téléchargez les fichiers LLM visuels nécessaires à l'analyse d'images. LLaVA 1.6 Mistral 7B (text model) LLaVA 1.6 Mistral 7B (modèle texte) LLaVA mmproj (vision encoder) LLaVA mmproj (encodeur de vision) Choose or add a custom model. Choisissez ou ajoutez un modèle personnalisé. Custom model selected. Modèle personnalisé sélectionné. Selection ready. Sélection prête. Choose or add a custom API endpoint. Choisissez ou ajoutez un point de terminaison API personnalisé. Custom API selected. API personnalisée sélectionnée. ChatGPT will use your API key and model. ChatGPT utilisera votre clé API et votre modèle. Enter your OpenAI API key and model to continue. Saisissez votre clé API OpenAI et votre modèle pour continuer. Gemini will use your API key and model. Gemini utilisera votre clé API et votre modèle. Enter your Gemini API key and model to continue. Saisissez votre clé API Gemini et votre modèle pour continuer. Model ready. Modèle prêt. Resume download Reprendre le téléchargement Partial download detected. You can resume. Téléchargement partiel détecté. Vous pouvez reprendre. Download required. Téléchargement requis. Unsupported LLM selection. Sélection de LLM non prise en charge. Missing download URL environment variable (%1). Variable d'environnement de l'URL de téléchargement manquante (%1). Delete downloaded model? Supprimer le modèle téléchargé ? Delete the downloaded model %1? Supprimer le modèle téléchargé %1 ? Failed to delete downloaded model. Échec de la suppression du modèle téléchargé. Deleted downloaded model. Modèle téléchargé supprimé. No downloaded model found to delete. Aucun modèle téléchargé à supprimer. Remote URL URL distante Local path Chemin local File size Taille du fichier File size: unknown Taille du fichier : inconnue Delete custom model Supprimer le modèle personnalisé Remove '%1' from your custom LLMs? This does not delete the file on disk. Supprimer '%1' de vos LLM personnalisés ? Cela ne supprime pas le fichier du disque. Delete custom API Supprimer l'API personnalisée Remove '%1' from your custom API list? This does not affect the server. Supprimer '%1' de votre liste d'API personnalisées ? Cela n'affecte pas le serveur. Missing download URL environment variable. Variable d'environnement de l'URL de téléchargement manquante. Downloading… Téléchargement… Download complete. Téléchargement terminé. Download cancelled. Téléchargement annulé. Download error: %1 Erreur de téléchargement : %1 MainApp File Explorer Explorateur de fichiers Select Directory Sélectionner un dossier Loaded folder %1 Dossier chargé %1 Analysis cancelled Analyse annulée Folder selected: %1 Dossier sélectionné : %1 More consistent Plus cohérent More refined Plus précis Recategorize folder? Recatégoriser le dossier ? This folder was categorized using the %1 mode. Do you want to recategorize it now using the %2 mode? Ce dossier a été catégorisé en mode %1. Voulez-vous le recatégoriser maintenant en mode %2 ? Recategorize Recatégoriser Keep existing Conserver l'existant Failed to reset cached categorization for this folder. Impossible de réinitialiser la catégorisation en cache pour ce dossier. Download required Téléchargement requis Image analysis requires visual LLM files. Download them now? L'analyse d'images nécessite les fichiers LLM visuels. Les télécharger maintenant ? OK OK Stop analyzing Arrêter l'analyse Analyzing… Analyse en cours… Analyze folder Analyser le dossier Ready Prêt Undo last run Annuler la dernière exécution This will attempt to move files back to their original locations based on the last run. Plan file: %1 Cela tentera de remettre les fichiers à leur emplacement d'origine en se basant sur la dernière exécution. Fichier de plan : %1 Restored %1 file(s). Skipped %2. %1 fichier(s) restauré(s). %2 ignoré(s). Undo complete Annulation terminée Thank you for using AI File Sorter! You have categorized %1 files thus far. I, the author, really hope this app was useful for you. Merci d'utiliser AI File Sorter ! Vous avez déjà catégorisé %1 fichiers. Moi, l'auteur, j'espère vraiment que cette application vous a été utile. AI File Sorter takes hundreds of hours of development, feature work, support replies, and ongoing costs such as servers and remote-model infrastructure. If the app saves you time or brings value, please consider supporting it so it can keep improving. AI File Sorter demande des centaines d'heures de développement, de travail sur les fonctionnalités, de réponses au support et des coûts continus tels que les serveurs et l'infrastructure des modèles distants. Si l'application vous fait gagner du temps ou vous apporte de la valeur, envisagez de la soutenir afin qu'elle puisse continuer à s'améliorer. Already donated? Click "I have already donated" to enter your donation code and permanently disable this reminder. Déjà fait un don ? Cliquez sur « J'ai déjà fait un don » pour saisir votre code de don et désactiver définitivement ce rappel. Donate to permanently hide the donation dialog Faire un don pour masquer définitivement la boîte de dialogue de don I'm not yet sure Je ne suis pas encore sûr I have already donated J'ai déjà fait un don Donation code Code de don Enter the donation code generated after your donation. A valid code will permanently hide the donation dialog. Saisissez le code de don généré après votre don. Un code valide masquera définitivement la boîte de dialogue de don. Invalid donation code Code de don invalide The donation code is invalid. Please try again or press Cancel. Le code de don est invalide. Veuillez réessayer ou appuyer sur Annuler. Open donation page Ouvrir la page de don Could not open your browser automatically. Please open this link manually: %1 Impossible d'ouvrir votre navigateur automatiquement. Veuillez ouvrir ce lien manuellement : %1 Directory Dossier File Fichier [ARCHIVE] Already categorized highlights: [ARCHIVE] Éléments déjà catégorisés : [DONE] No files to categorize. [TERMINÉ] Aucun fichier à catégoriser. [QUEUE] Items waiting for categorization: [ATTENTE] Éléments en attente de catégorisation : [SCAN] Exploring %1 [SCAN] Exploration de %1 [PROCESS] Letting the AI do its magic... [TRAITEMENT] L'IA fait sa magie... [VISION] Decoding image batch %1/%2 (%3%) [VISION] Décodage du lot d'images %1/%2 (%3%) Switch image analysis to CPU? Basculer l'analyse d'image sur le CPU ? Image analysis ran out of GPU memory. L'analyse d'image a manqué de mémoire GPU. Retry on CPU instead? Cancel will skip visual analysis and fall back to filename-based categorization. Réessayer plutôt sur le CPU ? Annuler ignorera l'analyse visuelle et reviendra à une catégorisation basée sur le nom de fichier. [VISION-ERROR] %1 (%2) [ERREUR-VISION] %1 (%2) [VISION] Switching visual analysis to CPU. [VISION] Basculement de l'analyse visuelle vers le CPU. [VISION-ERROR] %1 [VISION-ERROR] %1 [VISION] Visual analysis disabled; falling back to filenames. [VISION] Analyse visuelle désactivée ; retour aux noms de fichiers. [VISION] Using cached suggestion for %1 [VISION] Utilisation de la suggestion en cache pour %1 [VISION] Analyzing %1 [VISION] Analyse de %1 [VISION] GPU memory issue detected. Switching to CPU. [VISION] Problème de mémoire GPU détecté. Basculement vers le CPU. [VISION] Visual analysis disabled for remaining images. [VISION] Analyse visuelle désactivée pour les images restantes. [DOC-ERROR] %1 (%2) [ERREUR-DOC] %1 (%2) [DOC] Using cached suggestion for %1 [DOC] Utilisation de la suggestion en cache pour %1 [DOC] Analyzing %1 [DOC] Analyse de %1 [SORT] %1 (%2) [TRI] %1 (%2) Cancelling analysis… Annulation de l'analyse… Switch local AI to CPU? Basculer l'IA locale sur le CPU ? The local model encountered a GPU error or ran out of memory. Le modèle local a rencontré une erreur GPU ou a manqué de mémoire. Retry on CPU instead? Cancel will stop this analysis. Réessayer plutôt sur le CPU ? Annuler arrêtera cette analyse. [WARN] GPU fallback to CPU declined. Cancelling analysis. [WARN] Repli du GPU vers le CPU refusé. Annulation de l'analyse. [WARN] GPU acceleration failed to initialize. Continuing on CPU (slower). [AVERTISSEMENT] L'accélération GPU n'a pas pu être initialisée. Poursuite sur CPU (plus lent). [WARN] %1 will be re-categorized: %2 [AVERTISSEMENT] %1 sera recatégorisé : %2 QObject Edit selected items Modifier les éléments sélectionnés Leave empty to keep existing Laisser vide pour conserver l'existant Category Catégorie Subcategory Sous-catégorie About %1 À propos de %1 About À propos Credits Crédits About the AGPL License À propos de la licence AGPL AI File Sorter is distributed under the GNU Affero General Public License v3.0.<br><br>You can access the full source code at <a href="https://github.com/hyperfield/ai-file-sorter">github.com/hyperfield/ai-file-sorter</a>.<br><br>A full copy of the license is provided with this application and available online at <a href="https://www.gnu.org/licenses/agpl-3.0.html">gnu.org</a>. AI File Sorter est distribué sous la licence GNU Affero General Public License v3.0.<br><br>Vous pouvez accéder au code source complet sur <a href="https://github.com/hyperfield/ai-file-sorter">github.com/hyperfield/ai-file-sorter</a>.<br><br>Une copie complète de la licence est fournie avec cette application et disponible en ligne sur <a href="https://www.gnu.org/licenses/agpl-3.0.html">gnu.org</a>. CPU CPU Metal Metal CUDA CUDA Vulkan Vulkan Metal (auto) Metal (auto) Vulkan (auto) Vulkan (auto) %1 (auto) %1 (auto) Auto Auto CPU (%1) CPU (%1) GPU (target: %1) GPU (cible : %1) GPU via Vulkan unavailable GPU via Vulkan indisponible GPU via CUDA unavailable GPU via CUDA indisponible Vulkan unavailable Vulkan indisponible GPU via Metal unavailable GPU via Metal indisponible GPU init failed Échec de l'initialisation du GPU Default model: %1 Modèle par défaut : %1 Measuring categorization (warm-up + %1 run(s))... Mesure de la catégorisation (échauffement + %1 exécution(s))... Measuring document analysis (warm-up + %1 run(s))... Mesure de l'analyse des documents (échauffement + %1 exécution(s))... Categorization: %1 Catégorisation : %1 done terminé failed échoué Warm-up: %1 Échauffement : %1 Init: %1 Initialisation : %1 Per-item (median of %1): %2 Par élément (médiane de %1) : %2 Per-item runs: %1 Exécutions par élément : %1 Details: %1 Détails : %1 Backend used: %1 Backend utilisé : %1 Document analysis: %1 Analyse des documents : %1 Model failed to load: %1 Échec du chargement du modèle : %1 optimal optimal acceptable acceptable a bit long assez long n/a n/a Result Résultat Categorization speed: unavailable Vitesse de catégorisation : indisponible Document analysis speed: unavailable Vitesse d'analyse des documents : indisponible Categorization speed: %1 Vitesse de catégorisation : %1 Document analysis speed: %1 Vitesse d'analyse des documents : %1 Image analysis speed: unavailable Vitesse d'analyse des images : indisponible Image analysis speed: %1 Vitesse d'analyse des images : %1 Recommended Local LLM choice: %1 LLM local recommandé : %1 You can toggle LLMs in Settings -> Select LLM Vous pouvez changer de LLM dans Paramètres -> Sélectionner le LLM Compatibility Benchmark Benchmark de compatibilité Run a quick performance check to estimate how image analysis, document analysis, and file categorization will perform on your system. Exécute une vérification rapide des performances pour estimer comment l'analyse d'images, l'analyse de documents et la catégorisation de fichiers fonctionneront sur votre système. It is recommended to quit any CPU- and GPU-intensive applications before running this test. Il est recommandé de quitter toute application intensive pour le CPU ou le GPU avant d'exécuter ce test. Run benchmark Lancer le benchmark Do not auto-show this dialog again Ne plus afficher automatiquement ce dialogue Stop Benchmark Arrêter le benchmark Close Fermer No previous results yet. Aucun résultat précédent. Last run: %1 Dernière exécution : %1 Previous results: Résultats précédents : No downloaded LLM files detected. Download a categorization or visual model to run the benchmark. Aucun fichier LLM téléchargé détecté. Téléchargez un modèle de catégorisation ou visuel pour exécuter le benchmark. Starting system compatibility check... Démarrage de la vérification de compatibilité système... CPU threads detected: %1 Threads CPU détectés : %1 GPU backend override: %1 Forçage du backend GPU : %1 Metal available: %1 Metal disponible : %1 yes oui no non GPU memory allocation (Metal): %1 free / %2 total Allocation mémoire GPU (Metal) : %1 libres / %2 au total GPU memory allocation (Metal): unavailable Allocation mémoire GPU (Metal) : indisponible CUDA available: %1 CUDA disponible : %1 CUDA memory (allocatable): %1 free / %2 total Mémoire CUDA (allouable) : %1 libres / %2 au total (device total: %1) (total de l'appareil : %1) GPU memory allocation (Vulkan): %1 free / %2 total Allocation mémoire GPU (Vulkan) : %1 libres / %2 au total GPU memory allocation (Vulkan): unavailable Allocation mémoire GPU (Vulkan) : indisponible Temporary directory setup failed; benchmark sample file creation may fail. La configuration du répertoire temporaire a échoué ; la création du fichier d'exemple du benchmark peut échouer. No default models downloaded; skipping categorization and document checks. Aucun modèle par défaut téléchargé ; saut des vérifications de catégorisation et d'analyse de documents. Default models detected: %1 Modèles par défaut détectés : %1 Benchmark stopped. Benchmark arrêté. Running image analysis test... Exécution du test d'analyse d'images... unavailable indisponible Image analysis: skipped (%1) Analyse des images : ignorée (%1) Image analysis: %1 Analyse des images : %1 Time: %1 Temps : %1 GPU disabled by backend override GPU désactivé par le forçage du backend Backend used (image analysis): %1 Backend utilisé (analyse d'images) : %1 Benchmark failed: %1 Benchmark échoué : %1 [STOP] Benchmark will stop after the current step is processed. [STOP] Le benchmark s'arrêtera après l'étape en cours. Error Erreur Local LLM (%1) LLM local (%1) Local LLM LLM local Support %1 Soutenir %1 Required Update Available Mise à jour obligatoire disponible A required update is available. Please update to continue. If you choose to quit, the application will close. Une mise à jour obligatoire est disponible. Veuillez mettre à jour pour continuer. Si vous choisissez de quitter, l'application se fermera. Update Now Mettre à jour maintenant Quit Quitter Optional Update Available Mise à jour facultative disponible An optional update is available. Would you like to update now? Une mise à jour facultative est disponible. Souhaitez-vous mettre à jour maintenant ? Skip This Version Ignorer cette version Cancel Annuler Downloading Update Téléchargement de la mise à jour Downloading the update installer... Téléchargement du programme d'installation de la mise à jour... Failed to prepare the update installer. %1 Échec de la préparation du programme d'installation de la mise à jour. %1 Installer Ready Programme d'installation prêt Quit the app and launch the installer to update Quittez l'application et lancez le programme d'installation pour effectuer la mise à jour Quit and Launch Installer Quitter et lancer le programme d'installation The installer could not be launched. Le programme d'installation n'a pas pu être lancé. No download target is available for this update. Aucune cible de téléchargement n'est disponible pour cette mise à jour. Update Failed Échec de la mise à jour Update manually Mettre à jour manuellement Edit whitelist Modifier la liste blanche Name: Nom : Categories (comma separated): Catégories (séparées par des virgules) : Subcategories (comma separated): Sous-catégories (séparées par des virgules) : CUDA Toolkit Missing Toolkit CUDA manquant A compatible NVIDIA GPU was detected, but the CUDA Toolkit is missing. CUDA is required for GPU acceleration in this application. Would you like to download and install it now? Un GPU NVIDIA compatible a été détecté, mais le toolkit CUDA est absent. CUDA est nécessaire pour l'accélération GPU dans cette application. Voulez-vous le télécharger et l'installer maintenant ? Launch Error Erreur de lancement Cannot enable both CUDA and Vulkan simultaneously. Impossible d'activer CUDA et Vulkan simultanément. Missing GGML Runtime Runtime GGML manquant Could not locate the backend runtime DLLs. Tried: %1 %2 Impossible de localiser les DLL d'exécution du backend. Tentatives : %1 %2 Launch Failed Échec du lancement Failed to launch the main application executable: %1 Échec du lancement de l'exécutable principal de l'application : %1 UiTranslator Folder: Dossier : Browse… Parcourir… Use subcategories Utiliser les sous-catégories Create subcategory folders within each category. Créer des sous-dossiers dans chaque catégorie. Categorization type Type de catégorisation Choose how strict the category labels should be. Choisir le niveau de précision des libellés de catégorie. More refined Plus précis Favor detailed labels even if similar items vary. Privilégie des libellés détaillés même si les éléments similaires varient. More consistent Plus cohérent Favor consistent labels across similar items. Privilégie des libellés cohérents pour les éléments similaires. Use a whitelist Utiliser une liste blanche Restrict categories and subcategories to the selected whitelist. Limiter les catégories et sous-catégories à la liste blanche sélectionnée. Select the whitelist used for this run. Sélectionner la liste blanche utilisée pour cette analyse. Categorize files Catégoriser les fichiers Include files in the categorization pass. Inclure les fichiers dans la catégorisation. Categorize folders Catégoriser les dossiers Include directories in the categorization pass. Inclure les dossiers dans la catégorisation. Scan subfolders Scanner les sous-dossiers Scan files inside subfolders and treat them as part of the main folder. Analyser les fichiers dans les sous-dossiers et les traiter comme s'ils étaient dans le dossier principal. Analyze picture files by content (can be slow) Analyser les fichiers image par contenu (peut être lent) Run the visual LLM on supported picture files. Exécuter le LLM visuel sur les fichiers image pris en charge. Process picture files only (ignore any other files) Traiter uniquement les fichiers image (ignorer tous les autres fichiers) Ignore non-picture files in this run. Ignorer les fichiers non image lors de cette analyse. Add image creation date (if available) to category name Ajouter la date de création de l'image (si disponible) au nom de la catégorie Append the image creation date from metadata to the category label. Ajouter la date de création de l'image depuis les métadonnées au libellé de la catégorie. Add photo date and place to filename (if available) Ajouter la date et le lieu de la photo au nom de fichier (si disponibles) Date comes from photo EXIF metadata. Place names are resolved online from GPS coordinates, so network access is required for place prefixes. La date provient des métadonnées EXIF de la photo. Les noms de lieux sont résolus en ligne à partir des coordonnées GPS ; un accès réseau est donc requis pour les préfixes de lieu. Add audio/video metadata to file name (if available) Ajouter les métadonnées audio/vidéo au nom de fichier (si disponibles) Use embedded media tags (for example year, artist, album, title) to build suggested audio/video filenames. Utiliser les tags média intégrés (par exemple année, artiste, album, titre) pour générer des noms de fichiers audio/vidéo suggérés. Offer to rename picture files Proposer de renommer les fichiers image Show suggested filenames for picture files. Afficher des noms de fichiers suggérés pour les fichiers image. Do not categorize picture files (only rename) Ne pas catégoriser les fichiers image (renommer uniquement) Skip categorization for picture files and only rename them. Ignorer la catégorisation des fichiers image et les renommer uniquement. Show or hide picture analysis options Afficher ou masquer les options d'analyse des images Analyze document files by content Analyser les fichiers de documents par contenu Summarize document contents with the selected LLM. Résumer le contenu des documents avec le LLM sélectionné. Process document files only (ignore any other files) Traiter uniquement les fichiers de documents (ignorer tous les autres fichiers) Ignore non-document files in this run. Ignorer les fichiers non document lors de cette analyse. Offer to rename document files Proposer de renommer les fichiers de documents Show suggested filenames for document files. Afficher des noms de fichiers suggérés pour les fichiers de documents. Do not categorize document files (only rename) Ne pas catégoriser les fichiers de documents (renommer uniquement) Skip categorization for document files and only rename them. Ignorer la catégorisation des fichiers de documents et les renommer uniquement. Add document creation date (if available) to category name Ajouter la date de création du document (si disponible) au nom de la catégorie Append the document creation date from metadata to the category label. Ajouter la date de création du document depuis les métadonnées au libellé de la catégorie. Show or hide document analysis options Afficher ou masquer les options d'analyse des documents Stop analyzing Arrêter l'analyse Analyze folder Analyser le dossier File Fichier Type Type Category Catégorie Subcategory Sous-catégorie Status Statut Directory Dossier Ready Prêt &Help &Aide File Explorer Explorateur de fichiers Cancelling analysis… Annulation de l'analyse… Analyzing… Analyse en cours… WhitelistManagerDialog Category whitelists Listes blanches de catégories Add Ajouter Edit Modifier Remove Retirer Cannot remove Impossible de retirer The default list cannot be removed. La liste par défaut ne peut pas être retirée. ================================================ FILE: app/resources/i18n/aifilesorter_it.ts ================================================ CategorizationDialog Tip: Click %1 cells to rename them. Suggerimento: fai clic sulle celle %1 per rinominarle. No items selected Nessun elemento selezionato Highlight one or more rows to select them for processing. Evidenzia una o più righe per selezionarle per l'elaborazione. Bulk edit unavailable Modifica in blocco non disponibile Bulk editing categories is unavailable while picture rename-only mode is active. La modifica in blocco delle categorie non è disponibile mentre è attiva la modalità di sola rinomina delle immagini. Highlight one or more rows to edit their categories. Evidenzia una o più righe per modificarne le categorie. Preview Anteprima Review and Confirm Rivedi e conferma Select all Seleziona tutto Select highlighted Seleziona evidenziati Edit selected... Modifica selezionati... Create subcategory folders Crea cartelle di sottocategoria Dry run (preview only, do not move files) Prova (solo anteprima, non spostare i file) Do not categorize picture files (only rename) Non categorizzare i file immagine (solo rinomina) Do not categorize document files (only rename) Non categorizzare i file di documenti (solo rinominarli) Confirm and Process Conferma e elabora Continue Later Continua più tardi Undo this change Annulla questa modifica Close Chiudi Mark highlighted rows for processing (Ctrl+Space). Contrassegna le righe evidenziate per l'elaborazione (Ctrl+Spazio). Apply category/subcategory values to highlighted rows. Applica i valori di categoria/sottocategoria alle righe evidenziate. Process Elabora File File Type Tipo Suggested filename Nome file suggerito Category Categoria Subcategory Sottocategoria Status Stato Planned destination Destinazione prevista Moved Spostato Renamed Rinominato Renamed & Moved Rinominato e spostato Skipped Saltato Not selected Non selezionato CategorizationProgressDialog [STOP] Analysis will stop after the current item is processed. [STOP] L'analisi si interromperà dopo l'elemento corrente. Image analysis Analisi delle immagini Document analysis Analisi dei documenti Categorization Categorizzazione Directory Cartella Image Immagine Document Documento File File Type Tipo Stage %1: %2 Fase %1: %2 Pending In attesa In progress In corso Complete Completato Processed 0/0 | In progress: 0 | Pending: 0 Elaborati 0/0 | In corso: 0 | In attesa: 0 Processed %1/%2 | In progress: %3 | Pending: %4 Elaborati %1/%2 | In corso: %3 | In attesa: %4 Analyzing Files Analisi dei file Stop Analysis Interrompi analisi Activity log Registro attività CustomApiDialog Custom OpenAI-compatible API API personalizzata compatibile con OpenAI e.g. http://localhost:1234/v1 ad es. http://localhost:1234/v1 e.g. llama-3.1, gpt-4o-mini ad es. llama-3.1, gpt-4o-mini Show Mostra Display name Nome visualizzato Description Descrizione Base URL or endpoint URL di base o endpoint Model Modello API key (optional) Chiave API (opzionale) Enter a base URL (e.g. http://localhost:1234/v1) or a full /chat/completions endpoint. Inserisci un URL di base (ad es. http://localhost:1234/v1) oppure un endpoint /chat/completions completo. CustomLLMDialog Custom local LLM LLM locale personalizzato Browse… Sfoglia… Display name Nome visualizzato Description Descrizione Model file (.gguf) File del modello (.gguf) Select .gguf model Seleziona modello .gguf GGUF models (*.gguf);;All files (*.*) Modelli GGUF (*.gguf);;Tutti i file (*.*) DryRunPreviewDialog Dry run preview Anteprima prova From Da To A Close Chiudi LLMSelectionDialog Choose LLM Mode Scegli la modalità LLM Select LLM Mode Seleziona modalità LLM Larger local model. Slower on CPU, but performs much better with GPU acceleration. Supports: Nvidia (CUDA), Apple (Metal), CPU. Modello locale più grande. Più lento su CPU, ma rende molto meglio con l'accelerazione GPU. Supporta: Nvidia (CUDA), Apple (Metal), CPU. Recommended Consigliato Smaller local model that works quickly even on CPUs. Good for lightweight local use. Modello locale più piccolo, rapido anche su CPU. Buono per un uso locale leggero. Legacy model kept for existing downloads. Modello legacy mantenuto per i download esistenti. Gemini (Google AI Studio API key) Gemini (chiave API di Google AI Studio) Use Google's Gemini models with your AI Studio API key (internet required). Usa i modelli Gemini di Google con la tua chiave API di AI Studio (richiede Internet). AIza... AIza... Show Mostra Gemini API key Chiave API Gemini e.g. gemini-2.5-flash-lite, gemini-2.5-flash, gemini-2.5-pro ad es. gemini-2.5-flash-lite, gemini-2.5-flash, gemini-2.5-pro Model Modello Your key is stored locally in the config file for this device. La tua chiave viene memorizzata localmente nel file di configurazione di questo dispositivo. <a href="https://aistudio.google.com/app/apikey">Get a Gemini API key</a> <a href="https://aistudio.google.com/app/apikey">Ottieni una chiave API Gemini</a> ChatGPT (OpenAI API key) ChatGPT (chiave API OpenAI) Use your own OpenAI API key to access ChatGPT models (internet required). Usa la tua chiave API OpenAI per accedere ai modelli ChatGPT (richiede Internet). sk-... sk-... OpenAI API key Chiave API OpenAI e.g. gpt-4o-mini, gpt-4.1, o3-mini ad es. gpt-4o-mini, gpt-4.1, o3-mini <a href="https://platform.openai.com/api-keys">Get an OpenAI API key</a> <a href="https://platform.openai.com/api-keys">Ottieni una chiave API OpenAI</a> Custom OpenAI-compatible API (advanced) API personalizzata compatibile con OpenAI (avanzata) Use OpenAI-compatible endpoints such as LM Studio or Ollama (local or remote). Usa endpoint compatibili con OpenAI come LM Studio o Ollama (locali o remoti). Add… Aggiungi… Edit… Modifica… Delete Elimina Custom local LLM (gguf) LLM locale personalizzato (gguf) Downloads Download Download Scarica Image analysis models (LLaVA) Modelli di analisi immagini (LLaVA) Download the visual LLM files required for image analysis. Scarica i file LLM visivi necessari per l'analisi delle immagini. LLaVA 1.6 Mistral 7B (text model) LLaVA 1.6 Mistral 7B (modello di testo) LLaVA mmproj (vision encoder) LLaVA mmproj (codificatore visivo) Choose or add a custom model. Scegli o aggiungi un modello personalizzato. Custom model selected. Modello personalizzato selezionato. Selection ready. Selezione pronta. Choose or add a custom API endpoint. Scegli o aggiungi un endpoint API personalizzato. Custom API selected. API personalizzata selezionata. ChatGPT will use your API key and model. ChatGPT userà la tua chiave API e il tuo modello. Enter your OpenAI API key and model to continue. Inserisci la tua chiave API OpenAI e il modello per continuare. Gemini will use your API key and model. Gemini userà la tua chiave API e il tuo modello. Enter your Gemini API key and model to continue. Inserisci la tua chiave API Gemini e il modello per continuare. Model ready. Modello pronto. Resume download Riprendi download Partial download detected. You can resume. Download parziale rilevato. Puoi riprendere. Download required. Download richiesto. Unsupported LLM selection. Selezione LLM non supportata. Missing download URL environment variable (%1). Variabile d'ambiente dell'URL di download mancante (%1). Delete downloaded model? Eliminare il modello scaricato? Delete the downloaded model %1? Eliminare il modello scaricato %1? Failed to delete downloaded model. Impossibile eliminare il modello scaricato. Deleted downloaded model. Modello scaricato eliminato. No downloaded model found to delete. Nessun modello scaricato da eliminare. Remote URL URL remoto Local path Percorso locale File size Dimensione file File size: unknown Dimensione file: sconosciuta Delete custom model Elimina modello personalizzato Remove '%1' from your custom LLMs? This does not delete the file on disk. Rimuovere '%1' dai tuoi LLM personalizzati? Questo non elimina il file dal disco. Delete custom API Elimina API personalizzata Remove '%1' from your custom API list? This does not affect the server. Rimuovere '%1' dalla tua lista di API personalizzate? Questo non influisce sul server. Missing download URL environment variable. Variabile d'ambiente dell'URL di download mancante. Downloading… Download in corso… Download complete. Download completato. Download cancelled. Download annullato. Download error: %1 Errore di download: %1 MainApp File Explorer Esplora file Select Directory Seleziona cartella Loaded folder %1 Cartella %1 caricata Analysis cancelled Analisi annullata Folder selected: %1 Cartella selezionata: %1 More consistent Più coerente More refined Più dettagliata Recategorize folder? Ricategorizzare la cartella? This folder was categorized using the %1 mode. Do you want to recategorize it now using the %2 mode? Questa cartella è stata categorizzata in modalità %1. Vuoi ricategorizzarla ora in modalità %2? Recategorize Ricategorizza Keep existing Mantieni Failed to reset cached categorization for this folder. Impossibile ripristinare la categorizzazione memorizzata per questa cartella. Download required Download richiesto Image analysis requires visual LLM files. Download them now? L'analisi delle immagini richiede i file LLM visivi. Scaricarli ora? OK OK Stop analyzing Interrompi analisi Analyzing… Analisi in corso… Analyze folder Analizza cartella Ready Pronto Undo last run Annulla l'ultima esecuzione This will attempt to move files back to their original locations based on the last run. Plan file: %1 Verrà effettuato un tentativo di riportare i file nelle loro posizioni originali in base all'ultima esecuzione. File di piano: %1 Restored %1 file(s). Skipped %2. Ripristinati %1 file. Saltati %2. Undo complete Annullamento completato Thank you for using AI File Sorter! You have categorized %1 files thus far. I, the author, really hope this app was useful for you. Grazie per usare AI File Sorter! Hai già categorizzato %1 file. Io, l'autore, spero davvero che questa app ti sia stata utile. AI File Sorter takes hundreds of hours of development, feature work, support replies, and ongoing costs such as servers and remote-model infrastructure. If the app saves you time or brings value, please consider supporting it so it can keep improving. AI File Sorter richiede centinaia di ore di sviluppo, lavoro sulle funzionalità, risposte di supporto e costi continui come server e infrastruttura per modelli remoti. Se l'app ti fa risparmiare tempo o ti offre valore, valuta di supportarla affinché possa continuare a migliorare. Already donated? Click "I have already donated" to enter your donation code and permanently disable this reminder. Hai già donato? Fai clic su "Ho già donato" per inserire il tuo codice di donazione e disattivare definitivamente questo promemoria. Donate to permanently hide the donation dialog Fai una donazione per nascondere permanentemente la finestra di dialogo di donazione I'm not yet sure Non sono ancora sicuro I have already donated Ho già donato Donation code Codice di donazione Enter the donation code generated after your donation. A valid code will permanently hide the donation dialog. Inserisci il codice di donazione generato dopo la tua donazione. Un codice valido nasconderà permanentemente la finestra di dialogo di donazione. Invalid donation code Codice di donazione non valido The donation code is invalid. Please try again or press Cancel. Il codice di donazione non è valido. Riprova o premi Annulla. Open donation page Apri la pagina delle donazioni Could not open your browser automatically. Please open this link manually: %1 Impossibile aprire automaticamente il browser. Apri manualmente questo link: %1 Directory Cartella File File [ARCHIVE] Already categorized highlights: [ARCHIVIO] Elementi già categorizzati: [DONE] No files to categorize. [FATTO] Nessun file da categorizzare. [QUEUE] Items waiting for categorization: [CODA] Elementi in attesa di categorizzazione: [SCAN] Exploring %1 [SCANSIONE] Esplorazione di %1 [PROCESS] Letting the AI do its magic... [ELABORAZIONE] L'IA fa la sua magia... [VISION] Decoding image batch %1/%2 (%3%) [VISIONE] Decodifica del lotto di immagini %1/%2 (%3%) Switch image analysis to CPU? Passare l'analisi delle immagini alla CPU? Image analysis ran out of GPU memory. L'analisi delle immagini ha esaurito la memoria GPU. Retry on CPU instead? Cancel will skip visual analysis and fall back to filename-based categorization. Riprovare invece sulla CPU? Annulla salterà l'analisi visiva e userà la categorizzazione basata sul nome file. [VISION-ERROR] %1 (%2) [ERRORE-VISIONE] %1 (%2) [VISION] Switching visual analysis to CPU. [VISION] Passaggio dell'analisi visiva alla CPU. [VISION-ERROR] %1 [VISION-ERROR] %1 [VISION] Visual analysis disabled; falling back to filenames. [VISION] Analisi visiva disattivata; ritorno ai nomi file. [VISION] Using cached suggestion for %1 [VISIONE] Uso del suggerimento in cache per %1 [VISION] Analyzing %1 [VISIONE] Analisi di %1 [VISION] GPU memory issue detected. Switching to CPU. [VISION] Rilevato un problema di memoria GPU. Passaggio alla CPU. [VISION] Visual analysis disabled for remaining images. [VISION] Analisi visiva disattivata per le immagini rimanenti. [DOC-ERROR] %1 (%2) [ERRORE-DOC] %1 (%2) [DOC] Using cached suggestion for %1 [DOC] Uso del suggerimento in cache per %1 [DOC] Analyzing %1 [DOC] Analisi di %1 [SORT] %1 (%2) [ORDINA] %1 (%2) Cancelling analysis… Annullamento analisi… Switch local AI to CPU? Passare l'IA locale alla CPU? The local model encountered a GPU error or ran out of memory. Il modello locale ha riscontrato un errore GPU o ha esaurito la memoria. Retry on CPU instead? Cancel will stop this analysis. Riprovare invece sulla CPU? Annulla interromperà questa analisi. [WARN] GPU fallback to CPU declined. Cancelling analysis. [WARN] Rifiutato il fallback da GPU a CPU. Annullamento dell'analisi. [WARN] GPU acceleration failed to initialize. Continuing on CPU (slower). [AVVISO] Impossibile inizializzare l'accelerazione GPU. Continuo su CPU (più lento). [WARN] %1 will be re-categorized: %2 [AVVISO] %1 verrà ricategorizzato: %2 QObject Edit selected items Modifica elementi selezionati Leave empty to keep existing Lascia vuoto per mantenere i valori esistenti Category Categoria Subcategory Sottocategoria About %1 Informazioni su %1 About Informazioni Credits Crediti About the AGPL License Informazioni sulla licenza AGPL AI File Sorter is distributed under the GNU Affero General Public License v3.0.<br><br>You can access the full source code at <a href="https://github.com/hyperfield/ai-file-sorter">github.com/hyperfield/ai-file-sorter</a>.<br><br>A full copy of the license is provided with this application and available online at <a href="https://www.gnu.org/licenses/agpl-3.0.html">gnu.org</a>. AI File Sorter è distribuito sotto la GNU Affero General Public License v3.0.<br><br>Puoi accedere al codice sorgente completo su <a href="https://github.com/hyperfield/ai-file-sorter">github.com/hyperfield/ai-file-sorter</a>.<br><br>Una copia completa della licenza è fornita con l'applicazione ed è disponibile online su <a href="https://www.gnu.org/licenses/agpl-3.0.html">gnu.org</a>. CPU CPU Metal Metal CUDA CUDA Vulkan Vulkan Metal (auto) Metal (automatico) Vulkan (auto) Vulkan (automatico) %1 (auto) %1 (automatico) Auto Automatico CPU (%1) CPU (%1) GPU (target: %1) GPU (destinazione: %1) GPU via Vulkan unavailable GPU via Vulkan non disponibile GPU via CUDA unavailable GPU via CUDA non disponibile Vulkan unavailable Vulkan non disponibile GPU via Metal unavailable GPU via Metal non disponibile GPU init failed Inizializzazione GPU non riuscita Default model: %1 Modello predefinito: %1 Measuring categorization (warm-up + %1 run(s))... Misurazione della categorizzazione (riscaldamento + %1 esecuzione/i)... Measuring document analysis (warm-up + %1 run(s))... Misurazione dell'analisi dei documenti (riscaldamento + %1 esecuzione/i)... Categorization: %1 Categorizzazione: %1 done completato failed fallito Warm-up: %1 Riscaldamento: %1 Init: %1 Inizializzazione: %1 Per-item (median of %1): %2 Per elemento (mediana di %1): %2 Per-item runs: %1 Esecuzioni per elemento: %1 Details: %1 Dettagli: %1 Backend used: %1 Backend utilizzato: %1 Document analysis: %1 Analisi dei documenti: %1 Model failed to load: %1 Impossibile caricare il modello: %1 optimal ottimale acceptable accettabile a bit long piuttosto lungo n/a n/d Result Risultato Categorization speed: unavailable Velocità di categorizzazione: non disponibile Document analysis speed: unavailable Velocità analisi documenti: non disponibile Categorization speed: %1 Velocità di categorizzazione: %1 Document analysis speed: %1 Velocità analisi documenti: %1 Image analysis speed: unavailable Velocità analisi immagini: non disponibile Image analysis speed: %1 Velocità analisi immagini: %1 Recommended Local LLM choice: %1 LLM locale consigliato: %1 You can toggle LLMs in Settings -> Select LLM Puoi cambiare i LLM in Impostazioni -> Seleziona LLM Compatibility Benchmark Benchmark di compatibilità Run a quick performance check to estimate how image analysis, document analysis, and file categorization will perform on your system. Esegue una rapida verifica delle prestazioni per stimare come l'analisi delle immagini, l'analisi dei documenti e la categorizzazione dei file funzioneranno sul sistema. It is recommended to quit any CPU- and GPU-intensive applications before running this test. Si consiglia di chiudere le applicazioni intensive per CPU e GPU prima di eseguire questo test. Run benchmark Avvia benchmark Do not auto-show this dialog again Non mostrare automaticamente questo dialogo Stop Benchmark Interrompi il benchmark Close Chiudi No previous results yet. Nessun risultato precedente. Last run: %1 Ultima esecuzione: %1 Previous results: Risultati precedenti: No downloaded LLM files detected. Download a categorization or visual model to run the benchmark. Nessun file LLM scaricato rilevato. Scarica un modello di categorizzazione o visivo per eseguire il benchmark. Starting system compatibility check... Avvio della verifica di compatibilità del sistema... CPU threads detected: %1 Thread CPU rilevati: %1 GPU backend override: %1 Override del backend GPU: %1 Metal available: %1 Metal disponibile: %1 yes no no GPU memory allocation (Metal): %1 free / %2 total Allocazione memoria GPU (Metal): %1 liberi / %2 totali GPU memory allocation (Metal): unavailable Allocazione memoria GPU (Metal): non disponibile CUDA available: %1 CUDA disponibile: %1 CUDA memory (allocatable): %1 free / %2 total Memoria CUDA (allocabile): %1 libera / %2 totale (device total: %1) (totale del dispositivo: %1) GPU memory allocation (Vulkan): %1 free / %2 total Allocazione memoria GPU (Vulkan): %1 liberi / %2 totali GPU memory allocation (Vulkan): unavailable Allocazione memoria GPU (Vulkan): non disponibile Temporary directory setup failed; benchmark sample file creation may fail. La configurazione della directory temporanea non è riuscita; la creazione del file di esempio del benchmark potrebbe non riuscire. No default models downloaded; skipping categorization and document checks. Nessun modello predefinito scaricato; salto la categorizzazione e i controlli sui documenti. Default models detected: %1 Modelli predefiniti rilevati: %1 Benchmark stopped. Benchmark interrotto. Running image analysis test... Esecuzione del test di analisi immagini... unavailable non disponibile Image analysis: skipped (%1) Analisi immagini: ignorata (%1) Image analysis: %1 Analisi immagini: %1 Time: %1 Tempo: %1 GPU disabled by backend override GPU disabilitata dall'override del backend Backend used (image analysis): %1 Backend utilizzato (analisi immagini): %1 Benchmark failed: %1 Benchmark non riuscito: %1 [STOP] Benchmark will stop after the current step is processed. [STOP] Il benchmark verrà interrotto dopo lo step corrente. Error Errore Local LLM (%1) LLM locale (%1) Local LLM LLM locale Support %1 Sostieni %1 Required Update Available Aggiornamento obbligatorio disponibile A required update is available. Please update to continue. If you choose to quit, the application will close. È disponibile un aggiornamento obbligatorio. Aggiorna per continuare. Se scegli di uscire, l'applicazione si chiuderà. Update Now Aggiorna ora Quit Esci Optional Update Available Aggiornamento opzionale disponibile An optional update is available. Would you like to update now? È disponibile un aggiornamento opzionale. Vuoi aggiornare ora? Skip This Version Salta questa versione Cancel Annulla Downloading Update Download aggiornamento Downloading the update installer... Download del programma di installazione dell'aggiornamento... Failed to prepare the update installer. %1 Impossibile preparare il programma di installazione dell'aggiornamento. %1 Installer Ready Programma di installazione pronto Quit the app and launch the installer to update Chiudi l'app e avvia il programma di installazione per aggiornare Quit and Launch Installer Chiudi e avvia il programma di installazione The installer could not be launched. Impossibile avviare il programma di installazione. No download target is available for this update. Nessuna destinazione di download disponibile per questo aggiornamento. Update Failed Aggiornamento non riuscito Update manually Aggiorna manualmente Edit whitelist Modifica whitelist Name: Nome: Categories (comma separated): Categorie (separate da virgole): Subcategories (comma separated): Sottocategorie (separate da virgole): CUDA Toolkit Missing Toolkit CUDA mancante A compatible NVIDIA GPU was detected, but the CUDA Toolkit is missing. CUDA is required for GPU acceleration in this application. Would you like to download and install it now? È stata rilevata una GPU NVIDIA compatibile, ma manca il CUDA Toolkit. CUDA è necessario per l'accelerazione GPU in questa applicazione. Vuoi scaricarlo e installarlo ora? Launch Error Errore di avvio Cannot enable both CUDA and Vulkan simultaneously. Impossibile abilitare contemporaneamente CUDA e Vulkan. Missing GGML Runtime Runtime GGML mancante Could not locate the backend runtime DLLs. Tried: %1 %2 Impossibile trovare le DLL di runtime del backend. Percorsi provati: %1 %2 Launch Failed Avvio non riuscito Failed to launch the main application executable: %1 Impossibile avviare l'eseguibile principale dell'applicazione: %1 UiTranslator Folder: Cartella: Browse… Sfoglia… Use subcategories Usa sottocategorie Create subcategory folders within each category. Crea sottocartelle all'interno di ogni categoria. Categorization type Tipo di categorizzazione Choose how strict the category labels should be. Scegli quanto devono essere rigorose le etichette delle categorie. More refined Più dettagliata Favor detailed labels even if similar items vary. Privilegia etichette dettagliate anche se gli elementi simili variano. More consistent Più coerente Favor consistent labels across similar items. Privilegia etichette coerenti tra elementi simili. Use a whitelist Usa whitelist Restrict categories and subcategories to the selected whitelist. Limita categorie e sottocategorie alla whitelist selezionata. Select the whitelist used for this run. Seleziona la whitelist usata per questa analisi. Categorize files Categoriza i file Include files in the categorization pass. Includi i file nella categorizzazione. Categorize folders Categoriza le cartelle Include directories in the categorization pass. Includi le cartelle nella categorizzazione. Scan subfolders Scansiona le sottocartelle Scan files inside subfolders and treat them as part of the main folder. Scansiona i file nelle sottocartelle e trattali come se fossero nella cartella principale. Analyze picture files by content (can be slow) Analizza i file immagine in base al contenuto (può essere lento) Run the visual LLM on supported picture files. Esegui il LLM visivo sui file immagine supportati. Process picture files only (ignore any other files) Elabora solo i file immagine (ignora tutti gli altri file) Ignore non-picture files in this run. Ignora i file non immagine in questa analisi. Add image creation date (if available) to category name Aggiungi la data di creazione dell'immagine (se disponibile) al nome della categoria Append the image creation date from metadata to the category label. Aggiungi la data di creazione dell'immagine dai metadati all'etichetta della categoria. Add photo date and place to filename (if available) Aggiungi data e luogo della foto al nome file (se disponibili) Date comes from photo EXIF metadata. Place names are resolved online from GPS coordinates, so network access is required for place prefixes. La data proviene dai metadati EXIF della foto. I nomi dei luoghi vengono risolti online dalle coordinate GPS, quindi è necessaria la rete per i prefissi di luogo. Add audio/video metadata to file name (if available) Aggiungi metadati audio/video al nome file (se disponibili) Use embedded media tags (for example year, artist, album, title) to build suggested audio/video filenames. Usa i tag multimediali incorporati (ad esempio anno, artista, album, titolo) per creare nomi file audio/video suggeriti. Offer to rename picture files Offri di rinominare i file immagine Show suggested filenames for picture files. Mostra nomi file suggeriti per i file immagine. Do not categorize picture files (only rename) Non categorizzare i file immagine (solo rinomina) Skip categorization for picture files and only rename them. Salta la categorizzazione dei file immagine e rinominali soltanto. Show or hide picture analysis options Mostra o nascondi le opzioni di analisi immagini Analyze document files by content Analizza i file di documenti in base al contenuto Summarize document contents with the selected LLM. Riassumi il contenuto dei documenti con il LLM selezionato. Process document files only (ignore any other files) Elabora solo i file di documenti (ignora tutti gli altri file) Ignore non-document files in this run. Ignora i file non documenti in questa analisi. Offer to rename document files Offri di rinominare i file di documenti Show suggested filenames for document files. Mostra nomi file suggeriti per i file di documenti. Do not categorize document files (only rename) Non categorizzare i file di documenti (solo rinominarli) Skip categorization for document files and only rename them. Salta la categorizzazione dei file di documenti e rinominali soltanto. Add document creation date (if available) to category name Aggiungi la data di creazione del documento (se disponibile) al nome della categoria Append the document creation date from metadata to the category label. Aggiungi la data di creazione del documento dai metadati all'etichetta della categoria. Show or hide document analysis options Mostra o nascondi le opzioni di analisi documenti Stop analyzing Interrompi analisi Analyze folder Analizza cartella File File Type Tipo Category Categoria Subcategory Sottocategoria Status Stato Directory Cartella Ready Pronto &Help &Aiuto File Explorer Esplora file Cancelling analysis… Annullamento analisi… Analyzing… Analisi in corso… WhitelistManagerDialog Category whitelists Whitelist delle categorie Add Aggiungi Edit Modifica Remove Rimuovi Cannot remove Impossibile rimuovere The default list cannot be removed. L'elenco predefinito non può essere rimosso. ================================================ FILE: app/resources/i18n/aifilesorter_ko.ts ================================================ CategorizationDialog Tip: Click %1 cells to rename them. 팁: 이름을 바꾸려면 %1 셀을 클릭하세요. No items selected 선택된 항목이 없습니다 Highlight one or more rows to select them for processing. 처리 대상으로 선택하려면 하나 이상의 행을 강조 표시하세요. Bulk edit unavailable 일괄 편집을 사용할 수 없습니다 Bulk editing categories is unavailable while picture rename-only mode is active. 사진 이름만 변경 모드가 활성화되어 있는 동안에는 카테고리를 일괄 편집할 수 없습니다. Highlight one or more rows to edit their categories. 카테고리를 편집하려면 하나 이상의 행을 강조 표시하세요. Preview 미리보기 Review and Confirm 검토 및 확인 Select all 모두 선택 Select highlighted 강조된 항목 선택 Edit selected... 선택 항목 편집... Create subcategory folders 하위 카테고리 폴더 만들기 Dry run (preview only, do not move files) 드라이 런(미리보기만, 파일 이동 안 함) Do not categorize picture files (only rename) 이미지 파일 분류 안 함(이름만 변경) Do not categorize document files (only rename) 문서 파일 분류 안 함(이름만 변경) Confirm and Process 확인 및 처리 Continue Later 나중에 계속 Undo this change 이 변경 사항 실행 취소 Close 닫기 Mark highlighted rows for processing (Ctrl+Space). 강조된 행을 처리 대상으로 표시합니다(Ctrl+Space). Apply category/subcategory values to highlighted rows. 카테고리/하위 카테고리 값을 강조된 행에 적용합니다. Process 처리 File 파일 Type 유형 Suggested filename 추천 파일명 Category 카테고리 Subcategory 하위 카테고리 Status 상태 Planned destination 계획된 대상 Moved 이동됨 Renamed 이름 변경됨 Renamed & Moved 이름이 변경되고 이동됨 Skipped 건너뜀 Not selected 선택되지 않음 CategorizationProgressDialog [STOP] Analysis will stop after the current item is processed. [STOP] 현재 항목 처리가 끝나면 분석이 중지됩니다. Image analysis 이미지 분석 Document analysis 문서 분석 Categorization 분류 Directory 폴더 Image 이미지 Document 문서 File 파일 Type 유형 Stage %1: %2 단계 %1: %2 Pending 대기 중 In progress 진행 중 Complete 완료됨 Processed 0/0 | In progress: 0 | Pending: 0 처리됨 0/0 | 진행 중: 0 | 대기 중: 0 Processed %1/%2 | In progress: %3 | Pending: %4 처리됨 %1/%2 | 진행 중: %3 | 대기 중: %4 Analyzing Files 파일 분석 중 Stop Analysis 분석 중지 Activity log 활동 로그 CustomApiDialog Custom OpenAI-compatible API 사용자 지정 OpenAI 호환 API e.g. http://localhost:1234/v1 예: http://localhost:1234/v1 e.g. llama-3.1, gpt-4o-mini 예: llama-3.1, gpt-4o-mini Show 표시 Display name 표시 이름 Description 설명 Base URL or endpoint 기본 URL 또는 엔드포인트 Model 모델 API key (optional) API 키(선택 사항) Enter a base URL (e.g. http://localhost:1234/v1) or a full /chat/completions endpoint. 기본 URL(예: http://localhost:1234/v1) 또는 전체 /chat/completions 엔드포인트를 입력하세요. CustomLLMDialog Custom local LLM 사용자 지정 로컬 LLM Browse… 찾아보기… Display name 표시 이름 Description 설명 Model file (.gguf) 모델 파일(.gguf) Select .gguf model .gguf 모델 선택 GGUF models (*.gguf);;All files (*.*) GGUF 모델 (*.gguf);;모든 파일 (*.*) DryRunPreviewDialog Dry run preview 드라이 런 미리보기 From 원본 To 대상 Close 닫기 LLMSelectionDialog Choose LLM Mode LLM 모드 선택 Select LLM Mode LLM 모드 선택 Larger local model. Slower on CPU, but performs much better with GPU acceleration. Supports: Nvidia (CUDA), Apple (Metal), CPU. 더 큰 로컬 모델입니다. CPU에서는 느리지만 GPU 가속을 사용하면 성능이 훨씬 좋아집니다. 지원 대상: Nvidia (CUDA), Apple (Metal), CPU. Recommended 권장 Smaller local model that works quickly even on CPUs. Good for lightweight local use. 더 작은 로컬 모델로 CPU에서도 빠르게 동작합니다. 가벼운 로컬 사용에 적합합니다. Legacy model kept for existing downloads. 기존 다운로드를 위해 레거시 모델을 유지합니다. Gemini (Google AI Studio API key) Gemini (Google AI Studio API 키) Use Google's Gemini models with your AI Studio API key (internet required). AI Studio API 키로 Google의 Gemini 모델을 사용하세요(인터넷 필요). AIza... AIza... Show 표시 Gemini API key Gemini API 키 e.g. gemini-2.5-flash-lite, gemini-2.5-flash, gemini-2.5-pro 예: gemini-2.5-flash-lite, gemini-2.5-flash, gemini-2.5-pro Model 모델 Your key is stored locally in the config file for this device. 키는 이 기기의 설정 파일에 로컬로 저장됩니다. <a href="https://aistudio.google.com/app/apikey">Get a Gemini API key</a> <a href="https://aistudio.google.com/app/apikey">Gemini API 키 받기</a> ChatGPT (OpenAI API key) ChatGPT (OpenAI API 키) Use your own OpenAI API key to access ChatGPT models (internet required). ChatGPT 모델에 액세스하려면 자신의 OpenAI API 키를 사용하세요(인터넷 필요). sk-... sk-... OpenAI API key OpenAI API 키 e.g. gpt-4o-mini, gpt-4.1, o3-mini 예: gpt-4o-mini, gpt-4.1, o3-mini <a href="https://platform.openai.com/api-keys">Get an OpenAI API key</a> <a href="https://platform.openai.com/api-keys">OpenAI API 키 받기</a> Custom OpenAI-compatible API (advanced) 사용자 지정 OpenAI 호환 API(고급) Use OpenAI-compatible endpoints such as LM Studio or Ollama (local or remote). LM Studio나 Ollama 같은 OpenAI 호환 엔드포인트를 사용하세요(로컬 또는 원격). Add… 추가… Edit… 편집… Delete 삭제 Custom local LLM (gguf) 사용자 지정 로컬 LLM (gguf) Downloads 다운로드 Download 다운로드 Image analysis models (LLaVA) 이미지 분석 모델(LLaVA) Download the visual LLM files required for image analysis. 이미지 분석에 필요한 비전 LLM 파일을 다운로드합니다. LLaVA 1.6 Mistral 7B (text model) LLaVA 1.6 Mistral 7B(텍스트 모델) LLaVA mmproj (vision encoder) LLaVA mmproj(비전 인코더) Choose or add a custom model. 사용자 지정 모델을 선택하거나 추가하세요. Custom model selected. 사용자 지정 모델이 선택되었습니다. Selection ready. 선택이 준비되었습니다. Choose or add a custom API endpoint. 사용자 지정 API 엔드포인트를 선택하거나 추가하세요. Custom API selected. 사용자 지정 API가 선택되었습니다. ChatGPT will use your API key and model. ChatGPT가 API 키와 모델을 사용합니다. Enter your OpenAI API key and model to continue. 계속하려면 OpenAI API 키와 모델을 입력하세요. Gemini will use your API key and model. Gemini가 API 키와 모델을 사용합니다. Enter your Gemini API key and model to continue. 계속하려면 Gemini API 키와 모델을 입력하세요. Model ready. 모델 준비 완료. Resume download 다운로드 재개 Partial download detected. You can resume. 부분 다운로드가 감지되었습니다. 재개할 수 있습니다. Download required. 다운로드가 필요합니다. Unsupported LLM selection. 지원되지 않는 LLM 선택입니다. Missing download URL environment variable (%1). 다운로드 URL 환경 변수가 없습니다(%1). Delete downloaded model? 다운로드한 모델을 삭제할까요? Delete the downloaded model %1? 다운로드한 모델 %1을(를) 삭제할까요? Failed to delete downloaded model. 다운로드한 모델을 삭제하지 못했습니다. Deleted downloaded model. 다운로드한 모델을 삭제했습니다. No downloaded model found to delete. 삭제할 다운로드한 모델이 없습니다. Remote URL 원격 URL Local path 로컬 경로 File size 파일 크기 File size: unknown 파일 크기: 알 수 없음 Delete custom model 사용자 지정 모델 삭제 Remove '%1' from your custom LLMs? This does not delete the file on disk. 사용자 지정 LLM에서 '%1'을(를) 제거할까요? 이렇게 해도 디스크의 파일은 삭제되지 않습니다. Delete custom API 사용자 지정 API 삭제 Remove '%1' from your custom API list? This does not affect the server. 사용자 지정 API 목록에서 '%1'을(를) 제거할까요? 서버에는 영향을 주지 않습니다. Missing download URL environment variable. 다운로드 URL 환경 변수가 없습니다. Downloading… 다운로드 중… Download complete. 다운로드 완료. Download cancelled. 다운로드가 취소되었습니다. Download error: %1 다운로드 오류: %1 MainApp File Explorer 파일 탐색기 Select Directory 폴더 선택 Loaded folder %1 폴더 %1 불러옴 Analysis cancelled 분석이 취소됨 Folder selected: %1 선택한 폴더: %1 More consistent 더 일관적 More refined 더 세분화 Recategorize folder? 폴더를 다시 분류할까요? This folder was categorized using the %1 mode. Do you want to recategorize it now using the %2 mode? 이 폴더는 %1 모드로 분류되었습니다. 지금 %2 모드로 다시 분류할까요? Recategorize 다시 분류 Keep existing 기존 유지 Failed to reset cached categorization for this folder. 이 폴더의 캐시된 분류를 초기화하지 못했습니다. Download required 다운로드 필요 Image analysis requires visual LLM files. Download them now? 이미지 분석에는 비전 LLM 파일이 필요합니다. 지금 다운로드할까요? OK 확인 Stop analyzing 분석 중지 Analyzing… 분석 중… Analyze folder 폴더 분석 Ready 준비됨 Undo last run 마지막 실행 취소 This will attempt to move files back to their original locations based on the last run. Plan file: %1 마지막 실행을 기준으로 파일을 원래 위치로 되돌리려고 시도합니다. 계획 파일: %1 Restored %1 file(s). Skipped %2. 파일 %1개를 복원했습니다. %2개는 건너뛰었습니다. Undo complete 실행 취소 완료 Thank you for using AI File Sorter! You have categorized %1 files thus far. I, the author, really hope this app was useful for you. AI File Sorter를 사용해 주셔서 감사합니다! 지금까지 %1개의 파일을 분류하셨습니다. 이 앱이 도움이 되었기를 바랍니다. AI File Sorter takes hundreds of hours of development, feature work, support replies, and ongoing costs such as servers and remote-model infrastructure. If the app saves you time or brings value, please consider supporting it so it can keep improving. AI File Sorter에는 수백 시간의 개발, 기능 작업, 지원 응답, 그리고 서버와 원격 모델 인프라 같은 지속적인 비용이 들어갑니다. 이 앱이 시간을 절약해 주거나 가치를 제공한다면 계속 개선될 수 있도록 지원을 고려해 주세요. Already donated? Click "I have already donated" to enter your donation code and permanently disable this reminder. 이미 기부하셨나요? 기부 코드를 입력해 이 알림을 영구적으로 끄려면 "이미 기부했습니다"를 클릭하세요. Donate to permanently hide the donation dialog 기부 대화 상자를 영구히 숨기려면 기부하기 I'm not yet sure 아직 모르겠어요 I have already donated 이미 기부했습니다 Donation code 기부 코드 Enter the donation code generated after your donation. A valid code will permanently hide the donation dialog. 기부 후 생성된 기부 코드를 입력하세요. 유효한 코드를 입력하면 기부 대화 상자가 영구적으로 숨겨집니다. Invalid donation code 유효하지 않은 기부 코드 The donation code is invalid. Please try again or press Cancel. 기부 코드가 유효하지 않습니다. 다시 시도하거나 취소를 누르세요. Open donation page 기부 페이지 열기 Could not open your browser automatically. Please open this link manually: %1 브라우저를 자동으로 열 수 없습니다. 다음 링크를 직접 열어 주세요: %1 Directory 폴더 File 파일 [ARCHIVE] Already categorized highlights: [ARCHIVE] 이미 분류된 항목: [DONE] No files to categorize. [DONE] 분류할 파일이 없습니다. [QUEUE] Items waiting for categorization: [QUEUE] 분류 대기 항목: [SCAN] Exploring %1 [SCAN] %1 탐색 중 [PROCESS] Letting the AI do its magic... [PROCESS] AI가 작업 중... [VISION] Decoding image batch %1/%2 (%3%) [VISION] 이미지 배치 %1/%2 디코딩 중 (%3%) Switch image analysis to CPU? 이미지 분석을 CPU로 전환할까요? Image analysis ran out of GPU memory. 이미지 분석 중 GPU 메모리가 부족해졌습니다. Retry on CPU instead? Cancel will skip visual analysis and fall back to filename-based categorization. 대신 CPU에서 다시 시도할까요? 취소하면 시각 분석을 건너뛰고 파일 이름 기반 분류로 대체합니다. [VISION-ERROR] %1 (%2) [VISION-ERROR] %1 (%2) [VISION] Switching visual analysis to CPU. [VISION] 시각 분석을 CPU로 전환합니다. [VISION-ERROR] %1 [VISION-ERROR] %1 [VISION] Visual analysis disabled; falling back to filenames. [VISION] 시각 분석이 비활성화되어 파일 이름으로 대체합니다. [VISION] Using cached suggestion for %1 [VISION] %1에 대해 캐시된 제안 사용 중 [VISION] Analyzing %1 [VISION] %1 분석 중 [VISION] GPU memory issue detected. Switching to CPU. [VISION] GPU 메모리 문제가 감지되었습니다. CPU로 전환합니다. [VISION] Visual analysis disabled for remaining images. [VISION] 남은 이미지에 대한 시각 분석이 비활성화되었습니다. [DOC-ERROR] %1 (%2) [DOC-ERROR] %1 (%2) [DOC] Using cached suggestion for %1 [DOC] %1에 대해 캐시된 제안 사용 중 [DOC] Analyzing %1 [DOC] %1 분석 중 [SORT] %1 (%2) [SORT] %1 (%2) Cancelling analysis… 분석 취소 중… Switch local AI to CPU? 로컬 AI를 CPU로 전환할까요? The local model encountered a GPU error or ran out of memory. 로컬 모델에서 GPU 오류가 발생했거나 메모리가 부족해졌습니다. Retry on CPU instead? Cancel will stop this analysis. 대신 CPU에서 다시 시도할까요? 취소하면 이 분석이 중단됩니다. [WARN] GPU fallback to CPU declined. Cancelling analysis. [WARN] GPU에서 CPU로의 전환이 거부되었습니다. 분석을 취소합니다. [WARN] GPU acceleration failed to initialize. Continuing on CPU (slower). [WARN] GPU 가속을 초기화하지 못했습니다. CPU로 계속 진행합니다(느려짐). [WARN] %1 will be re-categorized: %2 [WARN] %1 재분류 예정: %2 QObject Edit selected items 선택한 항목 편집 Leave empty to keep existing 기존 값을 유지하려면 비워 두세요 Category 카테고리 Subcategory 하위 카테고리 Error 오류 Local LLM (%1) 로컬 LLM (%1) Local LLM 로컬 LLM Support %1 %1 지원 About %1 %1 정보 About 정보 Credits 크레딧 About the AGPL License AGPL 라이선스 정보 AI File Sorter is distributed under the GNU Affero General Public License v3.0.<br><br>You can access the full source code at <a href="https://github.com/hyperfield/ai-file-sorter">github.com/hyperfield/ai-file-sorter</a>.<br><br>A full copy of the license is provided with this application and available online at <a href="https://www.gnu.org/licenses/agpl-3.0.html">gnu.org</a>. AI File Sorter는 GNU Affero General Public License v3.0에 따라 배포됩니다.<br><br>전체 소스 코드는 <a href="https://github.com/hyperfield/ai-file-sorter">github.com/hyperfield/ai-file-sorter</a>에서 확인할 수 있습니다.<br><br>라이선스 전문은 이 애플리케이션과 함께 제공되며 <a href="https://www.gnu.org/licenses/agpl-3.0.html">gnu.org</a>에서도 확인할 수 있습니다. CPU CPU Metal Metal CUDA CUDA Vulkan Vulkan Metal (auto) Metal (자동) Vulkan (auto) Vulkan (자동) %1 (auto) %1 (자동) Auto 자동 CPU (%1) CPU (%1) GPU (target: %1) GPU (대상: %1) GPU via Vulkan unavailable Vulkan을 통한 GPU 사용 불가 GPU via CUDA unavailable CUDA를 통한 GPU 사용 불가 Vulkan unavailable Vulkan 사용 불가 GPU via Metal unavailable Metal을 통한 GPU 사용 불가 GPU init failed GPU 초기화 실패 Default model: %1 기본 모델: %1 Measuring categorization (warm-up + %1 run(s))... 분류 측정(워밍업 + %1회 실행)... Measuring document analysis (warm-up + %1 run(s))... 문서 분석 측정(워밍업 + %1회 실행)... Categorization: %1 분류: %1 done 완료 failed 실패 Warm-up: %1 워밍업: %1 Init: %1 초기화: %1 Per-item (median of %1): %2 항목당(%1회 중앙값): %2 Per-item runs: %1 항목당 실행: %1 Details: %1 세부 정보: %1 Backend used: %1 사용한 백엔드: %1 Document analysis: %1 문서 분석: %1 Model failed to load: %1 모델을 불러오지 못했습니다: %1 optimal 최적 acceptable 수용 가능 a bit long 꽤 김 n/a 해당 없음 Result 결과 Categorization speed: unavailable 분류 속도: 사용할 수 없음 Document analysis speed: unavailable 문서 분석 속도: 사용할 수 없음 Categorization speed: %1 분류 속도: %1 Document analysis speed: %1 문서 분석 속도: %1 Image analysis speed: unavailable 이미지 분석 속도: 사용할 수 없음 Image analysis speed: %1 이미지 분석 속도: %1 Recommended Local LLM choice: %1 권장 로컬 LLM 선택: %1 You can toggle LLMs in Settings -> Select LLM 설정 -> LLM 선택에서 LLM을 전환할 수 있습니다 Compatibility Benchmark 호환성 벤치마크 Run a quick performance check to estimate how image analysis, document analysis, and file categorization will perform on your system. 이 시스템에서 이미지 분석, 문서 분석 및 파일 분류가 어떻게 수행될지 추정하기 위해 빠른 성능 확인을 실행합니다. It is recommended to quit any CPU- and GPU-intensive applications before running this test. 이 테스트를 실행하기 전에 CPU 및 GPU를 많이 사용하는 응용 프로그램을 종료하는 것이 권장됩니다. Run benchmark 벤치마크 실행 Do not auto-show this dialog again 이 대화 상자를 자동으로 다시 표시하지 않음 Stop Benchmark 벤치마크 중지 Close 닫기 No previous results yet. 이전 결과가 없습니다. Last run: %1 마지막 실행: %1 Previous results: 이전 결과: No downloaded LLM files detected. Download a categorization or visual model to run the benchmark. 다운로드된 LLM 파일이 없습니다. 벤치마크를 실행하려면 분류 또는 비주얼 모델을 다운로드하세요. Starting system compatibility check... 시스템 호환성 확인을 시작합니다... CPU threads detected: %1 CPU 스레드 감지됨: %1 GPU backend override: %1 GPU 백엔드 강제 설정: %1 Metal available: %1 Metal 사용 가능: %1 yes no 아니오 GPU memory allocation (Metal): %1 free / %2 total GPU 메모리 할당(Metal): %1 여유 / %2 전체 GPU memory allocation (Metal): unavailable GPU 메모리 할당(Metal): 사용할 수 없음 CUDA available: %1 CUDA 사용 가능: %1 CUDA memory (allocatable): %1 free / %2 total CUDA 메모리(할당 가능): %1 여유 / %2 전체 (device total: %1) (기기 총량: %1) GPU memory allocation (Vulkan): %1 free / %2 total GPU 메모리 할당(Vulkan): %1 여유 / %2 전체 GPU memory allocation (Vulkan): unavailable GPU 메모리 할당(Vulkan): 사용할 수 없음 Temporary directory setup failed; benchmark sample file creation may fail. 임시 디렉터리 설정에 실패했습니다. 벤치마크 샘플 파일 생성이 실패할 수 있습니다. No default models downloaded; skipping categorization and document checks. 기본 모델이 다운로드되지 않아 분류 및 문서 검사를 건너뜁니다. Default models detected: %1 기본 모델 감지됨: %1 Benchmark stopped. 벤치마크가 중지되었습니다. Running image analysis test... 이미지 분석 테스트 실행 중... unavailable 사용할 수 없음 Image analysis: skipped (%1) 이미지 분석: 건너뜀(%1) Image analysis: %1 이미지 분석: %1 Time: %1 시간: %1 GPU disabled by backend override 백엔드 강제 설정으로 GPU 비활성화됨 Backend used (image analysis): %1 사용한 백엔드(이미지 분석): %1 Benchmark failed: %1 벤치마크 실패: %1 [STOP] Benchmark will stop after the current step is processed. [STOP] 벤치마크가 현재 단계가 끝난 후 중지됩니다. Required Update Available 필수 업데이트 사용 가능 A required update is available. Please update to continue. If you choose to quit, the application will close. 필수 업데이트가 있습니다. 계속하려면 업데이트하세요. 종료를 선택하면 애플리케이션이 닫힙니다. Update Now 지금 업데이트 Quit 종료 Optional Update Available 선택적 업데이트 사용 가능 An optional update is available. Would you like to update now? 선택적 업데이트가 있습니다. 지금 업데이트하시겠습니까? Skip This Version 이 버전 건너뛰기 Cancel 취소 Downloading Update 업데이트 다운로드 중 Downloading the update installer... 업데이트 설치 프로그램을 다운로드하는 중... Failed to prepare the update installer. %1 업데이트 설치 프로그램을 준비하지 못했습니다. %1 Installer Ready 설치 프로그램 준비 완료 Quit the app and launch the installer to update 업데이트하려면 앱을 종료하고 설치 프로그램을 실행하세요 Quit and Launch Installer 종료 후 설치 프로그램 실행 The installer could not be launched. 설치 프로그램을 실행할 수 없습니다. No download target is available for this update. 이 업데이트에 사용할 다운로드 대상이 없습니다. Update Failed 업데이트 실패 Update manually 수동으로 업데이트 Edit whitelist 화이트리스트 편집 Name: 이름: Categories (comma separated): 카테고리(쉼표로 구분): Subcategories (comma separated): 하위 카테고리(쉼표로 구분): CUDA Toolkit Missing CUDA Toolkit 누락 A compatible NVIDIA GPU was detected, but the CUDA Toolkit is missing. CUDA is required for GPU acceleration in this application. Would you like to download and install it now? 호환되는 NVIDIA GPU가 감지되었지만 CUDA Toolkit이 없습니다. 이 애플리케이션에서 GPU 가속을 사용하려면 CUDA가 필요합니다. 지금 다운로드하여 설치하시겠습니까? Launch Error 실행 오류 Cannot enable both CUDA and Vulkan simultaneously. CUDA와 Vulkan을 동시에 활성화할 수 없습니다. Missing GGML Runtime GGML 런타임 누락 Could not locate the backend runtime DLLs. Tried: %1 %2 백엔드 런타임 DLL을 찾을 수 없습니다. 시도한 위치: %1 %2 Launch Failed 실행 실패 Failed to launch the main application executable: %1 메인 애플리케이션 실행 파일을 시작하지 못했습니다: %1 UiTranslator Folder: 폴더: Browse… 찾아보기… Use subcategories 하위 카테고리 사용 Create subcategory folders within each category. 각 카테고리 안에 하위 카테고리 폴더를 생성합니다. Categorization type 분류 유형 Choose how strict the category labels should be. 카테고리 레이블의 엄격함을 선택합니다. More refined 더 세분화 Favor detailed labels even if similar items vary. 유사한 항목 간 차이가 있더라도 자세한 레이블을 선호합니다. More consistent 더 일관적 Favor consistent labels across similar items. 유사한 항목에 일관된 레이블을 선호합니다. Use a whitelist 화이트리스트 사용 Restrict categories and subcategories to the selected whitelist. 선택한 화이트리스트로 카테고리와 하위 카테고리를 제한합니다. Select the whitelist used for this run. 이번 실행에 사용할 화이트리스트를 선택합니다. Categorize files 파일 분류 Include files in the categorization pass. 분류 단계에 파일을 포함합니다. Categorize folders 폴더 분류 Include directories in the categorization pass. 분류 단계에 폴더를 포함합니다. Scan subfolders 하위 폴더 스캔 Scan files inside subfolders and treat them as part of the main folder. 하위 폴더의 파일을 스캔하고 기본 폴더에 있는 것처럼 처리합니다. Analyze picture files by content (can be slow) 이미지 파일을 내용으로 분석(느릴 수 있음) Run the visual LLM on supported picture files. 지원되는 이미지 파일에 비전 LLM을 실행합니다. Process picture files only (ignore any other files) 이미지 파일만 처리(다른 파일 무시) Ignore non-picture files in this run. 이번 실행에서 이미지가 아닌 파일은 무시합니다. Add image creation date (if available) to category name 이미지 생성 날짜(가능한 경우)를 카테고리 이름에 추가 Append the image creation date from metadata to the category label. 메타데이터의 이미지 생성 날짜를 카테고리 라벨에 추가합니다. Add photo date and place to filename (if available) 사진 날짜와 장소를 파일명에 추가(가능한 경우) Date comes from photo EXIF metadata. Place names are resolved online from GPS coordinates, so network access is required for place prefixes. 날짜는 사진 EXIF 메타데이터에서 가져옵니다. 장소 이름은 GPS 좌표를 바탕으로 온라인에서 확인되므로 장소 접두어에는 네트워크 연결이 필요합니다. Add audio/video metadata to file name (if available) 오디오/비디오 메타데이터를 파일 이름에 추가(가능한 경우) Use embedded media tags (for example year, artist, album, title) to build suggested audio/video filenames. 내장 미디어 태그(예: 연도, 아티스트, 앨범, 제목)를 사용해 오디오/비디오 추천 파일명을 만듭니다. Offer to rename picture files 이미지 파일 이름 바꾸기 제안 Show suggested filenames for picture files. 이미지 파일에 대한 추천 파일명을 표시합니다. Do not categorize picture files (only rename) 이미지 파일 분류 안 함(이름만 변경) Skip categorization for picture files and only rename them. 이미지 파일의 분류를 건너뛰고 이름만 변경합니다. Show or hide picture analysis options 이미지 분석 옵션 표시/숨기기 Analyze document files by content 문서 파일을 내용으로 분석 Summarize document contents with the selected LLM. 선택한 LLM으로 문서 내용을 요약합니다. Process document files only (ignore any other files) 문서 파일만 처리(다른 파일 무시) Ignore non-document files in this run. 이번 실행에서 문서가 아닌 파일은 무시합니다. Offer to rename document files 문서 파일 이름 바꾸기 제안 Show suggested filenames for document files. 문서 파일에 대한 추천 파일명을 표시합니다. Do not categorize document files (only rename) 문서 파일 분류 안 함(이름만 변경) Skip categorization for document files and only rename them. 문서 파일의 분류를 건너뛰고 이름만 변경합니다. Add document creation date (if available) to category name 문서 생성 날짜(가능한 경우)를 카테고리 이름에 추가 Append the document creation date from metadata to the category label. 메타데이터의 문서 생성 날짜를 카테고리 라벨에 추가합니다. Show or hide document analysis options 문서 분석 옵션 표시/숨기기 Stop analyzing 분석 중지 Analyze folder 폴더 분석 File 파일 Type 유형 Category 카테고리 Subcategory 하위 카테고리 Status 상태 Directory 폴더 Ready 준비됨 &Help &도움말 File Explorer 파일 탐색기 Cancelling analysis… 분석 취소 중… Analyzing… 분석 중… WhitelistManagerDialog Category whitelists 카테고리 화이트리스트 Add 추가 Edit 편집 Remove 제거 Cannot remove 제거할 수 없음 The default list cannot be removed. 기본 목록은 제거할 수 없습니다. ================================================ FILE: app/resources/i18n/aifilesorter_nl.ts ================================================ CategorizationDialog Tip: Click %1 cells to rename them. Tip: klik op %1-cellen om ze te hernoemen. No items selected Geen items geselecteerd Highlight one or more rows to select them for processing. Markeer een of meer rijen om ze voor verwerking te selecteren. Bulk edit unavailable Bulkbewerking niet beschikbaar Bulk editing categories is unavailable while picture rename-only mode is active. Bulkbewerking van categorieën is niet beschikbaar zolang de modus Alleen afbeeldingen hernoemen actief is. Highlight one or more rows to edit their categories. Markeer een of meer rijen om hun categorieën te bewerken. Preview Voorbeeld Review and Confirm Beoordelen en bevestigen Select all Alles selecteren Select highlighted Gemarkeerde selecteren Edit selected... Geselecteerde bewerken... Create subcategory folders Subcategoriemappen maken Dry run (preview only, do not move files) Proefrun (alleen voorbeeld, verplaats geen bestanden) Do not categorize picture files (only rename) Afbeeldingsbestanden niet categoriseren (alleen hernoemen) Do not categorize document files (only rename) Documentbestanden niet categoriseren (alleen hernoemen) Confirm and Process Bevestigen en verwerken Continue Later Later doorgaan Undo this change Deze wijziging ongedaan maken Close Sluiten Mark highlighted rows for processing (Ctrl+Space). Markeer gemarkeerde rijen voor verwerking (Ctrl+Spatie). Apply category/subcategory values to highlighted rows. Pas categorie-/subcategoriewaarden toe op de gemarkeerde rijen. Process Verwerken File Bestand Type Type Suggested filename Voorgestelde bestandsnaam Category Categorie Subcategory Subcategorie Status Status Planned destination Geplande bestemming Moved Verplaatst Renamed Hernoemd Renamed & Moved Hernoemd en verplaatst Skipped Overgeslagen Not selected Niet geselecteerd CategorizationProgressDialog [STOP] Analysis will stop after the current item is processed. [STOP] Analyse stopt na het huidige item. Image analysis Beeldanalyse Document analysis Documentanalyse Categorization Categorisatie Directory Map Image Afbeelding Document Document File Bestand Type Type Stage %1: %2 Fase %1: %2 Pending In afwachting In progress Bezig Complete Voltooid Processed 0/0 | In progress: 0 | Pending: 0 Verwerkt 0/0 | Bezig: 0 | In afwachting: 0 Processed %1/%2 | In progress: %3 | Pending: %4 Verwerkt %1/%2 | Bezig: %3 | In afwachting: %4 Analyzing Files Bestanden analyseren Stop Analysis Analyse stoppen Activity log Activiteitenlogboek CustomApiDialog Custom OpenAI-compatible API Aangepaste OpenAI-compatibele API e.g. http://localhost:1234/v1 bijv. http://localhost:1234/v1 e.g. llama-3.1, gpt-4o-mini bijv. llama-3.1, gpt-4o-mini Show Tonen Display name Weergavenaam Description Beschrijving Base URL or endpoint Basis-URL of eindpunt Model Model API key (optional) API-sleutel (optioneel) Enter a base URL (e.g. http://localhost:1234/v1) or a full /chat/completions endpoint. Voer een basis-URL in (bijv. http://localhost:1234/v1) of een volledig /chat/completions-eindpunt. CustomLLMDialog Custom local LLM Aangepast lokaal LLM Browse… Bladeren… Display name Weergavenaam Description Beschrijving Model file (.gguf) Modelbestand (.gguf) Select .gguf model .gguf-model selecteren GGUF models (*.gguf);;All files (*.*) GGUF-modellen (*.gguf);;Alle bestanden (*.*) DryRunPreviewDialog Dry run preview Proefrun-voorbeeld From Van To Naar Close Sluiten LLMSelectionDialog Choose LLM Mode LLM-modus kiezen Select LLM Mode LLM-modus selecteren Larger local model. Slower on CPU, but performs much better with GPU acceleration. Supports: Nvidia (CUDA), Apple (Metal), CPU. Groter lokaal model. Langzamer op CPU, maar presteert veel beter met GPU-versnelling. Ondersteunt: Nvidia (CUDA), Apple (Metal), CPU. Recommended Aanbevolen Smaller local model that works quickly even on CPUs. Good for lightweight local use. Kleiner lokaal model dat ook op CPU's snel werkt. Goed voor licht lokaal gebruik. Legacy model kept for existing downloads. Verouderd model behouden voor bestaande downloads. Gemini (Google AI Studio API key) Gemini (Google AI Studio API-sleutel) Use Google's Gemini models with your AI Studio API key (internet required). Gebruik Google's Gemini-modellen met uw AI Studio-API-sleutel (internet vereist). AIza... AIza... Show Tonen Gemini API key Gemini-API-sleutel e.g. gemini-2.5-flash-lite, gemini-2.5-flash, gemini-2.5-pro bijv. gemini-2.5-flash-lite, gemini-2.5-flash, gemini-2.5-pro Model Model Your key is stored locally in the config file for this device. Uw sleutel wordt lokaal opgeslagen in het configuratiebestand van dit apparaat. <a href="https://aistudio.google.com/app/apikey">Get a Gemini API key</a> <a href="https://aistudio.google.com/app/apikey">Een Gemini-API-sleutel ophalen</a> ChatGPT (OpenAI API key) ChatGPT (OpenAI API-sleutel) Use your own OpenAI API key to access ChatGPT models (internet required). Gebruik uw eigen OpenAI-API-sleutel om toegang te krijgen tot ChatGPT-modellen (internet vereist). sk-... sk-... OpenAI API key OpenAI-API-sleutel e.g. gpt-4o-mini, gpt-4.1, o3-mini bijv. gpt-4o-mini, gpt-4.1, o3-mini <a href="https://platform.openai.com/api-keys">Get an OpenAI API key</a> <a href="https://platform.openai.com/api-keys">Een OpenAI-API-sleutel ophalen</a> Custom OpenAI-compatible API (advanced) Aangepaste OpenAI-compatibele API (geavanceerd) Use OpenAI-compatible endpoints such as LM Studio or Ollama (local or remote). Gebruik OpenAI-compatibele eindpunten zoals LM Studio of Ollama (lokaal of extern). Add… Toevoegen… Edit… Bewerken… Delete Verwijderen Custom local LLM (gguf) Aangepast lokaal LLM (gguf) Downloads Downloads Download Downloaden Image analysis models (LLaVA) Beeldanalysemodellen (LLaVA) Download the visual LLM files required for image analysis. Download de visuele LLM-bestanden die nodig zijn voor beeldanalyse. LLaVA 1.6 Mistral 7B (text model) LLaVA 1.6 Mistral 7B (tekstmodel) LLaVA mmproj (vision encoder) LLaVA mmproj (visie-encoder) Choose or add a custom model. Kies of voeg een aangepast model toe. Custom model selected. Aangepast model geselecteerd. Selection ready. Selectie gereed. Choose or add a custom API endpoint. Kies of voeg een aangepast API-eindpunt toe. Custom API selected. Aangepaste API geselecteerd. ChatGPT will use your API key and model. ChatGPT gebruikt uw API-sleutel en model. Enter your OpenAI API key and model to continue. Voer uw OpenAI-API-sleutel en model in om door te gaan. Gemini will use your API key and model. Gemini gebruikt uw API-sleutel en model. Enter your Gemini API key and model to continue. Voer uw Gemini-API-sleutel en model in om door te gaan. Model ready. Model gereed. Resume download Download hervatten Partial download detected. You can resume. Gedeeltelijke download gedetecteerd. U kunt hervatten. Download required. Download vereist. Unsupported LLM selection. Niet-ondersteunde LLM-selectie. Missing download URL environment variable (%1). Ontbrekende download-URL-omgevingsvariabele (%1). Delete downloaded model? Gedownload model verwijderen? Delete the downloaded model %1? Gedownload model %1 verwijderen? Failed to delete downloaded model. Kan gedownloade model niet verwijderen. Deleted downloaded model. Gedownload model verwijderd. No downloaded model found to delete. Geen gedownload model gevonden om te verwijderen. Remote URL Externe URL Local path Lokaal pad File size Bestandsgrootte File size: unknown Bestandsgrootte: onbekend Delete custom model Aangepast model verwijderen Remove '%1' from your custom LLMs? This does not delete the file on disk. '%1' uit uw aangepaste LLM's verwijderen? Dit verwijdert het bestand niet van de schijf. Delete custom API Aangepaste API verwijderen Remove '%1' from your custom API list? This does not affect the server. '%1' uit uw lijst met aangepaste API's verwijderen? Dit heeft geen invloed op de server. Missing download URL environment variable. Ontbrekende download-URL-omgevingsvariabele. Downloading… Bezig met downloaden… Download complete. Download voltooid. Download cancelled. Download geannuleerd. Download error: %1 Downloadfout: %1 MainApp File Explorer Bestandsverkenner Select Directory Map selecteren Loaded folder %1 Map %1 geladen Analysis cancelled Analyse geannuleerd Folder selected: %1 Map geselecteerd: %1 More consistent Meer consistent More refined Meer verfijnd Recategorize folder? Map opnieuw categoriseren? This folder was categorized using the %1 mode. Do you want to recategorize it now using the %2 mode? Deze map is gecategoriseerd met de modus %1. Wilt u deze nu opnieuw categoriseren met de modus %2? Recategorize Opnieuw categoriseren Keep existing Bestaande behouden Failed to reset cached categorization for this folder. Kon de in cache opgeslagen categorisatie voor deze map niet resetten. Download required Download vereist Image analysis requires visual LLM files. Download them now? Beeldanalyse vereist visuele LLM-bestanden. Nu downloaden? OK OK Stop analyzing Analyse stoppen Analyzing… Bezig met analyseren… Analyze folder Map analyseren Ready Gereed Undo last run Laatste run ongedaan maken This will attempt to move files back to their original locations based on the last run. Plan file: %1 Dit probeert bestanden terug te zetten naar hun oorspronkelijke locaties op basis van de laatste uitvoering. Planbestand: %1 Restored %1 file(s). Skipped %2. %1 bestand(en) hersteld. %2 overgeslagen. Undo complete Ongedaan maken voltooid Thank you for using AI File Sorter! You have categorized %1 files thus far. I, the author, really hope this app was useful for you. Bedankt voor het gebruiken van AI File Sorter! U heeft tot nu toe %1 bestanden gecategoriseerd. Ik, de auteur, hoop echt dat deze app nuttig voor u was. AI File Sorter takes hundreds of hours of development, feature work, support replies, and ongoing costs such as servers and remote-model infrastructure. If the app saves you time or brings value, please consider supporting it so it can keep improving. AI File Sorter kost honderden uren ontwikkeling, feature-werk, supportreacties en doorlopende kosten zoals servers en infrastructuur voor externe modellen. Als de app u tijd bespaart of waarde biedt, overweeg dan om te ondersteunen zodat hij kan blijven verbeteren. Already donated? Click "I have already donated" to enter your donation code and permanently disable this reminder. Al gedoneerd? Klik op "Ik heb al gedoneerd" om je donatiecode in te voeren en deze herinnering permanent uit te schakelen. Donate to permanently hide the donation dialog Doneer om het donatiedialoogvenster permanent te verbergen I'm not yet sure Ik weet het nog niet I have already donated Ik heb al gedoneerd Donation code Donatiecode Enter the donation code generated after your donation. A valid code will permanently hide the donation dialog. Voer de donatiecode in die na uw donatie is gegenereerd. Een geldige code verbergt het donatiedialoogvenster permanent. Invalid donation code Ongeldige donatiecode The donation code is invalid. Please try again or press Cancel. De donatiecode is ongeldig. Probeer het opnieuw of klik op Annuleren. Open donation page Donatiepagina openen Could not open your browser automatically. Please open this link manually: %1 Kon je browser niet automatisch openen. Open deze link handmatig: %1 Directory Map File Bestand [ARCHIVE] Already categorized highlights: [ARCHIEF] Reeds gecategoriseerde items: [DONE] No files to categorize. [KLAAR] Geen bestanden om te categoriseren. [QUEUE] Items waiting for categorization: [WACHTRIJ] Items in afwachting van categorisatie: [SCAN] Exploring %1 [SCAN] Verkennen van %1 [PROCESS] Letting the AI do its magic... [VERWERKING] De AI doet zijn magie... [VISION] Decoding image batch %1/%2 (%3%) [VISIE] Afbeeldingsbatch %1/%2 decoderen (%3%) Switch image analysis to CPU? Beeldanalyse overschakelen naar de CPU? Image analysis ran out of GPU memory. De beeldanalyse heeft geen GPU-geheugen meer. Retry on CPU instead? Cancel will skip visual analysis and fall back to filename-based categorization. Opnieuw proberen op de CPU? Annuleren slaat de visuele analyse over en valt terug op categorisering op basis van bestandsnamen. [VISION-ERROR] %1 (%2) [VISIE-FOUT] %1 (%2) [VISION] Switching visual analysis to CPU. [VISION] Visuele analyse wordt overgeschakeld naar de CPU. [VISION-ERROR] %1 [VISION-ERROR] %1 [VISION] Visual analysis disabled; falling back to filenames. [VISION] Visuele analyse uitgeschakeld; teruggevallen op bestandsnamen. [VISION] Using cached suggestion for %1 [VISIE] Gebruik cachesuggestie voor %1 [VISION] Analyzing %1 [VISIE] Analyseren van %1 [VISION] GPU memory issue detected. Switching to CPU. [VISION] Probleem met GPU-geheugen gedetecteerd. Overschakelen naar CPU. [VISION] Visual analysis disabled for remaining images. [VISION] Visuele analyse uitgeschakeld voor de resterende afbeeldingen. [DOC-ERROR] %1 (%2) [DOC-FOUT] %1 (%2) [DOC] Using cached suggestion for %1 [DOC] Gebruik cachesuggestie voor %1 [DOC] Analyzing %1 [DOC] Analyseren van %1 [SORT] %1 (%2) [SORTEREN] %1 (%2) Cancelling analysis… Analyse wordt geannuleerd… Switch local AI to CPU? Lokale AI overschakelen naar de CPU? The local model encountered a GPU error or ran out of memory. Het lokale model kreeg een GPU-fout of had onvoldoende geheugen. Retry on CPU instead? Cancel will stop this analysis. Opnieuw proberen op de CPU? Annuleren stopt deze analyse. [WARN] GPU fallback to CPU declined. Cancelling analysis. [WARN] Terugval van GPU naar CPU geweigerd. Analyse wordt geannuleerd. [WARN] GPU acceleration failed to initialize. Continuing on CPU (slower). [WAARSCHUWING] GPU-versnelling kon niet worden geïnitialiseerd. Doorgaan op CPU (langzamer). [WARN] %1 will be re-categorized: %2 [WAARSCHUWING] %1 wordt opnieuw gecategoriseerd: %2 QObject Edit selected items Geselecteerde items bewerken Leave empty to keep existing Leeg laten om bestaande waarden te behouden Category Categorie Subcategory Subcategorie About %1 Over %1 About Over Credits Credits About the AGPL License Over de AGPL-licentie AI File Sorter is distributed under the GNU Affero General Public License v3.0.<br><br>You can access the full source code at <a href="https://github.com/hyperfield/ai-file-sorter">github.com/hyperfield/ai-file-sorter</a>.<br><br>A full copy of the license is provided with this application and available online at <a href="https://www.gnu.org/licenses/agpl-3.0.html">gnu.org</a>. AI File Sorter wordt verspreid onder de GNU Affero General Public License v3.0.<br><br>U kunt de volledige broncode vinden op <a href="https://github.com/hyperfield/ai-file-sorter">github.com/hyperfield/ai-file-sorter</a>.<br><br>Een volledige kopie van de licentie wordt met deze applicatie meegeleverd en is online beschikbaar op <a href="https://www.gnu.org/licenses/agpl-3.0.html">gnu.org</a>. CPU CPU Metal Metal CUDA CUDA Vulkan Vulkan Metal (auto) Metal (automatisch) Vulkan (auto) Vulkan (automatisch) %1 (auto) %1 (automatisch) Auto Automatisch CPU (%1) CPU (%1) GPU (target: %1) GPU (doel: %1) GPU via Vulkan unavailable GPU via Vulkan niet beschikbaar GPU via CUDA unavailable GPU via CUDA niet beschikbaar Vulkan unavailable Vulkan niet beschikbaar GPU via Metal unavailable GPU via Metal niet beschikbaar GPU init failed GPU-initialisatie mislukt Default model: %1 Standaardmodel: %1 Measuring categorization (warm-up + %1 run(s))... Categorisatie meten (opwarming + %1 uitvoering(en))... Measuring document analysis (warm-up + %1 run(s))... Documentanalyse meten (opwarming + %1 uitvoering(en))... Categorization: %1 Categorisatie: %1 done gereed failed mislukt Warm-up: %1 Opwarming: %1 Init: %1 Initialisatie: %1 Per-item (median of %1): %2 Per item (mediaan van %1): %2 Per-item runs: %1 Uitvoeringen per item: %1 Details: %1 Details: %1 Backend used: %1 Backend gebruikt: %1 Document analysis: %1 Documentanalyse: %1 Model failed to load: %1 Model kon niet worden geladen: %1 optimal optimaal acceptable acceptabel a bit long behoorlijk lang n/a n.v.t. Result Resultaat Categorization speed: unavailable Categorisatiesnelheid: niet beschikbaar Document analysis speed: unavailable Documentanalysesnelheid: niet beschikbaar Categorization speed: %1 Categorisatiesnelheid: %1 Document analysis speed: %1 Documentanalysesnelheid: %1 Image analysis speed: unavailable Beeldanalysesnelheid: niet beschikbaar Image analysis speed: %1 Beeldanalysesnelheid: %1 Recommended Local LLM choice: %1 Aanbevolen lokale LLM-keuze: %1 You can toggle LLMs in Settings -> Select LLM Je kunt LLM's wisselen via Instellingen -> LLM selecteren Compatibility Benchmark Compatibiliteitsbenchmark Run a quick performance check to estimate how image analysis, document analysis, and file categorization will perform on your system. Voer een snelle prestatiecontrole uit om te schatten hoe beeldanalyse, documentanalyse en bestandscategorisatie op dit systeem zullen presteren. It is recommended to quit any CPU- and GPU-intensive applications before running this test. Het wordt aanbevolen om vóór het uitvoeren van deze test alle CPU- en GPU-intensieve toepassingen af te sluiten. Run benchmark Benchmark uitvoeren Do not auto-show this dialog again Dit dialoogvenster niet automatisch opnieuw tonen Stop Benchmark Benchmark stoppen Close Sluiten No previous results yet. Nog geen eerdere resultaten. Last run: %1 Laatste uitvoering: %1 Previous results: Vorige resultaten: No downloaded LLM files detected. Download a categorization or visual model to run the benchmark. Geen gedownloade LLM-bestanden gevonden. Download een categorisatie- of visueel model om de benchmark uit te voeren. Starting system compatibility check... Systeemcompatibiliteitscontrole starten... CPU threads detected: %1 CPU-threads gedetecteerd: %1 GPU backend override: %1 GPU-backend geforceerd: %1 Metal available: %1 Metal beschikbaar: %1 yes ja no nee GPU memory allocation (Metal): %1 free / %2 total GPU-geheugentoewijzing (Metal): %1 vrij / %2 totaal GPU memory allocation (Metal): unavailable GPU-geheugentoewijzing (Metal): niet beschikbaar CUDA available: %1 CUDA beschikbaar: %1 CUDA memory (allocatable): %1 free / %2 total CUDA-geheugen (toewijsbaar): %1 vrij / %2 totaal (device total: %1) (apparaat totaal: %1) GPU memory allocation (Vulkan): %1 free / %2 total GPU-geheugentoewijzing (Vulkan): %1 vrij / %2 totaal GPU memory allocation (Vulkan): unavailable GPU-geheugentoewijzing (Vulkan): niet beschikbaar Temporary directory setup failed; benchmark sample file creation may fail. Het instellen van de tijdelijke map is mislukt; het aanmaken van het benchmarkvoorbeeldbestand kan mislukken. No default models downloaded; skipping categorization and document checks. Geen standaardmodellen gedownload; categorisatie en documentcontroles worden overgeslagen. Default models detected: %1 Standaardmodellen gedetecteerd: %1 Benchmark stopped. Benchmark gestopt. Running image analysis test... Beeldanalysetest uitvoeren... unavailable niet beschikbaar Image analysis: skipped (%1) Beeldanalyse: overgeslagen (%1) Image analysis: %1 Beeldanalyse: %1 Time: %1 Tijd: %1 GPU disabled by backend override GPU uitgeschakeld door backend-override Backend used (image analysis): %1 Backend gebruikt (beeldanalyse): %1 Benchmark failed: %1 Benchmark mislukt: %1 [STOP] Benchmark will stop after the current step is processed. [STOP] De benchmark stopt na de huidige stap. Error Fout Local LLM (%1) Lokaal LLM (%1) Local LLM Lokaal LLM Support %1 Ondersteun %1 Required Update Available Verplichte update beschikbaar A required update is available. Please update to continue. If you choose to quit, the application will close. Er is een verplichte update beschikbaar. Werk bij om door te gaan. Als u afsluiten kiest, wordt de toepassing gesloten. Update Now Nu bijwerken Quit Afsluiten Optional Update Available Optionele update beschikbaar An optional update is available. Would you like to update now? Er is een optionele update beschikbaar. Wilt u nu bijwerken? Skip This Version Deze versie overslaan Cancel Annuleren Downloading Update Update downloaden Downloading the update installer... Het installatieprogramma van de update wordt gedownload... Failed to prepare the update installer. %1 Het installatieprogramma van de update kon niet worden voorbereid. %1 Installer Ready Installatieprogramma gereed Quit the app and launch the installer to update Sluit de app af en start het installatieprogramma om bij te werken Quit and Launch Installer Afsluiten en installatieprogramma starten The installer could not be launched. Het installatieprogramma kon niet worden gestart. No download target is available for this update. Er is geen downloaddoel beschikbaar voor deze update. Update Failed Bijwerken mislukt Update manually Handmatig bijwerken Edit whitelist Whitelist bewerken Name: Naam: Categories (comma separated): Categorieën (door komma's gescheiden): Subcategories (comma separated): Subcategorieën (door komma's gescheiden): CUDA Toolkit Missing CUDA Toolkit ontbreekt A compatible NVIDIA GPU was detected, but the CUDA Toolkit is missing. CUDA is required for GPU acceleration in this application. Would you like to download and install it now? Er is een compatibele NVIDIA-GPU gedetecteerd, maar de CUDA Toolkit ontbreekt. CUDA is vereist voor GPU-versnelling in deze toepassing. Wilt u het nu downloaden en installeren? Launch Error Startfout Cannot enable both CUDA and Vulkan simultaneously. CUDA en Vulkan kunnen niet tegelijkertijd worden ingeschakeld. Missing GGML Runtime GGML-runtime ontbreekt Could not locate the backend runtime DLLs. Tried: %1 %2 Kon de runtime-DLL's van de backend niet vinden. Geprobeerd: %1 %2 Launch Failed Start mislukt Failed to launch the main application executable: %1 Kon het hoofdprogramma niet starten: %1 UiTranslator Folder: Map: Browse… Bladeren… Use subcategories Subcategorieën gebruiken Create subcategory folders within each category. Subcategorie-mappen binnen elke categorie maken. Categorization type Categorisatietype Choose how strict the category labels should be. Kies hoe strikt de categorielabels moeten zijn. More refined Meer verfijnd Favor detailed labels even if similar items vary. Geef de voorkeur aan gedetailleerde labels, ook als vergelijkbare items verschillen. More consistent Meer consistent Favor consistent labels across similar items. Geef de voorkeur aan consistente labels voor vergelijkbare items. Use a whitelist Whitelist gebruiken Restrict categories and subcategories to the selected whitelist. Beperk categorieën en subcategorieën tot de geselecteerde whitelist. Select the whitelist used for this run. Selecteer de whitelist die voor deze run wordt gebruikt. Categorize files Bestanden categoriseren Include files in the categorization pass. Neem bestanden op in de categorisatieronde. Categorize folders Mappen categoriseren Include directories in the categorization pass. Neem mappen op in de categorisatieronde. Scan subfolders Submappen scannen Scan files inside subfolders and treat them as part of the main folder. Bestanden in submappen scannen en behandelen alsof ze in de hoofdmap staan. Analyze picture files by content (can be slow) Afbeeldingsbestanden op inhoud analyseren (kan traag zijn) Run the visual LLM on supported picture files. Voer de visuele LLM uit op ondersteunde afbeeldingsbestanden. Process picture files only (ignore any other files) Alleen afbeeldingsbestanden verwerken (alle andere bestanden negeren) Ignore non-picture files in this run. Niet-afbeeldingsbestanden in deze run negeren. Add image creation date (if available) to category name Voeg de aanmaakdatum van de afbeelding (indien beschikbaar) toe aan de categorienaam Append the image creation date from metadata to the category label. Voeg de aanmaakdatum van de afbeelding uit metadata toe aan het categorielabel. Add photo date and place to filename (if available) Voeg fotodatum en plaats toe aan bestandsnaam (indien beschikbaar) Date comes from photo EXIF metadata. Place names are resolved online from GPS coordinates, so network access is required for place prefixes. De datum komt uit EXIF-metadata van de foto. Plaatsnamen worden online uit GPS-coördinaten bepaald, dus netwerktoegang is vereist voor plaatsvoorvoegsels. Add audio/video metadata to file name (if available) Audio-/videometadata toevoegen aan bestandsnaam (indien beschikbaar) Use embedded media tags (for example year, artist, album, title) to build suggested audio/video filenames. Gebruik ingesloten mediatags (bijv. jaar, artiest, album, titel) om voorgestelde audio-/videobestandsnamen te maken. Offer to rename picture files Aanbieden om afbeeldingsbestanden te hernoemen Show suggested filenames for picture files. Toon voorgestelde bestandsnamen voor afbeeldingsbestanden. Do not categorize picture files (only rename) Afbeeldingsbestanden niet categoriseren (alleen hernoemen) Skip categorization for picture files and only rename them. Categorisatie voor afbeeldingsbestanden overslaan en alleen hernoemen. Show or hide picture analysis options Opties voor afbeeldingsanalyse tonen of verbergen Analyze document files by content Documentbestanden op inhoud analyseren Summarize document contents with the selected LLM. Documentinhoud samenvatten met het geselecteerde LLM. Process document files only (ignore any other files) Alleen documentbestanden verwerken (alle andere bestanden negeren) Ignore non-document files in this run. Niet-documentbestanden in deze run negeren. Offer to rename document files Aanbieden om documentbestanden te hernoemen Show suggested filenames for document files. Toon voorgestelde bestandsnamen voor documentbestanden. Do not categorize document files (only rename) Documentbestanden niet categoriseren (alleen hernoemen) Skip categorization for document files and only rename them. Categorisatie voor documentbestanden overslaan en alleen hernoemen. Add document creation date (if available) to category name Voeg de aanmaakdatum van het document (indien beschikbaar) toe aan de categorienaam Append the document creation date from metadata to the category label. Voeg de aanmaakdatum van het document uit metadata toe aan het categorielabel. Show or hide document analysis options Opties voor documentanalyse tonen of verbergen Stop analyzing Analyse stoppen Analyze folder Map analyseren File Bestand Type Type Category Categorie Subcategory Subcategorie Status Status Directory Map Ready Gereed &Help &Help File Explorer Bestandsverkenner Cancelling analysis… Analyse wordt geannuleerd… Analyzing… Bezig met analyseren… WhitelistManagerDialog Category whitelists Categorie-whitelists Add Toevoegen Edit Bewerken Remove Verwijderen Cannot remove Kan niet worden verwijderd The default list cannot be removed. De standaardlijst kan niet worden verwijderd. ================================================ FILE: app/resources/i18n/aifilesorter_tr.ts ================================================ CategorizationDialog Tip: Click %1 cells to rename them. İpucu: Yeniden adlandırmak için %1 hücrelerine tıklayın. No items selected Hiç öğe seçilmedi Highlight one or more rows to select them for processing. İşleme için seçmek üzere bir veya daha fazla satırı vurgulayın. Bulk edit unavailable Toplu düzenleme kullanılamıyor Bulk editing categories is unavailable while picture rename-only mode is active. Resimlerde yalnızca yeniden adlandırma modu etkinken kategorilerin toplu düzenlenmesi kullanılamaz. Highlight one or more rows to edit their categories. Kategorilerini düzenlemek için bir veya daha fazla satırı vurgulayın. Preview Önizleme Review and Confirm Gözden geçir ve onayla Select all Tümünü seç Select highlighted Vurgulananları seç Edit selected... Seçilenleri düzenle... Create subcategory folders Alt kategori klasörleri oluştur Dry run (preview only, do not move files) Deneme çalıştırma (yalnızca önizleme, dosyaları taşıma) Do not categorize picture files (only rename) Resim dosyalarını kategorize etme (yalnızca yeniden adlandır) Do not categorize document files (only rename) Belge dosyalarını kategorize etme (yalnızca yeniden adlandır) Confirm and Process Onayla ve işle Continue Later Daha sonra devam et Undo this change Bu değişikliği geri al Close Kapat Mark highlighted rows for processing (Ctrl+Space). Vurgulanan satırları işleme için işaretleyin (Ctrl+Boşluk). Apply category/subcategory values to highlighted rows. Kategori/alt kategori değerlerini vurgulanan satırlara uygulayın. Process İşle File Dosya Type Tür Suggested filename Önerilen dosya adı Category Kategori Subcategory Alt kategori Status Durum Planned destination Planlanan hedef Moved Taşındı Renamed Yeniden adlandırıldı Renamed & Moved Yeniden adlandırıldı ve taşındı Skipped Atlandı Not selected Seçilmedi CategorizationProgressDialog [STOP] Analysis will stop after the current item is processed. [DUR] Analiz, geçerli öğe işlendiğinde duracaktır. Image analysis Görüntü analizi Document analysis Belge analizi Categorization Kategorizasyon Directory Klasör Image Görsel Document Belge File Dosya Type Tür Stage %1: %2 Aşama %1: %2 Pending Beklemede In progress Devam ediyor Complete Tamamlandı Processed 0/0 | In progress: 0 | Pending: 0 İşlenen 0/0 | Devam eden: 0 | Bekleyen: 0 Processed %1/%2 | In progress: %3 | Pending: %4 İşlenen %1/%2 | Devam eden: %3 | Bekleyen: %4 Analyzing Files Dosyalar analiz ediliyor Stop Analysis Analizi durdur Activity log Etkinlik günlüğü CustomApiDialog Custom OpenAI-compatible API Özel OpenAI uyumlu API e.g. http://localhost:1234/v1 ör. http://localhost:1234/v1 e.g. llama-3.1, gpt-4o-mini ör. llama-3.1, gpt-4o-mini Show Göster Display name Görünen ad Description Açıklama Base URL or endpoint Temel URL veya uç nokta Model Model API key (optional) API anahtarı (isteğe bağlı) Enter a base URL (e.g. http://localhost:1234/v1) or a full /chat/completions endpoint. Bir temel URL girin (ör. http://localhost:1234/v1) ya da tam bir /chat/completions uç noktası girin. CustomLLMDialog Custom local LLM Özel yerel LLM Browse… Gözat… Display name Görünen ad Description Açıklama Model file (.gguf) Model dosyası (.gguf) Select .gguf model .gguf modeli seç GGUF models (*.gguf);;All files (*.*) GGUF modelleri (*.gguf);;Tüm dosyalar (*.*) DryRunPreviewDialog Dry run preview Deneme çalıştırma önizlemesi From Kaynak To Hedef Close Kapat LLMSelectionDialog Choose LLM Mode LLM modunu seç Select LLM Mode LLM modunu seç Larger local model. Slower on CPU, but performs much better with GPU acceleration. Supports: Nvidia (CUDA), Apple (Metal), CPU. Daha büyük yerel model. CPU'da daha yavaştır, ancak GPU hızlandırmasıyla çok daha iyi performans gösterir. Destekler: Nvidia (CUDA), Apple (Metal), CPU. Recommended Önerilen Smaller local model that works quickly even on CPUs. Good for lightweight local use. CPU'larda bile hızlı çalışan daha küçük yerel model. Hafif yerel kullanım için uygundur. Legacy model kept for existing downloads. Eski model, mevcut indirmeler için korunur. Gemini (Google AI Studio API key) Gemini (Google AI Studio API anahtarı) Use Google's Gemini models with your AI Studio API key (internet required). Google'ın Gemini modellerini AI Studio API anahtarınızla kullanın (internet gerekir). AIza... AIza... Show Göster Gemini API key Gemini API anahtarı e.g. gemini-2.5-flash-lite, gemini-2.5-flash, gemini-2.5-pro ör. gemini-2.5-flash-lite, gemini-2.5-flash, gemini-2.5-pro Model Model Your key is stored locally in the config file for this device. Anahtarınız bu cihazdaki yapılandırma dosyasında yerel olarak saklanır. <a href="https://aistudio.google.com/app/apikey">Get a Gemini API key</a> <a href="https://aistudio.google.com/app/apikey">Gemini API anahtarı alın</a> ChatGPT (OpenAI API key) ChatGPT (OpenAI API anahtarı) Use your own OpenAI API key to access ChatGPT models (internet required). ChatGPT modellerine erişmek için kendi OpenAI API anahtarınızı kullanın (internet gerekir). sk-... sk-... OpenAI API key OpenAI API anahtarı e.g. gpt-4o-mini, gpt-4.1, o3-mini ör. gpt-4o-mini, gpt-4.1, o3-mini <a href="https://platform.openai.com/api-keys">Get an OpenAI API key</a> <a href="https://platform.openai.com/api-keys">OpenAI API anahtarı alın</a> Custom OpenAI-compatible API (advanced) Özel OpenAI uyumlu API (gelişmiş) Use OpenAI-compatible endpoints such as LM Studio or Ollama (local or remote). LM Studio veya Ollama gibi OpenAI uyumlu uç noktaları kullanın (yerel ya da uzak). Add… Ekle… Edit… Düzenle… Delete Sil Custom local LLM (gguf) Özel yerel LLM (gguf) Downloads İndirilenler Download İndir Image analysis models (LLaVA) Görüntü analizi modelleri (LLaVA) Download the visual LLM files required for image analysis. Görüntü analizi için gerekli görsel LLM dosyalarını indirin. LLaVA 1.6 Mistral 7B (text model) LLaVA 1.6 Mistral 7B (metin modeli) LLaVA mmproj (vision encoder) LLaVA mmproj (görüntü kodlayıcı) Choose or add a custom model. Özel bir model seçin veya ekleyin. Custom model selected. Özel model seçildi. Selection ready. Seçim hazır. Choose or add a custom API endpoint. Özel bir API uç noktası seçin veya ekleyin. Custom API selected. Özel API seçildi. ChatGPT will use your API key and model. ChatGPT API anahtarınızı ve modelinizi kullanacak. Enter your OpenAI API key and model to continue. Devam etmek için OpenAI API anahtarınızı ve modelinizi girin. Gemini will use your API key and model. Gemini API anahtarınızı ve modelinizi kullanacak. Enter your Gemini API key and model to continue. Devam etmek için Gemini API anahtarınızı ve modelinizi girin. Model ready. Model hazır. Resume download İndirmeye devam et Partial download detected. You can resume. Kısmi indirme tespit edildi. Devam edebilirsiniz. Download required. İndirme gerekli. Unsupported LLM selection. Desteklenmeyen LLM seçimi. Missing download URL environment variable (%1). İndirme URL'si ortam değişkeni eksik (%1). Delete downloaded model? İndirilen modeli sil? Delete the downloaded model %1? İndirilen model %1 silinsin mi? Failed to delete downloaded model. İndirilen model silinemedi. Deleted downloaded model. İndirilen model silindi. No downloaded model found to delete. Silinecek indirilen model bulunamadı. Remote URL Uzak URL Local path Yerel yol File size Dosya boyutu File size: unknown Dosya boyutu: bilinmiyor Delete custom model Özel modeli sil Remove '%1' from your custom LLMs? This does not delete the file on disk. '%1' özel LLM listenizden kaldırılsın mı? Bu işlem diskteki dosyayı silmez. Delete custom API Özel API'yi sil Remove '%1' from your custom API list? This does not affect the server. '%1' özel API listenizden kaldırılsın mı? Bu işlem sunucuyu etkilemez. Missing download URL environment variable. İndirme URL'si ortam değişkeni eksik. Downloading… İndiriliyor… Download complete. İndirme tamamlandı. Download cancelled. İndirme iptal edildi. Download error: %1 İndirme hatası: %1 MainApp File Explorer Dosya gezgini Select Directory Klasör seç Loaded folder %1 %1 klasörü yüklendi Analysis cancelled Analiz iptal edildi Folder selected: %1 Seçilen klasör: %1 More consistent Daha tutarlı More refined Daha ayrıntılı Recategorize folder? Klasör yeniden kategorilendirilsin mi? This folder was categorized using the %1 mode. Do you want to recategorize it now using the %2 mode? Bu klasör %1 modunda kategorilendirildi. Şimdi %2 moduyla yeniden kategorilendirmek ister misiniz? Recategorize Yeniden kategorilendir Keep existing Mevcut kalsın Failed to reset cached categorization for this folder. Bu klasör için önbellekteki kategorilendirme sıfırlanamadı. Download required İndirme gerekli Image analysis requires visual LLM files. Download them now? Görüntü analizi için görsel LLM dosyaları gerekir. Şimdi indirilsin mi? OK Tamam Stop analyzing Analizi durdur Analyzing… Analiz ediliyor… Analyze folder Klasörü analiz et Ready Hazır Undo last run Son çalıştırmayı geri al This will attempt to move files back to their original locations based on the last run. Plan file: %1 Son çalıştırmaya göre dosyaları özgün konumlarına geri taşımaya çalışır. Plan dosyası: %1 Restored %1 file(s). Skipped %2. %1 dosya geri yüklendi. %2 atlandı. Undo complete Geri alma tamamlandı Thank you for using AI File Sorter! You have categorized %1 files thus far. I, the author, really hope this app was useful for you. AI File Sorter'ı kullandığınız için teşekkürler! Şimdiye kadar %1 dosyayı kategorilendirdiniz. Geliştirici olarak umarım bu uygulama sizin için faydalı olmuştur. AI File Sorter takes hundreds of hours of development, feature work, support replies, and ongoing costs such as servers and remote-model infrastructure. If the app saves you time or brings value, please consider supporting it so it can keep improving. AI File Sorter yüzlerce saatlik geliştirme, özellik çalışması, destek yanıtları ve sunucular ile uzak model altyapısı gibi sürekli maliyetler gerektirir. Uygulama size zaman kazandırıyor veya değer sağlıyorsa, gelişmeye devam edebilmesi için desteklemeyi düşünün. Already donated? Click "I have already donated" to enter your donation code and permanently disable this reminder. Zaten bağış yaptınız mı? Bağış kodunuzu girmek ve bu hatırlatmayı kalıcı olarak kapatmak için "Zaten bağış yaptım" seçeneğine tıklayın. Donate to permanently hide the donation dialog Bağış iletişim kutusunu kalıcı olarak gizlemek için bağış yap I'm not yet sure Henüz emin değilim I have already donated Zaten bağış yaptım Donation code Bağış kodu Enter the donation code generated after your donation. A valid code will permanently hide the donation dialog. Bağışınızdan sonra oluşturulan bağış kodunu girin. Geçerli bir kod bağış iletişim kutusunu kalıcı olarak gizler. Invalid donation code Geçersiz bağış kodu The donation code is invalid. Please try again or press Cancel. Bağış kodu geçersiz. Lütfen tekrar deneyin veya İptal'e basın. Open donation page Bağış sayfasını aç Could not open your browser automatically. Please open this link manually: %1 Tarayıcınız otomatik olarak açılamadı. Lütfen bu bağlantıyı elle açın: %1 Directory Klasör File Dosya [ARCHIVE] Already categorized highlights: [ARŞİV] Zaten kategorize edilen öğeler: [DONE] No files to categorize. [BİTTİ] Kategorize edilecek dosya yok. [QUEUE] Items waiting for categorization: [SIRA] Kategorizasyon için bekleyen öğeler: [SCAN] Exploring %1 [TARAMA] %1 keşfediliyor [PROCESS] Letting the AI do its magic... [İŞLEM] Yapay zeka sihrini yapıyor... [VISION] Decoding image batch %1/%2 (%3%) [GÖRSEL] Görüntü grubu %1/%2 çözümleniyor (%3%) Switch image analysis to CPU? Görüntü analizi CPU'ya geçirilsin mi? Image analysis ran out of GPU memory. Görüntü analizi GPU belleğini tüketti. Retry on CPU instead? Cancel will skip visual analysis and fall back to filename-based categorization. Bunun yerine CPU'da yeniden denensin mi? İptal, görsel analizi atlayıp dosya adına dayalı kategorizasyona döner. [VISION-ERROR] %1 (%2) [GÖRSEL-HATA] %1 (%2) [VISION] Switching visual analysis to CPU. [VISION] Görsel analiz CPU'ya geçiriliyor. [VISION-ERROR] %1 [VISION-ERROR] %1 [VISION] Visual analysis disabled; falling back to filenames. [VISION] Görsel analiz devre dışı; dosya adlarına geri dönülüyor. [VISION] Using cached suggestion for %1 [GÖRSEL] %1 için önbellekteki öneri kullanılıyor [VISION] Analyzing %1 [GÖRSEL] %1 analiz ediliyor [VISION] GPU memory issue detected. Switching to CPU. [VISION] GPU bellek sorunu algılandı. CPU'ya geçiliyor. [VISION] Visual analysis disabled for remaining images. [VISION] Kalan görseller için görsel analiz devre dışı bırakıldı. [DOC-ERROR] %1 (%2) [BELGE-HATA] %1 (%2) [DOC] Using cached suggestion for %1 [BELGE] %1 için önbellekteki öneri kullanılıyor [DOC] Analyzing %1 [BELGE] %1 analiz ediliyor [SORT] %1 (%2) [SIRALAMA] %1 (%2) Cancelling analysis… Analiz iptal ediliyor… Switch local AI to CPU? Yerel yapay zeka CPU'ya geçirilsin mi? The local model encountered a GPU error or ran out of memory. Yerel model bir GPU hatasıyla karşılaştı veya belleği tükendi. Retry on CPU instead? Cancel will stop this analysis. Bunun yerine CPU'da yeniden denensin mi? İptal, bu analizi durdurur. [WARN] GPU fallback to CPU declined. Cancelling analysis. [WARN] GPU'dan CPU'ya geri dönüş reddedildi. Analiz iptal ediliyor. [WARN] GPU acceleration failed to initialize. Continuing on CPU (slower). [UYARI] GPU hızlandırması başlatılamadı. CPU ile devam ediliyor (daha yavaş). [WARN] %1 will be re-categorized: %2 [UYARI] %1 yeniden kategorize edilecek: %2 QObject Edit selected items Seçili öğeleri düzenle Leave empty to keep existing Mevcut değeri korumak için boş bırakın Category Kategori Subcategory Alt kategori About %1 %1 hakkında About Hakkında Credits Emeği geçenler About the AGPL License AGPL lisansı hakkında AI File Sorter is distributed under the GNU Affero General Public License v3.0.<br><br>You can access the full source code at <a href="https://github.com/hyperfield/ai-file-sorter">github.com/hyperfield/ai-file-sorter</a>.<br><br>A full copy of the license is provided with this application and available online at <a href="https://www.gnu.org/licenses/agpl-3.0.html">gnu.org</a>. AI File Sorter, GNU Affero General Public License v3.0 kapsamında dağıtılmaktadır.<br><br>Tam kaynak koduna şu adresten erişebilirsiniz: <a href="https://github.com/hyperfield/ai-file-sorter">github.com/hyperfield/ai-file-sorter</a>.<br><br>Lisansın tam kopyası uygulama ile birlikte gelir ve çevrimiçi olarak <a href="https://www.gnu.org/licenses/agpl-3.0.html">gnu.org</a> adresinde bulunur. CPU CPU Metal Metal CUDA CUDA Vulkan Vulkan Metal (auto) Metal (otomatik) Vulkan (auto) Vulkan (otomatik) %1 (auto) %1 (otomatik) Auto Otomatik CPU (%1) CPU (%1) GPU (target: %1) GPU (hedef: %1) GPU via Vulkan unavailable Vulkan üzerinden GPU kullanılamıyor GPU via CUDA unavailable CUDA üzerinden GPU kullanılamıyor Vulkan unavailable Vulkan kullanılamıyor GPU via Metal unavailable Metal üzerinden GPU kullanılamıyor GPU init failed GPU başlatma başarısız Default model: %1 Varsayılan model: %1 Measuring categorization (warm-up + %1 run(s))... Kategorilendirme ölçülüyor (ısınma + %1 çalıştırma(lar))... Measuring document analysis (warm-up + %1 run(s))... Belge analizi ölçülüyor (ısınma + %1 çalıştırma(lar))... Categorization: %1 Kategorilendirme: %1 done tamamlandı failed başarısız Warm-up: %1 Isınma: %1 Init: %1 Başlatma: %1 Per-item (median of %1): %2 Öğe başına (%1 medyanı): %2 Per-item runs: %1 Öğe başına çalıştırmalar: %1 Details: %1 Ayrıntılar: %1 Backend used: %1 Kullanılan arka uç: %1 Document analysis: %1 Belge analizi: %1 Model failed to load: %1 Model yüklenemedi: %1 optimal optimal acceptable kabul edilebilir a bit long oldukça uzun n/a uygulanamaz Result Sonuç Categorization speed: unavailable Sınıflandırma hızı: kullanılamıyor Document analysis speed: unavailable Belge analizi hızı: kullanılamıyor Categorization speed: %1 Sınıflandırma hızı: %1 Document analysis speed: %1 Belge analizi hızı: %1 Image analysis speed: unavailable Görüntü analizi hızı: kullanılamıyor Image analysis speed: %1 Görüntü analizi hızı: %1 Recommended Local LLM choice: %1 Önerilen yerel LLM seçimi: %1 You can toggle LLMs in Settings -> Select LLM LLM'leri Ayarlar -> LLM seç bölümünden değiştirebilirsiniz Compatibility Benchmark Uyumluluk kıyaslaması Run a quick performance check to estimate how image analysis, document analysis, and file categorization will perform on your system. Bu sistemde görüntü analizi, belge analizi ve dosya kategorilendirmenin nasıl performans göstereceğini tahmin etmek için hızlı bir performans kontrolü yapar. It is recommended to quit any CPU- and GPU-intensive applications before running this test. Bu testi çalıştırmadan önce CPU ve GPU yoğun uygulamaları kapatmanız önerilir. Run benchmark Benchmark'ı çalıştır Do not auto-show this dialog again Bu iletişim kutusunu otomatik olarak tekrar gösterme Stop Benchmark Benchmark durdur Close Kapat No previous results yet. Henüz önceki sonuç yok. Last run: %1 Son çalışma: %1 Previous results: Önceki sonuçlar: No downloaded LLM files detected. Download a categorization or visual model to run the benchmark. İndirilen LLM dosyası algılanmadı. Benchmark'ı çalıştırmak için bir kategorilendirme veya görsel model indirin. Starting system compatibility check... Sistem uyumluluk denetimi başlatılıyor... CPU threads detected: %1 CPU iş parçacıkları algılandı: %1 GPU backend override: %1 GPU arka uç zorlaması: %1 Metal available: %1 Metal kullanılabilir: %1 yes evet no hayır GPU memory allocation (Metal): %1 free / %2 total GPU bellek ayırma (Metal): %1 boş / %2 toplam GPU memory allocation (Metal): unavailable GPU bellek ayırma (Metal): kullanılamıyor CUDA available: %1 CUDA kullanılabilir: %1 CUDA memory (allocatable): %1 free / %2 total CUDA belleği (ayrılabilir): %1 boş / %2 toplam (device total: %1) (cihaz toplamı: %1) GPU memory allocation (Vulkan): %1 free / %2 total GPU bellek ayırma (Vulkan): %1 boş / %2 toplam GPU memory allocation (Vulkan): unavailable GPU bellek ayırma (Vulkan): kullanılamıyor Temporary directory setup failed; benchmark sample file creation may fail. Geçici dizin kurulumu başarısız oldu; kıyaslama örnek dosyası oluşturma başarısız olabilir. No default models downloaded; skipping categorization and document checks. Varsayılan model indirilmedi; kategorilendirme ve belge kontrolleri atlanıyor. Default models detected: %1 Varsayılan modeller algılandı: %1 Benchmark stopped. Benchmark durduruldu. Running image analysis test... Görüntü analizi testi çalıştırılıyor... unavailable kullanılamıyor Image analysis: skipped (%1) Görüntü analizi: atlandı (%1) Image analysis: %1 Görüntü analizi: %1 Time: %1 Süre: %1 GPU disabled by backend override GPU, arka uç zorlamasıyla devre dışı bırakıldı Backend used (image analysis): %1 Kullanılan arka uç (görüntü analizi): %1 Benchmark failed: %1 Benchmark başarısız: %1 [STOP] Benchmark will stop after the current step is processed. [STOP] Benchmark mevcut adımdan sonra duracaktır. Error Hata Local LLM (%1) Yerel LLM (%1) Local LLM Yerel LLM Support %1 %1'ı Destekle Required Update Available Zorunlu güncelleme mevcut A required update is available. Please update to continue. If you choose to quit, the application will close. Zorunlu bir güncelleme mevcut. Devam etmek için lütfen güncelleyin. Çıkış'ı seçerseniz uygulama kapanacaktır. Update Now Şimdi güncelle Quit Çıkış Optional Update Available İsteğe bağlı güncelleme mevcut An optional update is available. Would you like to update now? İsteğe bağlı bir güncelleme mevcut. Şimdi güncellemek ister misiniz? Skip This Version Bu sürümü atla Cancel İptal Downloading Update Güncelleme indiriliyor Downloading the update installer... Güncelleme yükleyicisi indiriliyor... Failed to prepare the update installer. %1 Güncelleme yükleyicisi hazırlanamadı. %1 Installer Ready Yükleyici hazır Quit the app and launch the installer to update Güncellemek için uygulamadan çıkın ve yükleyiciyi başlatın Quit and Launch Installer Çık ve yükleyiciyi başlat The installer could not be launched. Yükleyici başlatılamadı. No download target is available for this update. Bu güncelleme için kullanılabilir bir indirme hedefi yok. Update Failed Güncelleme başarısız oldu Update manually Elle güncelle Edit whitelist İzin listesini düzenle Name: Ad: Categories (comma separated): Kategoriler (virgülle ayrılmış): Subcategories (comma separated): Alt kategoriler (virgülle ayrılmış): CUDA Toolkit Missing CUDA Toolkit eksik A compatible NVIDIA GPU was detected, but the CUDA Toolkit is missing. CUDA is required for GPU acceleration in this application. Would you like to download and install it now? Uyumlu bir NVIDIA GPU algılandı, ancak CUDA Toolkit eksik. Bu uygulamada GPU hızlandırması için CUDA gereklidir. Şimdi indirip kurmak ister misiniz? Launch Error Başlatma hatası Cannot enable both CUDA and Vulkan simultaneously. CUDA ve Vulkan aynı anda etkinleştirilemez. Missing GGML Runtime GGML çalışma zamanı eksik Could not locate the backend runtime DLLs. Tried: %1 %2 Arka uç çalışma zamanı DLL'leri bulunamadı. Denenen yollar: %1 %2 Launch Failed Başlatma başarısız Failed to launch the main application executable: %1 Ana uygulama yürütülebilir dosyası başlatılamadı: %1 UiTranslator Folder: Klasör: Browse… Gözat… Use subcategories Alt kategorileri kullan Create subcategory folders within each category. Her kategori içinde alt klasörler oluştur. Categorization type Kategorilendirme türü Choose how strict the category labels should be. Kategori etiketlerinin ne kadar katı olacağını seç. More refined Daha ayrıntılı Favor detailed labels even if similar items vary. Benzer öğeler değişse bile ayrıntılı etiketleri tercih eder. More consistent Daha tutarlı Favor consistent labels across similar items. Benzer öğelerde tutarlı etiketleri tercih eder. Use a whitelist Beyaz liste kullan Restrict categories and subcategories to the selected whitelist. Kategorileri ve alt kategorileri seçili beyaz listeyle sınırla. Select the whitelist used for this run. Bu çalışma için kullanılacak beyaz listeyi seç. Categorize files Dosyaları kategorilendir Include files in the categorization pass. Dosyaları kategorizasyona dahil et. Categorize folders Dizinleri kategorilendir Include directories in the categorization pass. Dizinleri kategorizasyona dahil et. Scan subfolders Alt klasörleri tara Scan files inside subfolders and treat them as part of the main folder. Alt dizinlerdeki dosyaları tara ve ana dizindeymiş gibi işle. Analyze picture files by content (can be slow) Resim dosyalarını içeriğe göre analiz et (yavaş olabilir) Run the visual LLM on supported picture files. Görsel LLM'yi desteklenen resim dosyaları üzerinde çalıştır. Process picture files only (ignore any other files) Yalnızca resim dosyalarını işle (diğer tüm dosyaları yok say) Ignore non-picture files in this run. Bu çalışmada resim olmayan dosyaları yok say. Add image creation date (if available) to category name Görüntü oluşturma tarihini (varsa) kategori adına ekle Append the image creation date from metadata to the category label. Görüntü oluşturma tarihini meta verilerden kategori etiketine ekle. Add photo date and place to filename (if available) Fotoğraf tarihini ve yerini dosya adına ekle (varsa) Date comes from photo EXIF metadata. Place names are resolved online from GPS coordinates, so network access is required for place prefixes. Tarih, fotoğrafın EXIF meta verilerinden alınır. Yer adları GPS koordinatlarından çevrimiçi çözümlenir; bu nedenle yer önekleri için ağ erişimi gerekir. Add audio/video metadata to file name (if available) Ses/video meta verilerini dosya adına ekle (varsa) Use embedded media tags (for example year, artist, album, title) to build suggested audio/video filenames. Önerilen ses/video dosya adlarını oluşturmak için gömülü medya etiketlerini (ör. yıl, sanatçı, albüm, başlık) kullan. Offer to rename picture files Resim dosyalarını yeniden adlandırmayı öner Show suggested filenames for picture files. Resim dosyaları için önerilen dosya adlarını göster. Do not categorize picture files (only rename) Resim dosyalarını kategorize etme (yalnızca yeniden adlandır) Skip categorization for picture files and only rename them. Resim dosyalarını kategorize etme, yalnızca yeniden adlandır. Show or hide picture analysis options Görsel analiz seçeneklerini göster veya gizle Analyze document files by content Belge dosyalarını içeriğe göre analiz et Summarize document contents with the selected LLM. Belge içeriğini seçilen LLM ile özetle. Process document files only (ignore any other files) Yalnızca belge dosyalarını işle (diğer tüm dosyaları yok say) Ignore non-document files in this run. Bu çalışmada belge olmayan dosyaları yok say. Offer to rename document files Belge dosyalarını yeniden adlandırmayı öner Show suggested filenames for document files. Belge dosyaları için önerilen dosya adlarını göster. Do not categorize document files (only rename) Belge dosyalarını kategorize etme (yalnızca yeniden adlandır) Skip categorization for document files and only rename them. Belge dosyalarını kategorize etme, yalnızca yeniden adlandır. Add document creation date (if available) to category name Belge oluşturma tarihini (varsa) kategori adına ekle Append the document creation date from metadata to the category label. Belge oluşturma tarihini meta verilerden kategori etiketine ekle. Show or hide document analysis options Belge analiz seçeneklerini göster veya gizle Stop analyzing Analizi durdur Analyze folder Klasörü analiz et File Dosya Type Tür Category Kategori Subcategory Alt kategori Status Durum Directory Klasör Ready Hazır &Help &Yardım File Explorer Dosya gezgini Cancelling analysis… Analiz iptal ediliyor… Analyzing… Analiz ediliyor… WhitelistManagerDialog Category whitelists Kategori izin listeleri Add Ekle Edit Düzenle Remove Kaldır Cannot remove Kaldırılamaz The default list cannot be removed. Varsayılan liste kaldırılamaz. ================================================ FILE: app/resources/windows/app_icon.rc.in ================================================ #include IDI_APP_ICON ICON "@APP_ICON_PATH@" ================================================ FILE: app/resources/windows/version.rc.in ================================================ #include #define VER_COMPANY "hyperfield" #define VER_FILEDESC "AI File Sorter" #define VER_PRODUCT "AI File Sorter" #define VER_FILEVER @APP_VER_MAJOR@,@APP_VER_MINOR@,@APP_VER_PATCH@,0 #define VER_FILEVER_STR "@APP_VER_MAJOR@.@APP_VER_MINOR@.@APP_VER_PATCH@\0" VS_VERSION_INFO VERSIONINFO FILEVERSION VER_FILEVER PRODUCTVERSION VER_FILEVER FILEFLAGSMASK 0x3fL FILEFLAGS 0x0L FILEOS 0x40004L FILETYPE 0x1L FILESUBTYPE 0x0L BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904E4" BEGIN VALUE "CompanyName", VER_COMPANY "\0" VALUE "FileDescription", VER_FILEDESC "\0" VALUE "FileVersion", VER_FILEVER_STR VALUE "ProductName", VER_PRODUCT "\0" VALUE "ProductVersion", VER_FILEVER_STR VALUE "OriginalFilename", "AIFileSorter.exe\0" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x0409, 1200 END END ================================================ FILE: app/scripts/README.md ================================================ # Diagnostic Collection Scripts This folder includes cross-platform scripts for collecting AI File Sorter diagnostics, automatically redacting common sensitive data, and creating a zipped bundle to share. ## Scripts - `collect_macos_diagnostics.sh` (macOS) - `collect_linux_diagnostics.sh` (Linux) - `collect_windows_diagnostics.ps1` (Windows PowerShell) ## What they do Each script: 1. Collects relevant app logs and platform crash/system logs. 2. Redacts common secrets and user-identifying paths from text-based files. 3. Produces a `*-redacted.zip` bundle for sharing. ## Collection window behavior - Default: **latest-run mode** - Uses the newest app log file timestamp and collects around that window. - Optional: **time-period mode** - You specify a duration such as `30m`, `1h`, `2h30m`, `1d`. If no relevant app logs are found, scripts fall back to a recent window (typically 1 hour). ## macOS Run from repo root: ```bash ./app/scripts/collect_macos_diagnostics.sh ./app/scripts/collect_macos_diagnostics.sh --time-period=1h ./app/scripts/collect_macos_diagnostics.sh --time-period=1h --open-output ``` Options: - `--time-period=` - `--output-dir=` - `--keep-raw` - `--open-output` - `-h`, `--help` Main sources collected: - `~/.cache/AIFileSorter/logs` (and `$XDG_CACHE_HOME/AIFileSorter/my_app/logs` if set) - `~/Library/Logs/DiagnosticReports/*aifilesorter*` - macOS unified logs (`log show`) filtered for AI File Sorter process/messages ## Linux Run from repo root: ```bash ./app/scripts/collect_linux_diagnostics.sh ./app/scripts/collect_linux_diagnostics.sh --time-period=1h ./app/scripts/collect_linux_diagnostics.sh --time-period=1h --open-output ``` Options: - `--time-period=` - `--output-dir=` - `--keep-raw` - `--open-output` - `-h`, `--help` Main sources collected: - `~/.cache/AIFileSorter/logs` (and `$XDG_CACHE_HOME/AIFileSorter/my_app/logs` if set) - `/var/crash` entries related to AI File Sorter (when available) - `coredumpctl` output for `aifilesorter` (when available) - `journalctl` entries for `aifilesorter` / `aifilesorter-bin` (when available) ## Windows (PowerShell) Run from repo root in PowerShell: ```powershell .\app\scripts\collect_windows_diagnostics.ps1 .\app\scripts\collect_windows_diagnostics.ps1 -TimePeriod 1h .\app\scripts\collect_windows_diagnostics.ps1 -TimePeriod 1h -OpenOutput ``` Options: - `-TimePeriod ` - `-OutputDir ` - `-KeepRaw` - `-OpenOutput` - `-ShowHelp` Main sources collected: - `%APPDATA%\AIFileSorter\logs` - `%LOCALAPPDATA%\CrashDumps` - `%LOCALAPPDATA%\Microsoft\Windows\WER\ReportArchive` and `ReportQueue` - Windows Application/System event entries matching AI File Sorter ## Output structure Scripts write to your output directory (default desktop/home), with names like: - `aifs-macos-diagnostics-YYYYMMDD_HHMMSS-redacted.zip` - `aifs-linux-diagnostics-YYYYMMDD_HHMMSS-redacted.zip` - `aifs-windows-diagnostics-YYYYMMDD_HHMMSS-redacted.zip` Inside, the archive contains a `redacted/` folder with sanitized artifacts. ## Redaction notes Redaction is best-effort and targets common sensitive patterns: - User home paths and usernames in paths - Authorization bearer tokens - URL query secrets such as `key`, `api_key`, `token`, etc. - Common API key patterns (`sk-...`, `AIza...`) You can keep raw files with `--keep-raw` / `-KeepRaw` for local inspection, but only share the redacted zip by default. ================================================ FILE: app/scripts/build_llama_linux.sh ================================================ #!/bin/bash set -e # Resolve script directory SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" LLAMA_DIR="$SCRIPT_DIR/../include/external/llama.cpp" if [ ! -d "$LLAMA_DIR" ]; then echo "Missing llama.cpp submodule. Please run:" echo " git submodule update --init --recursive" exit 1 fi PRECOMPILED_ROOT_DIR="$SCRIPT_DIR/../lib/precompiled" HEADERS_DIR="$SCRIPT_DIR/../include/llama" # Parse optional arguments (cuda=on/off, vulkan=on/off, blas=on/off/auto) CUDASWITCH="OFF" VULKANSWITCH="OFF" BLASSWITCH="AUTO" for arg in "$@"; do case "${arg,,}" in cuda=on) CUDASWITCH="ON" ;; cuda=off) CUDASWITCH="OFF" ;; vulkan=on) VULKANSWITCH="ON" ;; vulkan=off) VULKANSWITCH="OFF" ;; blas=on) BLASSWITCH="ON" ;; blas=off) BLASSWITCH="OFF" ;; blas=auto) BLASSWITCH="AUTO" ;; esac done if [[ "$CUDASWITCH" == "ON" && "$VULKANSWITCH" == "ON" ]]; then echo "Cannot enable both CUDA and Vulkan simultaneously. Choose one backend." exit 1 fi echo "CUDA support: $CUDASWITCH" echo "VULKAN support: $VULKANSWITCH" echo "BLAS support: $BLASSWITCH (auto prefers OpenBLAS for CPU baseline)" # Resolve OpenBLAS availability when BLAS is set to AUTO resolve_blas_setting() { local requested="$1" if [[ "$requested" == "ON" || "$requested" == "OFF" ]]; then echo "$requested" return 0 fi if command -v pkg-config >/dev/null 2>&1 && pkg-config --exists openblas; then echo "ON" return 0 fi for candidate in /usr/lib/libopenblas.so /usr/lib64/libopenblas.so /usr/lib/x86_64-linux-gnu/libopenblas.so /usr/lib/aarch64-linux-gnu/libopenblas.so; do if [ -e "$candidate" ]; then echo "ON" return 0 fi done echo "OFF" } build_variant() { local variant="$1" local cuda_flag="$2" local vulkan_flag="$3" local blas_flag="$4" local runtime_subdir="$5" local build_dir="$LLAMA_DIR/build-$variant" rm -rf "$build_dir" mkdir -p "$build_dir" echo "Building variant '$variant' (CUDA=$cuda_flag, VULKAN=$vulkan_flag, BLAS=$blas_flag)..." cd "$LLAMA_DIR" local cmake_args=( -DGGML_CUDA="$cuda_flag" -DGGML_VULKAN="$vulkan_flag" -DGGML_OPENCL=OFF -DGGML_BLAS="$blas_flag" -DBUILD_SHARED_LIBS=ON -DGGML_NATIVE=OFF -DCMAKE_C_FLAGS="-mavx2 -mfma" -DCMAKE_CXX_FLAGS="-mavx2 -mfma" -S . -B "$build_dir" ) if [[ "$blas_flag" == "ON" ]]; then cmake_args+=( -DGGML_BLAS_VENDOR=OpenBLAS ) fi if [[ "$cuda_flag" == "ON" ]]; then cmake_args+=( -DCMAKE_CUDA_HOST_COMPILER=/usr/bin/g++-10 ) fi cmake "${cmake_args[@]}" cmake --build "$build_dir" --config Release -- -j"$(nproc)" local variant_root="$PRECOMPILED_ROOT_DIR/$variant" local variant_bin="$variant_root/bin" local variant_lib="$variant_root/lib" local ggml_runtime_root="$SCRIPT_DIR/../lib/ggml" local runtime_dir="$ggml_runtime_root/$runtime_subdir" rm -rf "$variant_bin" "$variant_lib" "$runtime_dir" mkdir -p "$variant_bin" "$variant_lib" "$runtime_dir" shopt -s nullglob for so in "$build_dir"/bin/*.so "$build_dir"/bin/*.so.*; do cp -P "$so" "$variant_bin/" cp -P "$so" "$runtime_dir/" done for lib in "$build_dir"/lib/*.a; do cp "$lib" "$variant_lib/" done for so in "$build_dir"/lib/*.so "$build_dir"/lib/*.so.*; do cp -P "$so" "$variant_lib/" cp -P "$so" "$runtime_dir/" done shopt -u nullglob if command -v patchelf >/dev/null 2>&1; then if compgen -G "$variant_bin/"'*.so*' >/dev/null; then for lib in "$variant_bin"/*.so*; do patchelf --set-rpath '$ORIGIN' "$lib" || true done fi else echo "Warning: patchelf not found; skipping RUNPATH fix for llama libraries." fi cd "$SCRIPT_DIR" } # Determine BLAS setting (AUTO falls back to OFF if OpenBLAS is missing) RESOLVED_BLAS="$(resolve_blas_setting "$BLASSWITCH")" if [[ "$BLASSWITCH" == "ON" && "$RESOLVED_BLAS" == "OFF" ]]; then echo "Requested BLAS=ON but OpenBLAS was not found. Install openblas (or set blas=off) and retry." >&2 exit 1 fi if [[ "$RESOLVED_BLAS" == "OFF" && "$BLASSWITCH" == "AUTO" ]]; then echo "OpenBLAS not detected; building CPU baseline without BLAS. Install openblas and rerun for BLAS acceleration." fi # Always build a CPU baseline (OpenBLAS when available) build_variant "cpu" "OFF" "OFF" "$RESOLVED_BLAS" "wocuda" # Build requested accelerator variant if applicable REQUESTED_VARIANT="cpu" REQUESTED_RUNTIME="wocuda" if [[ "$CUDASWITCH" == "ON" ]]; then REQUESTED_VARIANT="cuda" REQUESTED_RUNTIME="wcuda" elif [[ "$VULKANSWITCH" == "ON" ]]; then REQUESTED_VARIANT="vulkan" REQUESTED_RUNTIME="wvulkan" fi if [[ "$REQUESTED_VARIANT" != "cpu" ]]; then build_variant "$REQUESTED_VARIANT" "$CUDASWITCH" "$VULKANSWITCH" "$RESOLVED_BLAS" "$REQUESTED_RUNTIME" fi # Copy headers once (from the source tree) rm -rf "$HEADERS_DIR" && mkdir -p "$HEADERS_DIR" cp "$LLAMA_DIR/include/llama.h" "$HEADERS_DIR" cp "$LLAMA_DIR"/ggml/src/*.h "$HEADERS_DIR" cp "$LLAMA_DIR"/ggml/include/*.h "$HEADERS_DIR" # Clean up build directories rm -rf "$LLAMA_DIR"/build-* ================================================ FILE: app/scripts/build_llama_macos.sh ================================================ #!/bin/bash set -e # CLI flags usage() { cat <<'USAGE' Usage: build_llama_macos.sh [options] Options: --arch Target macOS architecture --arm64 Alias for --arch arm64 (Apple Silicon) --x86_64 Alias for --arch x86_64 (Intel) --intel Alias for --arch x86_64 --m1 | --m2 | --m3 Alias for --arch arm64 -h | --help Show this help Environment overrides: LLAMA_MACOS_ARCH Target architecture (overridden by CLI) LLAMA_MACOS_ENABLE_METAL=0|1|auto LLAMA_MACOS_MULTI_VARIANT=0|1 USAGE } CLI_ARCH="" while [[ $# -gt 0 ]]; do case "$1" in --arch) if [[ -z "${2:-}" ]]; then echo "Missing value for --arch" >&2 usage exit 1 fi CLI_ARCH="$2" shift 2 ;; --arm64|--apple-silicon|--m1|--m2|--m3) CLI_ARCH="arm64" shift ;; --x86_64|--intel) CLI_ARCH="x86_64" shift ;; -h|--help) usage exit 0 ;; *) echo "Unknown option: $1" >&2 usage exit 1 ;; esac done if [[ -n "$CLI_ARCH" ]]; then case "$CLI_ARCH" in arm64|x86_64) ;; *) echo "Unsupported arch: $CLI_ARCH (use arm64 or x86_64)" >&2 exit 1 ;; esac export LLAMA_MACOS_ARCH="$CLI_ARCH" fi # Resolve script directory (cross-shell portable) SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" LLAMA_DIR="$SCRIPT_DIR/../include/external/llama.cpp" if [ ! -d "$LLAMA_DIR" ]; then echo "Missing llama.cpp submodule. Please run:" echo " git submodule update --init --recursive" exit 1 fi PRECOMPILED_LIBS_DIR="${LLAMA_PRECOMPILED_DIR:-$SCRIPT_DIR/../lib/precompiled}" if [[ "$PRECOMPILED_LIBS_DIR" != /* ]]; then PRECOMPILED_LIBS_DIR="$SCRIPT_DIR/../$PRECOMPILED_LIBS_DIR" fi HEADERS_DIR="$SCRIPT_DIR/../include/llama" BUILD_DIR="$LLAMA_DIR/build" BUILD_BIN_DIR="$BUILD_DIR/bin" DYLIB_RPATH="@loader_path" normalize_macos_dylib_rpaths() { local dylib_dir="$1" local stale_rpath="$2" shopt -s nullglob for dylib in "$dylib_dir"/*.dylib; do if ! otool -l "$dylib" | grep -Fq "$DYLIB_RPATH"; then install_name_tool -add_rpath "$DYLIB_RPATH" "$dylib" fi if otool -l "$dylib" | grep -Fq "$stale_rpath"; then install_name_tool -delete_rpath "$stale_rpath" "$dylib" fi done shopt -u nullglob } ARCH=$(uname -m) TARGET_ARCH=${LLAMA_MACOS_ARCH:-$ARCH} echo "Building on architecture: $ARCH (target: $TARGET_ARCH)" CROSS_COMPILE=0 if [ "$ARCH" != "$TARGET_ARCH" ]; then CROSS_COMPILE=1 fi MACOSX_DEPLOYMENT_TARGET=${MACOSX_DEPLOYMENT_TARGET:-11.0} export MACOSX_DEPLOYMENT_TARGET echo "Targeting macOS ${MACOSX_DEPLOYMENT_TARGET} for build outputs" DEFAULT_BREW_PREFIX="/opt/homebrew" if [ "$TARGET_ARCH" = "x86_64" ]; then DEFAULT_BREW_PREFIX="/usr/local" fi if [ -n "${BREW_PREFIX:-}" ]; then HOMEBREW_PREFIX="$BREW_PREFIX" elif [ -x "${DEFAULT_BREW_PREFIX}/bin/brew" ]; then HOMEBREW_PREFIX="$(${DEFAULT_BREW_PREFIX}/bin/brew --prefix)" elif command -v brew >/dev/null 2>&1; then HOMEBREW_PREFIX="$(brew --prefix)" else HOMEBREW_PREFIX="$DEFAULT_BREW_PREFIX" fi echo "Using Homebrew prefix: ${HOMEBREW_PREFIX}" QT_PREFIX="${HOMEBREW_PREFIX}/opt/qt" OPENSSL_PREFIX="${HOMEBREW_PREFIX}/opt/openssl@3" PKG_CONFIG_DIRS=( "${HOMEBREW_PREFIX}/lib/pkgconfig" "${HOMEBREW_PREFIX}/share/pkgconfig" "${OPENSSL_PREFIX}/lib/pkgconfig" "${QT_PREFIX}/lib/pkgconfig" ) PKG_CONFIG_PATH_VALUE="$(IFS=:; echo "${PKG_CONFIG_DIRS[*]}")" export PKG_CONFIG_PATH="${PKG_CONFIG_PATH_VALUE}${PKG_CONFIG_PATH:+:${PKG_CONFIG_PATH}}" export PKG_CONFIG_LIBDIR="${PKG_CONFIG_PATH_VALUE}" export CMAKE_PREFIX_PATH="${HOMEBREW_PREFIX}${CMAKE_PREFIX_PATH:+;${CMAKE_PREFIX_PATH}}" if [ "$TARGET_ARCH" = "x86_64" ]; then export CMAKE_IGNORE_PREFIX_PATH="/opt/homebrew${CMAKE_IGNORE_PREFIX_PATH:+;${CMAKE_IGNORE_PREFIX_PATH}}" fi # Decide whether to enable Metal. Apple Silicon machines benefit from it, but # most Intel Macs either lack usable Metal compute queues or expose 0 bytes of # GPU memory to ggml, which causes llama.cpp to fail the moment it tries to # initialize the backend. On Intel default to a CPU-only build; allow overrides # via LLAMA_MACOS_ENABLE_METAL=1. ENABLE_METAL=${LLAMA_MACOS_ENABLE_METAL:-auto} if [ "$ENABLE_METAL" = "auto" ]; then if [ "$TARGET_ARCH" = "arm64" ]; then ENABLE_METAL=1 else ENABLE_METAL=0 fi fi if [ "$ENABLE_METAL" != "0" ]; then echo "Enabling Metal backend" METAL_FLAG=ON else echo "Disabling Metal backend (CPU-only build)" METAL_FLAG=OFF fi MULTI_VARIANT=${LLAMA_MACOS_MULTI_VARIANT:-0} CPU_VARIANT_ARGS="" if [ "$MULTI_VARIANT" = "1" ]; then echo "Enabling multi-variant CPU backend build" CPU_VARIANT_ARGS="-DGGML_BACKEND_DL=ON -DGGML_CPU_ALL_VARIANTS=ON -DGGML_NATIVE=OFF" elif [ "$CROSS_COMPILE" = "1" ]; then echo "Cross-compiling CPU backend; disabling native CPU targeting" CPU_VARIANT_ARGS="-DGGML_NATIVE=OFF" fi ARCH_CMAKE_ARG="" if [ -n "$LLAMA_MACOS_ARCH" ]; then ARCH_CMAKE_ARG="-DCMAKE_OSX_ARCHITECTURES=${LLAMA_MACOS_ARCH}" fi # Ensure SDK paths and libc++ headers are available (especially on Intel Macs). if command -v xcrun >/dev/null 2>&1; then SDKROOT="$(xcrun --sdk macosx --show-sdk-path 2>/dev/null)" if [ -n "$SDKROOT" ]; then export SDKROOT export CFLAGS="${CFLAGS} -isysroot ${SDKROOT}" export CXXFLAGS="${CXXFLAGS} -isysroot ${SDKROOT} -stdlib=libc++ -I${SDKROOT}/usr/include/c++/v1" export LDFLAGS="${LDFLAGS} -isysroot ${SDKROOT}" CMAKE_SYSROOT_ARG="-DCMAKE_OSX_SYSROOT=${SDKROOT}" fi fi # Enter llama.cpp directory and build cd "$LLAMA_DIR" rm -rf "$BUILD_DIR" mkdir -p "$BUILD_DIR" LDFLAGS= cmake -S . -B "$BUILD_DIR" \ ${CMAKE_SYSROOT_ARG} \ ${ARCH_CMAKE_ARG} \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_OSX_DEPLOYMENT_TARGET=${MACOSX_DEPLOYMENT_TARGET} \ -DCMAKE_BUILD_WITH_INSTALL_RPATH=ON \ -DCMAKE_INSTALL_RPATH=${DYLIB_RPATH} \ -DOPENSSL_ROOT_DIR=${OPENSSL_PREFIX} \ -DBUILD_SHARED_LIBS=ON \ -DCMAKE_EXE_LINKER_FLAGS= \ -DCMAKE_SHARED_LINKER_FLAGS= \ -DCMAKE_MODULE_LINKER_FLAGS= \ ${CPU_VARIANT_ARGS} \ -DGGML_METAL=${METAL_FLAG} \ -DGGML_BLAS=ON -DGGML_BLAS_VENDOR=Accelerate \ -DGGML_CUDA=OFF \ -DGGML_OPENCL=OFF \ -DGGML_VULKAN=OFF \ -DGGML_SYCL=OFF \ -DGGML_HIP=OFF \ -DGGML_KLEIDIAI=OFF \ -DBLAS_LIBRARIES="-framework Accelerate" LDFLAGS= cmake --build "$BUILD_DIR" --config Release -- -j$(sysctl -n hw.logicalcpu) # Copy the resulting dynamic (.dylib) libraries rm -rf "$PRECOMPILED_LIBS_DIR" mkdir -p "$PRECOMPILED_LIBS_DIR" cp "$BUILD_BIN_DIR"/libllama.dylib "$PRECOMPILED_LIBS_DIR" cp "$BUILD_BIN_DIR"/libggml*.dylib "$PRECOMPILED_LIBS_DIR" cp "$BUILD_BIN_DIR"/libmtmd.dylib "$PRECOMPILED_LIBS_DIR" normalize_macos_dylib_rpaths "$PRECOMPILED_LIBS_DIR" "$BUILD_BIN_DIR" # Provide versioned symlinks expected by the app runtime loader ( cd "$PRECOMPILED_LIBS_DIR" ln -sf libllama.dylib libllama.0.dylib ln -sf libmtmd.dylib libmtmd.0.dylib ) if [ "$MULTI_VARIANT" = "1" ]; then shopt -s nullglob for backend_lib in "$BUILD_BIN_DIR"/libggml-*.so; do cp "$backend_lib" "$PRECOMPILED_LIBS_DIR" done shopt -u nullglob for backend_dylib in "$PRECOMPILED_LIBS_DIR"/libggml-*.dylib; do base="${backend_dylib%.dylib}" if [ ! -e "${base}.so" ]; then ln -sf "$(basename "$backend_dylib")" "${base}.so" fi done fi # Copy headers rm -rf "$HEADERS_DIR" mkdir -p "$HEADERS_DIR" cp include/llama.h "$HEADERS_DIR" cp ggml/src/*.h "$HEADERS_DIR" cp ggml/include/*.h "$HEADERS_DIR" ================================================ FILE: app/scripts/build_llama_windows.ps1 ================================================ $ErrorActionPreference = "Stop" # --- Parse optional arguments --- $useCuda = "OFF" $useVulkan = "OFF" $useBlas = "AUTO" # AUTO = enable BLAS for CPU-only builds by default $vcpkgRootArg = $null $openBlasRootArg = $null foreach ($arg in $args) { if ($arg -match "^cuda=(on|off)$") { $useCuda = $Matches[1].ToUpper() } elseif ($arg -match "^vulkan=(on|off)$") { $useVulkan = $Matches[1].ToUpper() } elseif ($arg -match "^blas=(on|off)$") { $useBlas = $Matches[1].ToUpper() } elseif ($arg -match "^vcpkgroot=(.+)$") { $vcpkgRootArg = $Matches[1] } elseif ($arg -match "^openblasroot=(.+)$") { $openBlasRootArg = $Matches[1] } } if ($useCuda -eq "ON" -and $useVulkan -eq "ON") { throw "Cannot enable both CUDA and Vulkan simultaneously. Choose only one backend." } Write-Output "`nCUDA Support: $useCuda`n" Write-Output "Vulkan Support: $useVulkan`n" Write-Output "BLAS Support: $useBlas (AUTO enables for CPU-only builds)`n" $scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Definition $llamaDir = Join-Path $scriptDir "..\include\external\llama.cpp" if (-not (Test-Path $llamaDir)) { Write-Output "Missing llama.cpp submodule. Please run:" Write-Output " git submodule update --init --recursive" exit 1 } $precompiledRootDir = Join-Path $scriptDir "..\lib\precompiled" $headersDir = Join-Path $scriptDir "..\include\llama" $ggmlRuntimeRoot = Join-Path $scriptDir "..\lib\ggml" # --- Locate cmake executable --- function Resolve-CMake { $cmd = Get-Command cmake -ErrorAction SilentlyContinue if ($cmd) { return $cmd.Source } $vsCMake = "C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin\cmake.exe" if (Test-Path $vsCMake) { return $vsCMake } throw "cmake executable not found in PATH. Run this script from a VS Developer PowerShell or install CMake and ensure it is on PATH." } $cmakeExe = Resolve-CMake function Resolve-MSVCCompiler { $cmd = Get-Command cl.exe -ErrorAction SilentlyContinue if ($cmd -and (Test-Path $cmd.Source)) { return $cmd.Source } $vswherePath = Join-Path ${env:ProgramFiles(x86)} "Microsoft Visual Studio\Installer\vswhere.exe" if (Test-Path $vswherePath) { $installationPath = & $vswherePath ` -latest ` -products * ` -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 ` -property installationPath if ($installationPath) { $toolRoot = Join-Path $installationPath "VC\Tools\MSVC" if (Test-Path $toolRoot) { $toolsets = Get-ChildItem -Path $toolRoot -Directory | Sort-Object Name -Descending foreach ($toolset in $toolsets) { $candidate = Join-Path $toolset.FullName "bin\Hostx64\x64\cl.exe" if (Test-Path $candidate) { return $candidate } } } } } throw "Could not locate MSVC cl.exe. Run this script from a Developer PowerShell or install the Visual Studio C++ toolchain." } $msvcCompiler = Resolve-MSVCCompiler # --- Locate OpenBLAS (required on Windows) --- function Resolve-VcpkgRoot { param([string]$Explicit) if ($Explicit) { return $Explicit } $defaultRoot = "C:\dev\vcpkg" if (Test-Path $defaultRoot) { return $defaultRoot } if ($env:VCPKG_ROOT) { if ($env:VCPKG_ROOT -like "*Program Files*Microsoft Visual Studio*") { Write-Warning "Detected Visual Studio's bundled vcpkg at '$($env:VCPKG_ROOT)', which is typically read-only. Please clone vcpkg to a writable location (e.g. $defaultRoot) and pass vcpkgroot=." return $null } return $env:VCPKG_ROOT } return $null } $cpuOnlyBuild = ($useCuda -eq "OFF" -and $useVulkan -eq "OFF") $enableBlas = ($useBlas -eq "ON") -or ($useBlas -eq "AUTO" -and $cpuOnlyBuild) function Resolve-OpenBlasRoot { param([string]$Explicit) $candidates = @() if ($Explicit) { $candidates += $Explicit } if ($env:OPENBLAS_ROOT) { $candidates += $env:OPENBLAS_ROOT } $candidates += "C:\msys64\mingw64" foreach ($candidate in $candidates) { if ($candidate -and (Test-Path $candidate)) { return (Resolve-Path $candidate).Path } } return $null } $vcpkgRoot = Resolve-VcpkgRoot -Explicit $vcpkgRootArg if (-not $vcpkgRoot -or -not (Test-Path $vcpkgRoot)) { throw "Could not resolve a writable vcpkg root. Pass vcpkgroot= (e.g. C:\dev\vcpkg) or set VCPKG_ROOT accordingly." } $env:VCPKG_ROOT = $vcpkgRoot $triplet = "x64-windows" function Invoke-Vcpkg { param( [string]$Subcommand, [string[]]$PackageArgs = @() ) $vcpkgExe = Join-Path $vcpkgRoot "vcpkg.exe" if (-not (Test-Path $vcpkgExe)) { throw "Cannot find vcpkg.exe under $vcpkgRoot. Please ensure vcpkg is installed there." } Push-Location $vcpkgRoot Write-Output "Invoking vcpkg with arguments: $Subcommand $($PackageArgs -join ' ') (count=$($PackageArgs.Count))" if ($PackageArgs.Count -eq 0) { & $vcpkgExe "--vcpkg-root" $vcpkgRoot $Subcommand } else { & $vcpkgExe "--vcpkg-root" $vcpkgRoot $Subcommand @PackageArgs } $exit = $LASTEXITCODE Pop-Location if ($exit -ne 0) { throw "vcpkg $Subcommand failed with exit code $exit" } } function Confirm-VcpkgPackage { param( [string]$HeaderCheckPath, [string]$LibraryCheckPath, [string]$PackageName, [string[]]$AdditionalPaths = @() ) $pathsToCheck = @() if ($HeaderCheckPath) { $pathsToCheck += $HeaderCheckPath } if ($LibraryCheckPath) { $pathsToCheck += $LibraryCheckPath } foreach ($extraPath in $AdditionalPaths) { if ($extraPath) { $pathsToCheck += $extraPath } } if ($pathsToCheck.Count -eq 0) { throw "Confirm-VcpkgPackage was called for $PackageName with no paths to validate." } $needsInstall = $false foreach ($candidate in $pathsToCheck) { if (-not (Test-Path $candidate)) { $needsInstall = $true break } } if ($needsInstall) { Write-Output "$PackageName not found. Installing via vcpkg ..." $pkgSpec = "${PackageName}:$triplet" Write-Output "Running: vcpkg install $pkgSpec" Invoke-Vcpkg -Subcommand "install" -PackageArgs @($pkgSpec) } foreach ($candidate in $pathsToCheck) { if (-not (Test-Path $candidate)) { throw "Expected $candidate from package $PackageName but the path is still missing." } } } $curlInclude = Join-Path $vcpkgRoot "installed\$triplet\include" $curlLib = Join-Path $vcpkgRoot "installed\$triplet\lib\libcurl.lib" $curlDll = Join-Path $vcpkgRoot "installed\$triplet\bin\libcurl.dll" Confirm-VcpkgPackage -HeaderCheckPath (Join-Path $curlInclude "curl\curl.h") -LibraryCheckPath $curlLib -PackageName "curl" $openBlasInclude = $null $openBlasLib = $null $openBlasDll = $null if ($enableBlas) { $openBlasRoot = Resolve-OpenBlasRoot -Explicit $openBlasRootArg if (-not $openBlasRoot) { throw "BLAS builds require OpenBLAS from MSYS2/MinGW64. Pass openblasroot= or set OPENBLAS_ROOT." } $openBlasIncludeRoot = Join-Path $openBlasRoot "include" $openBlasInclude = Join-Path $openBlasIncludeRoot "openblas" $openBlasHeader = Join-Path $openBlasInclude "cblas.h" if (-not (Test-Path $openBlasHeader)) { throw "Missing cblas.h under $openBlasInclude. Install OpenBLAS via MSYS2 (pacman -S mingw-w64-x86_64-openblas) or point openblasroot to a valid tree." } $openBlasLibCandidates = @( (Join-Path $openBlasRoot "lib\openblas.lib") (Join-Path $openBlasRoot "lib\libopenblas.lib") (Join-Path $openBlasRoot "lib\libopenblas.dll.a") (Join-Path $openBlasRoot "lib\libopenblas.a") ) foreach ($candidate in $openBlasLibCandidates) { if (Test-Path $candidate) { $openBlasLib = $candidate break } } if (-not $openBlasLib) { throw "Could not find an OpenBLAS import library under $openBlasRoot\lib." } $openBlasDllCandidates = @( (Join-Path $openBlasRoot "bin\libopenblas.dll") (Join-Path $openBlasRoot "bin\openblas.dll") ) foreach ($candidate in $openBlasDllCandidates) { if (Test-Path $candidate) { $openBlasDll = $candidate break } } if (-not $openBlasDll) { throw "Could not find the OpenBLAS runtime DLL (e.g. libopenblas.dll) under $openBlasRoot\bin." } Write-Host "Using OpenBLAS from $openBlasRoot" } $vulkanIncludeDir = $null $vulkanLibPath = $null $vulkanDllPath = $null $vulkanGlslcPath = $null $vulkanSdkRoot = $null if ($useVulkan -eq "ON") { $vulkanIncludeDir = Join-Path $vcpkgRoot "installed\$triplet\include" $vulkanHeaderPath = Join-Path $vulkanIncludeDir "vulkan\vulkan.h" $vulkanLibPath = Join-Path $vcpkgRoot "installed\$triplet\lib\vulkan-1.lib" $vulkanDllPath = Join-Path $vcpkgRoot "installed\$triplet\bin\vulkan-1.dll" $shadercToolsDir = Join-Path $vcpkgRoot "installed\$triplet\tools\shaderc" $vulkanGlslcPath = Join-Path $shadercToolsDir "glslc.exe" Confirm-VcpkgPackage -HeaderCheckPath $vulkanHeaderPath -LibraryCheckPath $null -PackageName "vulkan-headers" Confirm-VcpkgPackage -HeaderCheckPath $null -LibraryCheckPath $vulkanLibPath -PackageName "vulkan-loader" -AdditionalPaths @($vulkanDllPath) Confirm-VcpkgPackage -HeaderCheckPath $null -LibraryCheckPath $null -PackageName "shaderc" -AdditionalPaths @($vulkanGlslcPath) $vulkanSdkRoot = Join-Path $vcpkgRoot "installed\$triplet" $env:VULKAN_SDK = $vulkanSdkRoot } # Write-Host "Using OpenBLAS include: $openBlasInclude" # Write-Host "Using OpenBLAS lib: $openBlasLib" # --- Build from llama.cpp --- Push-Location $llamaDir if (Test-Path "build") { Remove-Item -Recurse -Force "build" } New-Item -ItemType Directory -Path "build" | Out-Null $cmakeArgs = @( "-DCMAKE_C_COMPILER=`"$msvcCompiler`"", "-DCMAKE_CXX_COMPILER=`"$msvcCompiler`"", "-DCURL_LIBRARY=`"$curlLib`"", "-DCURL_INCLUDE_DIR=`"$curlInclude`"", "-DBUILD_SHARED_LIBS=ON", "-DGGML_OPENCL=OFF", "-DGGML_VULKAN=$useVulkan", "-DGGML_SYCL=OFF", "-DGGML_HIP=OFF", "-DGGML_KLEIDIAI=OFF", "-DGGML_NATIVE=OFF", "-DCMAKE_C_FLAGS=/arch:AVX2", "-DCMAKE_CXX_FLAGS=/arch:AVX2" ) if ($enableBlas) { if (-not $openBlasInclude -or -not $openBlasLib) { throw "OpenBLAS paths not initialized for the BLAS-enabled build." } $cmakeArgs += @( "-DGGML_BLAS=ON", "-DGGML_BLAS_VENDOR=OpenBLAS", "-DBLA_VENDOR=OpenBLAS", "-DBLAS_INCLUDE_DIRS=`"$openBlasInclude`"", "-DBLAS_LIBRARIES=`"$openBlasLib`"" ) } else { $cmakeArgs += "-DGGML_BLAS=OFF" } if ($useCuda -eq "ON") { $cudaRoot = "C:/Program Files/NVIDIA GPU Computing Toolkit/CUDA/v12.9" $includeDir = "$cudaRoot/include" $libDir = "$cudaRoot/lib/x64/cudart.lib" $cmakeArgs += @( "-DGGML_CUDA=ON", "-DCUDA_TOOLKIT_ROOT_DIR=`"$cudaRoot`"", "-DCUDA_INCLUDE_DIRS=`"$includeDir`"", "-DCUDA_CUDART=`"$libDir`"" ) } else { $cmakeArgs += "-DGGML_CUDA=OFF" } if ($useVulkan -eq "ON") { if (-not $vulkanIncludeDir -or -not $vulkanLibPath -or -not $vulkanGlslcPath) { throw "Vulkan paths were not initialized even though Vulkan support is enabled." } $cmakeArgs += @( "-DVulkan_INCLUDE_DIR=`"$vulkanIncludeDir`"", "-DVulkan_LIBRARY=`"$vulkanLibPath`"", "-DVulkan_GLSLC_EXECUTABLE=`"$vulkanGlslcPath`"" ) if ($vulkanSdkRoot) { $cmakeArgs += "-DVULKAN_SDK=`"$vulkanSdkRoot`"" } } & $cmakeExe -S . -B build @cmakeArgs & $cmakeExe --build build --config Release -- /m Pop-Location # --- Clean and repopulate precompiled outputs --- $variant = "cpu" $runtimeSubdir = "wocuda" if ($useCuda -eq "ON") { $variant = "cuda" $runtimeSubdir = "wcuda" } elseif ($useVulkan -eq "ON") { if ($enableBlas) { $variant = "vulkan-blas" $runtimeSubdir = "wvulkan-cpu" } else { $variant = "vulkan" $runtimeSubdir = "wvulkan" } } $variantRoot = Join-Path $precompiledRootDir $variant $variantBin = Join-Path $variantRoot "bin" $variantLib = Join-Path $variantRoot "lib" $runtimeDir = Join-Path $ggmlRuntimeRoot $runtimeSubdir foreach ($dir in @($variantBin, $variantLib, $runtimeDir)) { if (Test-Path $dir) { Remove-Item -Recurse -Force $dir } New-Item -ItemType Directory -Force -Path $dir | Out-Null } $releaseBin = Join-Path $llamaDir "build\bin\Release" $dllList = @() if (Test-Path $releaseBin) { $dllList = Get-ChildItem -Path $releaseBin -Filter "*.dll" -File | Select-Object -ExpandProperty Name } if (-not $dllList -or $dllList.Count -eq 0) { throw "No DLLs were produced in $releaseBin." } foreach ($dll in $dllList) { $src = Join-Path $releaseBin $dll Copy-Item $src -Destination $variantBin -Force if ($dll -ne "libcurl.dll") { Copy-Item $src -Destination $runtimeDir -Force } } if ($enableBlas -and $openBlasDll -and (Test-Path $openBlasDll)) { $libOpenBlasName = "libopenblas.dll" Copy-Item $openBlasDll -Destination (Join-Path $variantBin $libOpenBlasName) -Force Copy-Item $openBlasDll -Destination (Join-Path $runtimeDir $libOpenBlasName) -Force foreach ($legacy in @((Join-Path $variantBin "openblas.dll"), (Join-Path $runtimeDir "openblas.dll"))) { if (Test-Path $legacy) { Remove-Item $legacy -Force } } } if (Test-Path $curlDll) { Copy-Item $curlDll -Destination $variantBin -Force Copy-Item $curlDll -Destination $runtimeDir -Force } if ($useVulkan -eq "ON" -and $vulkanDllPath -and (Test-Path $vulkanDllPath)) { Copy-Item $vulkanDllPath -Destination $variantBin -Force Copy-Item $vulkanDllPath -Destination $runtimeDir -Force } $importLibNames = @("llama.lib", "ggml.lib", "ggml-base.lib", "ggml-cpu.lib", "mtmd.lib") $optionalLibs = @("ggml-blas.lib", "ggml-openblas.lib") if ($useCuda -eq "ON") { $importLibNames += "ggml-cuda.lib" } foreach ($libName in $importLibNames) { $libSource = Get-ChildItem (Join-Path $llamaDir "build") -Filter $libName -Recurse -ErrorAction SilentlyContinue | Select-Object -First 1 if (-not $libSource) { throw "Could not locate $libName within the llama.cpp build directory." } Copy-Item $libSource.FullName -Destination (Join-Path $variantLib $libName) -Force } foreach ($libName in $optionalLibs) { $libSource = Get-ChildItem (Join-Path $llamaDir "build") -Filter $libName -Recurse -ErrorAction SilentlyContinue | Select-Object -First 1 if ($libSource) { Copy-Item $libSource.FullName -Destination (Join-Path $variantLib $libName) -Force } } # --- Copy headers --- New-Item -ItemType Directory -Force -Path $headersDir | Out-Null Copy-Item "$llamaDir\include\llama.h" -Destination $headersDir Copy-Item "$llamaDir\ggml\src\*.h" -Destination $headersDir -ErrorAction SilentlyContinue Copy-Item "$llamaDir\ggml\include\*.h" -Destination $headersDir -ErrorAction SilentlyContinue ================================================ FILE: app/scripts/collect_linux_diagnostics.sh ================================================ #!/usr/bin/env bash set -euo pipefail usage() { cat <<'EOF' Collect, redact, and zip AI File Sorter diagnostics on Linux. Usage: ./collect_linux_diagnostics.sh [options] Options: --time-period= Collect logs from the last duration (e.g. 30m, 1h, 2h30m, 1d) --output-dir= Output directory for collected artifacts (default: ~/Desktop or ~) --keep-raw Keep unredacted raw logs on disk (default: remove raw logs) --open-output Open output directory after completion -h, --help Show this help Default behavior: If --time-period is not supplied, the script attempts "latest run" mode: it finds the newest app log mtime and collects logs around that window. Examples: ./collect_linux_diagnostics.sh ./collect_linux_diagnostics.sh --time-period=1h ./collect_linux_diagnostics.sh --time-period=90m --output-dir="$HOME/Desktop" EOF } die() { echo "Error: $*" >&2 exit 1 } warn() { echo "Warning: $*" >&2 } parse_duration_to_seconds() { local input="$1" local value value="$(printf '%s' "$input" | tr '[:upper:]' '[:lower:]')" value="${value// /}" [[ -n "$value" ]] || die "Empty duration." if [[ "$value" =~ ^[0-9]+$ ]]; then echo "$value" return fi local rest="$value" local total=0 local chunk number unit multiplier while [[ -n "$rest" ]]; do if [[ "$rest" =~ ^([0-9]+)([smhd])(.*)$ ]]; then number="${BASH_REMATCH[1]}" unit="${BASH_REMATCH[2]}" chunk="${BASH_REMATCH[0]}" rest="${BASH_REMATCH[3]}" case "$unit" in s) multiplier=1 ;; m) multiplier=60 ;; h) multiplier=3600 ;; d) multiplier=86400 ;; *) die "Unsupported duration unit in '$chunk'." ;; esac total=$((total + number * multiplier)) else die "Invalid duration format: '$input' (examples: 30m, 1h, 2h30m, 1d)." fi done (( total > 0 )) || die "Duration must be greater than zero." echo "$total" } is_text_like_file() { local file="$1" case "$file" in *.log|*.txt|*.json|*.crash|*.ips|*.ini|*.cfg|*.conf|*.out|*.err) return 0 ;; esac local mime mime="$(file -b --mime-type "$file" 2>/dev/null || true)" case "$mime" in text/*|application/json|application/xml|application/x-empty) return 0 ;; esac return 1 } redact_text_file() { local src="$1" local dst="$2" perl -CS -pe ' BEGIN { $home = $ENV{"HOME"} // ""; } if ($home ne "") { s/\Q$home\E//g; } s#(/home/)[^/\s]+#${1}#g; s#(/media/)[^/\s]+#${1}#g; s#(/mnt/)[^/\s]+#${1}#g; s#(/run/user/)[0-9]+#${1}#g; s/(Authorization:\s*Bearer\s+)[^\s"\047]+/${1}/ig; s/([?&](?:key|api_key|apikey|token|auth|authorization)=)[^&\s"\047]+/${1}/ig; s/\bsk-(?:proj-)?[A-Za-z0-9_-]{8,}\b/sk-/g; s/\bAIza[0-9A-Za-z_-]{20,}\b/AIza/g; ' "$src" > "$dst" } copy_recent_log_files() { local source_dir="$1" local dest_dir="$2" local since_epoch="$3" local copied=0 mkdir -p "$dest_dir" local file mtime for file in "$source_dir"/core.log* "$source_dir"/db.log* "$source_dir"/ui.log*; do [[ -f "$file" ]] || continue mtime="$(stat -c %Y "$file" 2>/dev/null || echo 0)" if (( mtime >= since_epoch )); then cp "$file" "$dest_dir/" copied=$((copied + 1)) fi done echo "$copied" } latest_app_log_epoch() { local latest=0 local dir file mtime for dir in "${APP_LOG_DIRS[@]}"; do [[ -d "$dir" ]] || continue for file in "$dir"/core.log* "$dir"/db.log* "$dir"/ui.log*; do [[ -f "$file" ]] || continue mtime="$(stat -c %Y "$file" 2>/dev/null || echo 0)" if (( mtime > latest )); then latest="$mtime" fi done done echo "$latest" } TIME_PERIOD_RAW="" OUTPUT_DIR="$HOME/Desktop" KEEP_RAW=0 OPEN_OUTPUT=0 while [[ $# -gt 0 ]]; do case "$1" in --time-period=*) TIME_PERIOD_RAW="${1#*=}" ;; --time-period) [[ -n "${2:-}" ]] || die "Missing value for --time-period" TIME_PERIOD_RAW="$2" shift ;; --output-dir=*) OUTPUT_DIR="${1#*=}" ;; --output-dir) [[ -n "${2:-}" ]] || die "Missing value for --output-dir" OUTPUT_DIR="$2" shift ;; --keep-raw) KEEP_RAW=1 ;; --open-output) OPEN_OUTPUT=1 ;; -h|--help) usage exit 0 ;; *) die "Unknown option: $1" ;; esac shift done if [[ "$(uname -s)" != "Linux" ]]; then die "This script is for Linux only." fi command -v perl >/dev/null 2>&1 || die "perl is required but was not found." command -v zip >/dev/null 2>&1 || die "zip is required but was not found." command -v stat >/dev/null 2>&1 || die "stat is required but was not found." if [[ ! -d "$OUTPUT_DIR" ]]; then OUTPUT_DIR="$HOME" fi mkdir -p "$OUTPUT_DIR" OUTPUT_DIR="$(cd "$OUTPUT_DIR" && pwd)" declare -a APP_LOG_DIRS APP_LOG_DIRS=("$HOME/.cache/AIFileSorter/logs") if [[ -n "${XDG_CACHE_HOME:-}" ]]; then APP_LOG_DIRS+=("$XDG_CACHE_HOME/AIFileSorter/my_app/logs") fi now_epoch="$(date +%s)" since_epoch=0 window_seconds=0 window_note="" if [[ -n "$TIME_PERIOD_RAW" ]]; then window_seconds="$(parse_duration_to_seconds "$TIME_PERIOD_RAW")" since_epoch=$((now_epoch - window_seconds)) window_note="time-period mode (--time-period=${TIME_PERIOD_RAW})" else latest_epoch="$(latest_app_log_epoch)" if (( latest_epoch > 0 )); then since_epoch=$((latest_epoch - 300)) if (( since_epoch < 0 )); then since_epoch=0 fi window_seconds=$((now_epoch - since_epoch)) if (( window_seconds < 300 )); then window_seconds=300 fi window_note="latest-run mode (newest app log mtime: $(date -d "@${latest_epoch}" "+%Y-%m-%d %H:%M:%S"))" else window_seconds=3600 since_epoch=$((now_epoch - window_seconds)) window_note="fallback mode (no app logs found, using last 1h)" warn "No app logs found. Falling back to last 1h." fi fi ts="$(date "+%Y%m%d_%H%M%S")" base_name="aifs-linux-diagnostics-${ts}" work_dir="${OUTPUT_DIR}/${base_name}" raw_dir="${work_dir}/raw" redacted_dir="${work_dir}/redacted" zip_path="${OUTPUT_DIR}/${base_name}-redacted.zip" mkdir -p "$raw_dir" "$redacted_dir" app_logs_copied=0 if [[ -d "$HOME/.cache/AIFileSorter/logs" ]]; then copied="$(copy_recent_log_files "$HOME/.cache/AIFileSorter/logs" "$raw_dir/cache-logs" "$since_epoch")" app_logs_copied=$((app_logs_copied + copied)) fi if [[ -n "${XDG_CACHE_HOME:-}" ]] && [[ -d "$XDG_CACHE_HOME/AIFileSorter/my_app/logs" ]]; then copied="$(copy_recent_log_files "$XDG_CACHE_HOME/AIFileSorter/my_app/logs" "$raw_dir/xdg-cache-logs" "$since_epoch")" app_logs_copied=$((app_logs_copied + copied)) fi if (( app_logs_copied == 0 )); then warn "No recent app log files matched the selected window." fi mkdir -p "$raw_dir/crash" crash_count=0 if [[ -d "/var/crash" ]]; then while IFS= read -r -d '' crash_file; do mtime="$(stat -c %Y "$crash_file" 2>/dev/null || echo 0)" if (( mtime >= since_epoch )); then cp "$crash_file" "$raw_dir/crash/" 2>/dev/null || true crash_count=$((crash_count + 1)) fi done < <(find /var/crash -maxdepth 1 -type f \ \( -iname "*aifilesorter*" -o -iname "*AIFileSorter*" \) -print0 2>/dev/null || true) fi if command -v coredumpctl >/dev/null 2>&1; then if ! coredumpctl --since "@${since_epoch}" list aifilesorter > "$raw_dir/crash/coredumpctl_aifilesorter.txt" 2>&1; then true fi fi mkdir -p "$raw_dir/journal" if command -v journalctl >/dev/null 2>&1; then journalctl --no-pager --since "@${since_epoch}" _COMM=aifilesorter \ > "$raw_dir/journal/journal_aifilesorter.log" 2> "$raw_dir/journal/journal_aifilesorter.stderr" || true journalctl --no-pager --since "@${since_epoch}" _COMM=aifilesorter-bin \ > "$raw_dir/journal/journal_aifilesorter_bin.log" 2> "$raw_dir/journal/journal_aifilesorter_bin.stderr" || true if [[ ! -s "$raw_dir/journal/journal_aifilesorter.log" ]] && [[ ! -s "$raw_dir/journal/journal_aifilesorter_bin.log" ]]; then journalctl --no-pager --since "@${since_epoch}" \ | grep -Ei 'aifilesorter|AIFileSorter' > "$raw_dir/journal/journal_filtered.log" 2>/dev/null || true fi for err_file in "$raw_dir/journal/"*.stderr; do [[ -f "$err_file" ]] || continue if [[ ! -s "$err_file" ]]; then rm -f "$err_file" fi done else warn "journalctl not found; skipping system journal collection." fi { echo "Collected at: $(date "+%Y-%m-%d %H:%M:%S %z")" echo "Window note: ${window_note}" echo "Window start: $(date -d "@${since_epoch}" "+%Y-%m-%d %H:%M:%S")" echo "Window seconds: ${window_seconds}" echo "App logs copied: ${app_logs_copied}" echo "Crash artifacts copied: ${crash_count}" echo echo "== uname -a ==" uname -a echo echo "== /etc/os-release ==" cat /etc/os-release 2>/dev/null || true echo echo "== lsb_release -a ==" lsb_release -a 2>/dev/null || true echo echo "== glibc ==" getconf GNU_LIBC_VERSION 2>/dev/null || true echo echo "== CPU ==" grep -m1 'model name' /proc/cpuinfo 2>/dev/null || true } > "$raw_dir/system_info.txt" while IFS= read -r -d '' src; do rel="${src#$raw_dir/}" dst="$redacted_dir/$rel" mkdir -p "$(dirname "$dst")" if is_text_like_file "$src"; then redact_text_file "$src" "$dst" else cp "$src" "$dst" fi done < <(find "$raw_dir" -type f -print0) ( cd "$work_dir" zip -qr "$zip_path" "redacted" ) if (( KEEP_RAW == 0 )); then rm -rf "$raw_dir" fi echo "Diagnostics bundle ready:" echo " $zip_path" echo echo "Collected with: $window_note" echo "If needed, inspect redacted files at:" echo " $redacted_dir" if (( OPEN_OUTPUT == 1 )); then if command -v xdg-open >/dev/null 2>&1; then xdg-open "$OUTPUT_DIR" >/dev/null 2>&1 || true fi fi ================================================ FILE: app/scripts/collect_macos_diagnostics.sh ================================================ #!/usr/bin/env bash set -euo pipefail usage() { cat <<'EOF' Collect, redact, and zip AI File Sorter diagnostics on macOS. Usage: ./collect_macos_diagnostics.sh [options] Options: --time-period= Collect logs from the last duration (e.g. 30m, 1h, 2h30m, 1d) --output-dir= Output directory for collected artifacts (default: ~/Desktop) --keep-raw Keep unredacted raw logs on disk (default: remove raw logs) --open-output Reveal the resulting zip in Finder -h, --help Show this help Default behavior: If --time-period is not supplied, the script attempts "latest run" mode: it finds the newest app log mtime and collects logs around that window. Examples: ./collect_macos_diagnostics.sh ./collect_macos_diagnostics.sh --time-period=1h ./collect_macos_diagnostics.sh --time-period=90m --output-dir="$HOME/Desktop" EOF } die() { echo "Error: $*" >&2 exit 1 } warn() { echo "Warning: $*" >&2 } parse_duration_to_seconds() { local input="$1" local value value="$(printf '%s' "$input" | tr '[:upper:]' '[:lower:]')" value="${value// /}" [[ -n "$value" ]] || die "Empty duration." if [[ "$value" =~ ^[0-9]+$ ]]; then echo "$value" return fi local rest="$value" local total=0 local chunk number unit multiplier while [[ -n "$rest" ]]; do if [[ "$rest" =~ ^([0-9]+)([smhd])(.*)$ ]]; then number="${BASH_REMATCH[1]}" unit="${BASH_REMATCH[2]}" chunk="${BASH_REMATCH[0]}" rest="${BASH_REMATCH[3]}" case "$unit" in s) multiplier=1 ;; m) multiplier=60 ;; h) multiplier=3600 ;; d) multiplier=86400 ;; *) die "Unsupported duration unit in '$chunk'." ;; esac total=$((total + number * multiplier)) else die "Invalid duration format: '$input' (examples: 30m, 1h, 2h30m, 1d)." fi done (( total > 0 )) || die "Duration must be greater than zero." echo "$total" } is_text_like_file() { local file="$1" case "$file" in *.log|*.txt|*.json|*.crash|*.ips|*.plist|*.ini|*.cfg|*.conf|*.out|*.err) return 0 ;; esac local mime mime="$(file -b --mime-type "$file" 2>/dev/null || true)" case "$mime" in text/*|application/json|application/xml|application/x-plist|application/x-empty) return 0 ;; esac return 1 } redact_text_file() { local src="$1" local dst="$2" perl -CS -pe ' BEGIN { $home = $ENV{"HOME"} // ""; } if ($home ne "") { s/\Q$home\E//g; } s#(/Users/)[^/\s]+#${1}#g; s#(/Volumes/)[^/\s]+#${1}#g; s#(/private/var/folders/)[^/\s]+#${1}#g; s/(Authorization:\s*Bearer\s+)[^\s"\047]+/${1}/ig; s/([?&](?:key|api_key|apikey|token|auth|authorization)=)[^&\s"\047]+/${1}/ig; s/\bsk-(?:proj-)?[A-Za-z0-9_-]{8,}\b/sk-/g; s/\bAIza[0-9A-Za-z_-]{20,}\b/AIza/g; ' "$src" > "$dst" } copy_recent_log_files() { local source_dir="$1" local dest_dir="$2" local since_epoch="$3" local copied=0 mkdir -p "$dest_dir" local file mtime for file in "$source_dir"/core.log* "$source_dir"/db.log* "$source_dir"/ui.log*; do [[ -f "$file" ]] || continue mtime="$(stat -f %m "$file" 2>/dev/null || echo 0)" if (( mtime >= since_epoch )); then cp "$file" "$dest_dir/" copied=$((copied + 1)) fi done echo "$copied" } latest_app_log_epoch() { local latest=0 local dir file mtime for dir in "${APP_LOG_DIRS[@]}"; do [[ -d "$dir" ]] || continue for file in "$dir"/core.log* "$dir"/db.log* "$dir"/ui.log*; do [[ -f "$file" ]] || continue mtime="$(stat -f %m "$file" 2>/dev/null || echo 0)" if (( mtime > latest )); then latest="$mtime" fi done done echo "$latest" } TIME_PERIOD_RAW="" OUTPUT_DIR="$HOME/Desktop" KEEP_RAW=0 OPEN_OUTPUT=0 while [[ $# -gt 0 ]]; do case "$1" in --time-period=*) TIME_PERIOD_RAW="${1#*=}" ;; --time-period) [[ -n "${2:-}" ]] || die "Missing value for --time-period" TIME_PERIOD_RAW="$2" shift ;; --output-dir=*) OUTPUT_DIR="${1#*=}" ;; --output-dir) [[ -n "${2:-}" ]] || die "Missing value for --output-dir" OUTPUT_DIR="$2" shift ;; --keep-raw) KEEP_RAW=1 ;; --open-output) OPEN_OUTPUT=1 ;; -h|--help) usage exit 0 ;; *) die "Unknown option: $1" ;; esac shift done if [[ "$(uname -s)" != "Darwin" ]]; then die "This script is for macOS only." fi command -v perl >/dev/null 2>&1 || die "perl is required but was not found." command -v zip >/dev/null 2>&1 || die "zip is required but was not found." command -v log >/dev/null 2>&1 || die "macOS 'log' tool not found." mkdir -p "$OUTPUT_DIR" OUTPUT_DIR="$(cd "$OUTPUT_DIR" && pwd)" declare -a APP_LOG_DIRS APP_LOG_DIRS=("$HOME/.cache/AIFileSorter/logs") if [[ -n "${XDG_CACHE_HOME:-}" ]]; then APP_LOG_DIRS+=("$XDG_CACHE_HOME/AIFileSorter/my_app/logs") fi now_epoch="$(date +%s)" since_epoch=0 window_seconds=0 window_note="" if [[ -n "$TIME_PERIOD_RAW" ]]; then window_seconds="$(parse_duration_to_seconds "$TIME_PERIOD_RAW")" since_epoch=$((now_epoch - window_seconds)) window_note="time-period mode (--time-period=${TIME_PERIOD_RAW})" else latest_epoch="$(latest_app_log_epoch)" if (( latest_epoch > 0 )); then since_epoch=$((latest_epoch - 300)) if (( since_epoch < 0 )); then since_epoch=0 fi window_seconds=$((now_epoch - since_epoch)) if (( window_seconds < 300 )); then window_seconds=300 fi window_note="latest-run mode (newest app log mtime: $(date -r "$latest_epoch" "+%Y-%m-%d %H:%M:%S"))" else window_seconds=3600 since_epoch=$((now_epoch - window_seconds)) window_note="fallback mode (no app logs found, using last 1h)" warn "No app logs found. Falling back to last 1h." fi fi ts="$(date "+%Y%m%d_%H%M%S")" base_name="aifs-macos-diagnostics-${ts}" work_dir="${OUTPUT_DIR}/${base_name}" raw_dir="${work_dir}/raw" redacted_dir="${work_dir}/redacted" zip_path="${OUTPUT_DIR}/${base_name}-redacted.zip" mkdir -p "$raw_dir" "$redacted_dir" app_logs_copied=0 if [[ -d "$HOME/.cache/AIFileSorter/logs" ]]; then copied="$(copy_recent_log_files "$HOME/.cache/AIFileSorter/logs" "$raw_dir/cache-logs" "$since_epoch")" app_logs_copied=$((app_logs_copied + copied)) fi if [[ -n "${XDG_CACHE_HOME:-}" ]] && [[ -d "$XDG_CACHE_HOME/AIFileSorter/my_app/logs" ]]; then copied="$(copy_recent_log_files "$XDG_CACHE_HOME/AIFileSorter/my_app/logs" "$raw_dir/xdg-cache-logs" "$since_epoch")" app_logs_copied=$((app_logs_copied + copied)) fi if (( app_logs_copied == 0 )); then warn "No recent app log files matched the selected window." fi mkdir -p "$raw_dir/DiagnosticReports" crash_count=0 if [[ -d "$HOME/Library/Logs/DiagnosticReports" ]]; then while IFS= read -r -d '' crash_file; do mtime="$(stat -f %m "$crash_file" 2>/dev/null || echo 0)" if (( mtime >= since_epoch )); then cp "$crash_file" "$raw_dir/DiagnosticReports/" crash_count=$((crash_count + 1)) fi done < <(find "$HOME/Library/Logs/DiagnosticReports" -maxdepth 1 -type f \ \( -iname "*aifilesorter*" -o -iname "*AIFileSorter*" \) -print0) fi mkdir -p "$raw_dir/unified" predicate='process == "aifilesorter" OR process == "AIFileSorter" OR eventMessage CONTAINS[c] "AIFileSorter" OR eventMessage CONTAINS[c] "aifilesorter"' if ! log show --style compact --last "${window_seconds}s" --predicate "$predicate" \ > "$raw_dir/unified/aifs_unified.log" 2> "$raw_dir/unified/aifs_unified.stderr"; then warn "Failed to read unified logs (see $raw_dir/unified/aifs_unified.stderr)." fi if [[ ! -s "$raw_dir/unified/aifs_unified.stderr" ]]; then rm -f "$raw_dir/unified/aifs_unified.stderr" fi { echo "Collected at: $(date "+%Y-%m-%d %H:%M:%S %z")" echo "Window note: ${window_note}" echo "Window start: $(date -r "$since_epoch" "+%Y-%m-%d %H:%M:%S")" echo "Window seconds: ${window_seconds}" echo "App logs copied: ${app_logs_copied}" echo "Crash reports copied: ${crash_count}" echo echo "== sw_vers ==" sw_vers echo echo "== uname -a ==" uname -a echo echo "== CPU ==" sysctl -n machdep.cpu.brand_string 2>/dev/null || true echo echo "== hw.model ==" sysctl -n hw.model 2>/dev/null || true } > "$raw_dir/system_info.txt" while IFS= read -r -d '' src; do rel="${src#$raw_dir/}" dst="$redacted_dir/$rel" mkdir -p "$(dirname "$dst")" if is_text_like_file "$src"; then redact_text_file "$src" "$dst" else cp "$src" "$dst" fi done < <(find "$raw_dir" -type f -print0) ( cd "$work_dir" zip -qr "$zip_path" "redacted" ) if (( KEEP_RAW == 0 )); then rm -rf "$raw_dir" fi echo "Diagnostics bundle ready:" echo " $zip_path" echo echo "Collected with: $window_note" echo "If needed, inspect redacted files at:" echo " $redacted_dir" if (( OPEN_OUTPUT == 1 )); then open -R "$zip_path" || true fi ================================================ FILE: app/scripts/collect_windows_diagnostics.ps1 ================================================ param( [Alias("time-period")] [string]$TimePeriod, [Alias("output-dir")] [string]$OutputDir = [System.Environment]::GetFolderPath("Desktop"), [Alias("keep-raw")] [switch]$KeepRaw, [Alias("open-output")] [switch]$OpenOutput, [Alias("h", "help")] [switch]$ShowHelp ) $ErrorActionPreference = "Stop" function Show-Usage { @" Collect, redact, and zip AI File Sorter diagnostics on Windows. Usage: .\collect_windows_diagnostics.ps1 [options] Options: -TimePeriod Collect logs from the last duration (e.g. 30m, 1h, 2h30m, 1d) -OutputDir Output directory for collected artifacts (default: Desktop) -KeepRaw Keep unredacted raw logs on disk (default: remove raw logs) -OpenOutput Reveal resulting zip in Explorer -ShowHelp Show this help Default behavior: If -TimePeriod is not supplied, the script attempts "latest run" mode: it finds the newest app log mtime and collects logs around that window. Examples: .\collect_windows_diagnostics.ps1 .\collect_windows_diagnostics.ps1 -TimePeriod 1h .\collect_windows_diagnostics.ps1 -TimePeriod 90m -OutputDir "$env:USERPROFILE\Desktop" "@ } function Convert-TimePeriodToTimeSpan { param([Parameter(Mandatory = $true)][string]$InputValue) $value = $InputValue.Trim().ToLowerInvariant() -replace "\s+", "" if ([string]::IsNullOrWhiteSpace($value)) { throw "Empty duration." } if ($value -match '^\d+$') { return [TimeSpan]::FromSeconds([int64]$value) } $rest = $value $totalSeconds = [int64]0 while ($rest.Length -gt 0) { $m = [regex]::Match($rest, '^([0-9]+)([smhd])(.*)$') if (-not $m.Success) { throw "Invalid duration format: '$InputValue' (examples: 30m, 1h, 2h30m, 1d)." } $number = [int64]$m.Groups[1].Value $unit = $m.Groups[2].Value $rest = $m.Groups[3].Value switch ($unit) { "s" { $totalSeconds += $number } "m" { $totalSeconds += $number * 60 } "h" { $totalSeconds += $number * 3600 } "d" { $totalSeconds += $number * 86400 } default { throw "Unsupported duration unit in '$InputValue'." } } } if ($totalSeconds -le 0) { throw "Duration must be greater than zero." } return [TimeSpan]::FromSeconds($totalSeconds) } function New-DirectoryIfMissing { param([Parameter(Mandatory = $true)][string]$Path) if (-not (Test-Path -LiteralPath $Path)) { New-Item -ItemType Directory -Path $Path -Force | Out-Null } } function Copy-RecentAppLogs { param( [Parameter(Mandatory = $true)][string]$SourceDir, [Parameter(Mandatory = $true)][string]$DestinationDir, [Parameter(Mandatory = $true)][datetime]$Since ) if (-not (Test-Path -LiteralPath $SourceDir)) { return 0 } New-DirectoryIfMissing -Path $DestinationDir $copied = 0 $patterns = @("core.log*", "db.log*", "ui.log*") foreach ($pattern in $patterns) { $files = Get-ChildItem -Path $SourceDir -Filter $pattern -File -ErrorAction SilentlyContinue foreach ($file in $files) { if ($file.LastWriteTime -ge $Since) { Copy-Item -LiteralPath $file.FullName -Destination $DestinationDir -Force $copied++ } } } return $copied } function Get-LatestAppLogTime { param([Parameter(Mandatory = $true)][string[]]$LogDirs) $latest = [datetime]::MinValue foreach ($dir in $LogDirs) { if (-not (Test-Path -LiteralPath $dir)) { continue } $patterns = @("core.log*", "db.log*", "ui.log*") foreach ($pattern in $patterns) { $files = Get-ChildItem -Path $dir -Filter $pattern -File -ErrorAction SilentlyContinue foreach ($file in $files) { if ($file.LastWriteTime -gt $latest) { $latest = $file.LastWriteTime } } } } return $latest } function Is-TextLikeFile { param([Parameter(Mandatory = $true)][string]$Path) $ext = [IO.Path]::GetExtension($Path).ToLowerInvariant() $textExtensions = @( ".log", ".txt", ".json", ".wer", ".xml", ".ini", ".cfg", ".conf", ".out", ".err", ".csv" ) return $textExtensions -contains $ext } function Redact-TextContent { param([Parameter(Mandatory = $true)][string]$Content) $result = $Content if ($env:USERPROFILE) { $result = [regex]::Replace($result, [regex]::Escape($env:USERPROFILE), "", "IgnoreCase") } if ($env:HOMEDRIVE -and $env:HOMEPATH) { $homePath = "$($env:HOMEDRIVE)$($env:HOMEPATH)" $result = [regex]::Replace($result, [regex]::Escape($homePath), "", "IgnoreCase") } $result = [regex]::Replace($result, '(?i)\b([A-Z]:\\Users\\)[^\\\s]+', '$1') $result = [regex]::Replace($result, '(?i)\b([A-Z]:\\Documents and Settings\\)[^\\\s]+', '$1') $result = [regex]::Replace($result, '(?i)(Authorization:\s*Bearer\s+)[^\s"''`]+', '$1') $result = [regex]::Replace($result, '(?i)([?&](?:key|api_key|apikey|token|auth|authorization)=)[^&\s"''`]+', '$1') $result = [regex]::Replace($result, '\bsk-(?:proj-)?[A-Za-z0-9_-]{8,}\b', 'sk-') $result = [regex]::Replace($result, '\bAIza[0-9A-Za-z_-]{20,}\b', 'AIza') return $result } if ($ShowHelp) { Show-Usage exit 0 } if ([System.Environment]::OSVersion.Platform -ne [System.PlatformID]::Win32NT) { throw "This script is for Windows only." } if (-not (Get-Command Compress-Archive -ErrorAction SilentlyContinue)) { throw "Compress-Archive cmdlet is unavailable." } if ([string]::IsNullOrWhiteSpace($OutputDir) -or -not (Test-Path -LiteralPath $OutputDir)) { $OutputDir = $env:USERPROFILE } New-DirectoryIfMissing -Path $OutputDir $OutputDir = (Resolve-Path -LiteralPath $OutputDir).Path $logDirs = @() if ($env:APPDATA) { $logDirs += (Join-Path $env:APPDATA "AIFileSorter\logs") } $now = Get-Date $since = $null $windowNote = "" if (-not [string]::IsNullOrWhiteSpace($TimePeriod)) { $span = Convert-TimePeriodToTimeSpan -InputValue $TimePeriod $since = $now - $span $windowNote = "time-period mode (-TimePeriod $TimePeriod)" } else { $latest = Get-LatestAppLogTime -LogDirs $logDirs if ($latest -gt [datetime]::MinValue) { $since = $latest.AddMinutes(-5) if ($since -lt [datetime]::UnixEpoch) { $since = [datetime]::UnixEpoch } $windowNote = "latest-run mode (newest app log mtime: $($latest.ToString("yyyy-MM-dd HH:mm:ss")))" } else { $since = $now.AddHours(-1) $windowNote = "fallback mode (no app logs found, using last 1h)" Write-Warning "No app logs found. Falling back to last 1h." } } $timestamp = Get-Date -Format "yyyyMMdd_HHmmss" $baseName = "aifs-windows-diagnostics-$timestamp" $workDir = Join-Path $OutputDir $baseName $rawDir = Join-Path $workDir "raw" $redactedDir = Join-Path $workDir "redacted" $zipPath = Join-Path $OutputDir "$baseName-redacted.zip" New-DirectoryIfMissing -Path $rawDir New-DirectoryIfMissing -Path $redactedDir $appLogsCopied = 0 if ($env:APPDATA) { $appLogsCopied += Copy-RecentAppLogs -SourceDir (Join-Path $env:APPDATA "AIFileSorter\logs") -DestinationDir (Join-Path $rawDir "appdata-logs") -Since $since } if ($appLogsCopied -eq 0) { Write-Warning "No recent app log files matched the selected window." } $crashRoot = Join-Path $rawDir "crash" New-DirectoryIfMissing -Path $crashRoot $crashCount = 0 if ($env:LOCALAPPDATA) { $crashDumpDir = Join-Path $env:LOCALAPPDATA "CrashDumps" if (Test-Path -LiteralPath $crashDumpDir) { $dumpDest = Join-Path $crashRoot "CrashDumps" New-DirectoryIfMissing -Path $dumpDest $dumps = Get-ChildItem -Path $crashDumpDir -File -ErrorAction SilentlyContinue | Where-Object { ($_.Name -match '(?i)aifilesorter') -and ($_.LastWriteTime -ge $since) } foreach ($dump in $dumps) { Copy-Item -LiteralPath $dump.FullName -Destination $dumpDest -Force $crashCount++ } } $werBase = Join-Path $env:LOCALAPPDATA "Microsoft\Windows\WER" foreach ($sub in @("ReportArchive", "ReportQueue")) { $dir = Join-Path $werBase $sub if (-not (Test-Path -LiteralPath $dir)) { continue } $dest = Join-Path $crashRoot "WER\$sub" New-DirectoryIfMissing -Path $dest $reportDirs = Get-ChildItem -Path $dir -Directory -ErrorAction SilentlyContinue | Where-Object { ($_.Name -match '(?i)aifilesorter') -and ($_.LastWriteTime -ge $since) } foreach ($reportDir in $reportDirs) { Copy-Item -LiteralPath $reportDir.FullName -Destination $dest -Recurse -Force $crashCount++ } } } $eventsDir = Join-Path $rawDir "events" New-DirectoryIfMissing -Path $eventsDir try { $appEvents = Get-WinEvent -FilterHashtable @{ LogName = "Application"; StartTime = $since } -ErrorAction Stop | Where-Object { $_.Message -match '(?i)aifilesorter|AIFileSorter' } if ($appEvents) { $appEvents | Select-Object TimeCreated, Id, LevelDisplayName, ProviderName, Message | Format-List | Out-File -FilePath (Join-Path $eventsDir "application_events.txt") -Encoding utf8 } else { "No matching Application events." | Out-File -FilePath (Join-Path $eventsDir "application_events.txt") -Encoding utf8 } } catch { "Failed to collect Application events: $($_.Exception.Message)" | Out-File -FilePath (Join-Path $eventsDir "application_events.txt") -Encoding utf8 } try { $sysEvents = Get-WinEvent -FilterHashtable @{ LogName = "System"; StartTime = $since } -ErrorAction Stop | Where-Object { $_.Message -match '(?i)aifilesorter|AIFileSorter' } if ($sysEvents) { $sysEvents | Select-Object TimeCreated, Id, LevelDisplayName, ProviderName, Message | Format-List | Out-File -FilePath (Join-Path $eventsDir "system_events.txt") -Encoding utf8 } else { "No matching System events." | Out-File -FilePath (Join-Path $eventsDir "system_events.txt") -Encoding utf8 } } catch { "Failed to collect System events: $($_.Exception.Message)" | Out-File -FilePath (Join-Path $eventsDir "system_events.txt") -Encoding utf8 } $systemInfoFile = Join-Path $rawDir "system_info.txt" @( "Collected at: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss zzz')" "Window note: $windowNote" "Window start: $($since.ToString('yyyy-MM-dd HH:mm:ss'))" "App logs copied: $appLogsCopied" "Crash artifacts copied: $crashCount" "" "== OS ==" (Get-CimInstance Win32_OperatingSystem | Select-Object -ExpandProperty Caption) (Get-CimInstance Win32_OperatingSystem | Select-Object -ExpandProperty Version) "" "== CPU ==" (Get-CimInstance Win32_Processor | Select-Object -First 1 -ExpandProperty Name) "" "== Computer ==" $env:COMPUTERNAME ) | Out-File -FilePath $systemInfoFile -Encoding utf8 $rawFiles = Get-ChildItem -Path $rawDir -Recurse -File -ErrorAction SilentlyContinue foreach ($srcFile in $rawFiles) { $relative = $srcFile.FullName.Substring($rawDir.Length).TrimStart('\') $dst = Join-Path $redactedDir $relative $dstParent = Split-Path -Parent $dst New-DirectoryIfMissing -Path $dstParent if (Is-TextLikeFile -Path $srcFile.FullName) { try { $content = Get-Content -LiteralPath $srcFile.FullName -Raw -ErrorAction Stop $redacted = Redact-TextContent -Content $content Set-Content -LiteralPath $dst -Value $redacted -Encoding utf8 } catch { Copy-Item -LiteralPath $srcFile.FullName -Destination $dst -Force } } else { Copy-Item -LiteralPath $srcFile.FullName -Destination $dst -Force } } if (Test-Path -LiteralPath $zipPath) { Remove-Item -LiteralPath $zipPath -Force } Compress-Archive -Path (Join-Path $workDir "redacted") -DestinationPath $zipPath -Force if (-not $KeepRaw) { Remove-Item -LiteralPath $rawDir -Recurse -Force } Write-Output "Diagnostics bundle ready:" Write-Output " $zipPath" Write-Output "" Write-Output "Collected with: $windowNote" Write-Output "If needed, inspect redacted files at:" Write-Output " $redactedDir" if ($OpenOutput) { Start-Process explorer.exe "/select,`"$zipPath`"" | Out-Null } ================================================ FILE: app/scripts/gen_run_wrapper.py ================================================ #!/usr/bin/env python3 import argparse from pathlib import Path DEV_DECL = "SCRIPT_DIR=\"$(cd \"$(dirname \"$0\")\" && pwd)\"\nAPP_DIR=\"$(cd \"$SCRIPT_DIR/..\" && pwd)\"" def main(): parser = argparse.ArgumentParser() parser.add_argument('--mode', choices=['dev', 'install'], default='dev') parser.add_argument('--install-app-dir', default='') parser.add_argument('--binary', required=True) parser.add_argument('--template', default='scripts/run_aifilesorter.sh.in') parser.add_argument('--output', required=True) args = parser.parse_args() template = Path(args.template).read_text() if args.mode == 'dev': app_decl = DEV_DECL else: app_decl = f'APP_DIR="{args.install_app_dir}"' content = template.replace('@APP_DIR_DECLARATION@', app_decl) content = content.replace('@WRAPPED_BINARY@', args.binary) Path(args.output).write_text(content) if __name__ == '__main__': main() ================================================ FILE: app/scripts/generate_icon.ps1 ================================================ param( [Parameter(Mandatory = $true)][string]$BasePng, [Parameter(Mandatory = $true)][string]$Ico ) $ErrorActionPreference = "Stop" Add-Type -AssemblyName System.Drawing $basePath = Resolve-Path $BasePng if (-not $basePath) { throw "Base PNG '$BasePng' does not exist." } $icoFullPath = [System.IO.Path]::GetFullPath($Ico) $icoDir = [System.IO.Path]::GetDirectoryName($icoFullPath) if ($icoDir -and -not (Test-Path $icoDir)) { New-Item -ItemType Directory -Force -Path $icoDir | Out-Null } $bitmap = [System.Drawing.Bitmap]::FromFile($basePath) try { $width = $bitmap.Width $height = $bitmap.Height $stream = New-Object System.IO.MemoryStream $bitmap.Save($stream, [System.Drawing.Imaging.ImageFormat]::Png) $bytes = $stream.ToArray() $stream.Dispose() } finally { $bitmap.Dispose() } $fs = [System.IO.File]::Open($icoFullPath, [System.IO.FileMode]::Create, [System.IO.FileAccess]::Write, [System.IO.FileShare]::None) $bw = New-Object System.IO.BinaryWriter($fs) try { $bw.Write([UInt16]0) $bw.Write([UInt16]1) $bw.Write([UInt16]1) $widthByte = if ($width -ge 256) { 0 } else { [byte]$width } $heightByte = if ($height -ge 256) { 0 } else { [byte]$height } $bw.Write([byte]$widthByte) $bw.Write([byte]$heightByte) $bw.Write([byte]0) $bw.Write([byte]0) $bw.Write([UInt16]1) $bw.Write([UInt16]32) $bw.Write([UInt32]$bytes.Length) $bw.Write([UInt32](6 + 16)) $bw.Write($bytes) } finally { $bw.Dispose() $fs.Dispose() } ================================================ FILE: app/scripts/package_deb.sh ================================================ #!/usr/bin/env bash set -euo pipefail # Builds a Debian package for AI File Sorter that bundles only the project-specific # llama/ggml libraries and assumes all other runtime libraries are supplied by the system. # # Usage: # ./package_deb.sh [options] [version] # If no version is supplied, the script reads app/include/app_version.hpp. # By default the package includes CPU precompiled libs. Add flags for GPU variants. SCRIPT_DIR="$(cd -- "$(dirname "${BASH_SOURCE[0]}")" && pwd)" REPO_ROOT="$(cd -- "$SCRIPT_DIR/../.." && pwd)" APP_DIR="$REPO_ROOT/app" usage() { cat <<'EOF' Usage: ./package_deb.sh [options] [version] Options: --include-cuda Include precompiled CUDA runtime libs (app/lib/precompiled/cuda) --include-vulkan Include precompiled Vulkan runtime libs (app/lib/precompiled/vulkan) --include-all Include CPU + CUDA + Vulkan precompiled runtime libs -h, --help Show this help Notes: - CPU precompiled libs are included by default. - Root files in app/lib/precompiled (e.g. libpdfium.so) are always included when present. EOF } VERSION_FROM_HEADER() { local header="$1" if [[ ! -f "$header" ]]; then echo "0.0.0" return fi local line line="$(grep -m1 'APP_VERSION' "$header" || true)" if [[ -z "$line" ]]; then echo "0.0.0" return fi if [[ "$line" =~ Version\{[[:space:]]*([0-9]+)[[:space:]]*,[[:space:]]*([0-9]+)[[:space:]]*,[[:space:]]*([0-9]+)[[:space:]]*\} ]]; then printf "%s.%s.%s\n" "${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}" "${BASH_REMATCH[3]}" else echo "0.0.0" fi } INCLUDE_CPU=1 INCLUDE_CUDA=0 INCLUDE_VULKAN=0 VERSION_ARG="" while [[ $# -gt 0 ]]; do case "$1" in --include-cuda) INCLUDE_CUDA=1 ;; --include-vulkan) INCLUDE_VULKAN=1 ;; --include-all) INCLUDE_CPU=1 INCLUDE_CUDA=1 INCLUDE_VULKAN=1 ;; -h|--help) usage exit 0 ;; -*) echo "Unknown option: $1" >&2 usage >&2 exit 1 ;; *) if [[ -n "$VERSION_ARG" ]]; then echo "Unexpected extra argument: $1" >&2 usage >&2 exit 1 fi VERSION_ARG="$1" ;; esac shift done VERSION="${VERSION_ARG:-$(VERSION_FROM_HEADER "$APP_DIR/include/app_version.hpp")}" if [[ -z "$VERSION" ]]; then echo "Failed to determine package version." >&2 exit 1 fi BIN_PATH="$APP_DIR/bin/aifilesorter-bin" if [[ ! -x "$BIN_PATH" ]]; then echo "Binary not found at $BIN_PATH — running make." >&2 make -C "$APP_DIR" fi if [[ ! -x "$BIN_PATH" ]]; then echo "Binary still missing after build attempt." >&2 exit 1 fi get_needed_soname() { local binary="$1" local pattern="$2" if ! command -v readelf >/dev/null 2>&1; then return 0 fi readelf -d "$binary" 2>/dev/null | awk -v pat="$pattern" ' /NEEDED/ { gsub(/\[|\]/, "", $5); if ($5 ~ pat) { print $5; exit } }' } resolve_fmt_dep() { local soname soname="$(get_needed_soname "$BIN_PATH" '^libfmt[.]so')" case "$soname" in libfmt.so.10) echo "libfmt10" ;; libfmt.so.9) echo "libfmt9" ;; libfmt.so.8) echo "libfmt8" ;; *) echo "libfmt10" ;; esac } resolve_jsoncpp_dep() { local soname soname="$(get_needed_soname "$BIN_PATH" '^libjsoncpp[.]so')" case "$soname" in libjsoncpp.so.26) echo "libjsoncpp26" ;; libjsoncpp.so.25) echo "libjsoncpp25" ;; libjsoncpp.so.24) echo "libjsoncpp24" ;; *) echo "libjsoncpp26" ;; esac } resolve_mediainfo_dep() { local soname soname="$(get_needed_soname "$BIN_PATH" '^libmediainfo[.]so')" case "$soname" in libmediainfo.so.0) echo "libmediainfo0v5" ;; *) echo "libmediainfo0v5" ;; esac } join_by_comma_space() { local first=1 local item for item in "$@"; do if [[ "$first" == "1" ]]; then printf '%s' "$item" first=0 else printf ', %s' "$item" fi done printf '\n' } FMT_DEP="$(resolve_fmt_dep)" JSONCPP_DEP="$(resolve_jsoncpp_dep)" CURL_DEP="libcurl4 | libcurl4t64" MEDIAINFO_DEP="$(resolve_mediainfo_dep)" ZLIB_DEP="zlib1g" OUT_DIR="$REPO_ROOT/dist/aifilesorter_deb" PKG_NAME="aifilesorter_${VERSION}" PKG_ROOT="$OUT_DIR/$PKG_NAME" echo "Staging package in $PKG_ROOT" rm -rf "$PKG_ROOT" mkdir -p \ "$PKG_ROOT/DEBIAN" \ "$PKG_ROOT/opt/aifilesorter/bin" \ "$PKG_ROOT/opt/aifilesorter/lib" \ "$PKG_ROOT/opt/aifilesorter/certs" \ "$PKG_ROOT/usr/bin" install -m 0755 "$BIN_PATH" "$PKG_ROOT/opt/aifilesorter/bin/aifilesorter-bin" ln -sf aifilesorter-bin "$PKG_ROOT/opt/aifilesorter/bin/aifilesorter" PRECOMPILED_SRC="$APP_DIR/lib/precompiled" PRECOMPILED_DST="$PKG_ROOT/opt/aifilesorter/lib/precompiled" copy_variant_dir() { local variant="$1" local enabled="$2" local src_dir="$PRECOMPILED_SRC/$variant" if [[ "$enabled" != "1" ]]; then return 0 fi if [[ ! -d "$src_dir" ]]; then echo "Requested precompiled variant '$variant' but '$src_dir' was not found." >&2 exit 1 fi cp -a "$src_dir" "$PRECOMPILED_DST/" } echo "Copying llama/ggml libraries" if [[ -d "$PRECOMPILED_SRC" ]]; then mkdir -p "$PRECOMPILED_DST" # Keep root-level runtime payloads such as libpdfium.so. find "$PRECOMPILED_SRC" -mindepth 1 -maxdepth 1 \( -type f -o -type l \) \ -exec cp -a {} "$PRECOMPILED_DST/" \; copy_variant_dir cpu "$INCLUDE_CPU" copy_variant_dir cuda "$INCLUDE_CUDA" copy_variant_dir vulkan "$INCLUDE_VULKAN" else echo "Warning: '$PRECOMPILED_SRC' not found; packaging without bundled llama/ggml runtime libs." >&2 fi SELECTED_VARIANTS=() if [[ "$INCLUDE_CPU" == "1" ]]; then SELECTED_VARIANTS+=("cpu"); fi if [[ "$INCLUDE_CUDA" == "1" ]]; then SELECTED_VARIANTS+=("cuda"); fi if [[ "$INCLUDE_VULKAN" == "1" ]]; then SELECTED_VARIANTS+=("vulkan"); fi echo "Included precompiled variants: ${SELECTED_VARIANTS[*]}" PACKAGE_DEPENDS=( "libc6 (>= 2.31)" "libstdc++6 (>= 12)" "libgcc-s1 (>= 12)" "libqt6widgets6 (>= 6.2)" "libqt6gui6 (>= 6.2)" "libqt6core6 (>= 6.2)" "libqt6dbus6 (>= 6.2)" "qt6-wayland" "$CURL_DEP" "$JSONCPP_DEP" "libsqlite3-0" "$FMT_DEP" "libssl3" "libopenblas0-pthread" "$MEDIAINFO_DEP" "$ZLIB_DEP" ) if [[ "$INCLUDE_VULKAN" == "1" ]]; then PACKAGE_DEPENDS+=("libvulkan1") fi PACKAGE_DEPENDS_STR="$(join_by_comma_space "${PACKAGE_DEPENDS[@]}")" DESCRIPTION_TEXT="AI-powered file categorization tool. Requires the listed runtime libraries from the host system." if [[ "$INCLUDE_VULKAN" == "1" ]]; then DESCRIPTION_TEXT+=" Includes the Vulkan backend and requires a working host Vulkan loader/driver stack." fi if [[ "$INCLUDE_CUDA" == "1" ]]; then DESCRIPTION_TEXT+=" CUDA-enabled builds require matching NVIDIA runtime libraries installed separately." fi if [[ -f "$APP_DIR/resources/certs/cacert.pem" ]]; then install -m 0644 "$APP_DIR/resources/certs/cacert.pem" "$PKG_ROOT/opt/aifilesorter/certs/cacert.pem" fi if [[ -f "$REPO_ROOT/LICENSE" ]]; then install -m 0644 "$REPO_ROOT/LICENSE" "$PKG_ROOT/opt/aifilesorter/LICENSE" fi cat > "$PKG_ROOT/usr/bin/run_aifilesorter.sh" <<'EOF' #!/bin/sh APP_DIR="/opt/aifilesorter" CPU_LIB_DIR="$APP_DIR/lib/precompiled/cpu/bin" CUDA_LIB_DIR="$APP_DIR/lib/precompiled/cuda/bin" VULKAN_LIB_DIR="$APP_DIR/lib/precompiled/vulkan/bin" PRECOMPILED_ROOT_DIR="$APP_DIR/lib/precompiled" PLATFORM_CANDIDATES="/usr/lib/x86_64-linux-gnu/qt6/plugins /usr/lib/qt6/plugins /lib/x86_64-linux-gnu/qt6/plugins" choose_vulkan_path() { if [ -d "$VULKAN_LIB_DIR" ]; then if command -v ldconfig >/dev/null 2>&1 && ldconfig -p 2>/dev/null | grep -q libvulkan; then echo "$VULKAN_LIB_DIR" return fi for candidate in /usr/lib/x86_64-linux-gnu/libvulkan.so* /usr/lib/libvulkan.so* /lib/x86_64-linux-gnu/libvulkan.so*; do if [ "$candidate" = "/usr/lib/x86_64-linux-gnu/libvulkan.so*" ]; then break fi if [ -e "$candidate" ]; then echo "$VULKAN_LIB_DIR" return fi done fi echo "" } choose_cuda_path() { if [ -d "$CUDA_LIB_DIR" ]; then if command -v ldconfig >/dev/null 2>&1 && ldconfig -p 2>/dev/null | grep -q libcudart; then echo "$CUDA_LIB_DIR" return fi for candidate in /usr/local/cuda*/targets/x86_64-linux/lib/libcudart.so*; do if [ "$candidate" = "/usr/local/cuda*/targets/x86_64-linux/lib/libcudart.so*" ]; then break fi if [ -e "$candidate" ]; then echo "$CUDA_LIB_DIR" return fi done fi echo "" } SELECTED_VULKAN_DIR="$(choose_vulkan_path)" SELECTED_CUDA_DIR="$(choose_cuda_path)" PATH_COMPONENTS="$CPU_LIB_DIR:$PRECOMPILED_ROOT_DIR" if [ -n "$SELECTED_VULKAN_DIR" ] && [ -d "$SELECTED_VULKAN_DIR" ] && [ "$SELECTED_VULKAN_DIR" != "$CPU_LIB_DIR" ]; then PATH_COMPONENTS="$SELECTED_VULKAN_DIR:$PATH_COMPONENTS" elif [ -n "$SELECTED_CUDA_DIR" ] && [ -d "$SELECTED_CUDA_DIR" ] && [ "$SELECTED_CUDA_DIR" != "$CPU_LIB_DIR" ]; then PATH_COMPONENTS="$SELECTED_CUDA_DIR:$PATH_COMPONENTS" fi if [ -n "$LD_LIBRARY_PATH" ]; then export LD_LIBRARY_PATH="$PATH_COMPONENTS:$LD_LIBRARY_PATH" else export LD_LIBRARY_PATH="$PATH_COMPONENTS" fi if [ -z "$QT_QPA_PLATFORM_PLUGIN_PATH" ]; then for candidate in $PLATFORM_CANDIDATES; do if [ -d "$candidate/platforms" ]; then export QT_QPA_PLATFORM_PLUGIN_PATH="$candidate/platforms" break fi done fi if [ -n "$QT_QPA_PLATFORM_PLUGIN_PATH" ] && [ ! -f "$QT_QPA_PLATFORM_PLUGIN_PATH/libqxcb.so" ]; then if [ -n "$WAYLAND_DISPLAY" ] || [ "$XDG_SESSION_TYPE" = "wayland" ]; then export QT_QPA_PLATFORM="wayland" else echo "Qt xcb platform plugin (libqxcb.so) not found in \$QT_QPA_PLATFORM_PLUGIN_PATH ($QT_QPA_PLATFORM_PLUGIN_PATH)." >&2 echo "Install a Qt 6 XCB platform plugin (e.g. from qt.io archives) or run under a Wayland session." >&2 exit 1 fi fi exec "$APP_DIR/bin/aifilesorter-bin" "$@" EOF chmod 0755 "$PKG_ROOT/usr/bin/run_aifilesorter.sh" ln -sf run_aifilesorter.sh "$PKG_ROOT/usr/bin/aifilesorter" CONTROL_FILE="$PKG_ROOT/DEBIAN/control" cat > "$CONTROL_FILE" < Installed-Size: 0 Depends: ${PACKAGE_DEPENDS_STR} Description: AI File Sorter desktop application ${DESCRIPTION_TEXT} EOF chmod 0644 "$CONTROL_FILE" echo "Adjusting permissions" find "$PKG_ROOT" -type d -exec chmod 755 {} + find "$PKG_ROOT/opt/aifilesorter/lib" -type f -exec chmod 0644 {} + chmod 0755 "$PKG_ROOT/opt/aifilesorter/bin/aifilesorter-bin" chmod 0755 "$PKG_ROOT/opt/aifilesorter/bin/aifilesorter" chmod 0755 "$PKG_ROOT/usr/bin/run_aifilesorter.sh" chmod 0755 "$PKG_ROOT/usr/bin/aifilesorter" SIZE_KB=$(du -sk "$PKG_ROOT" | cut -f1) sed -i "s/^Installed-Size: .*/Installed-Size: ${SIZE_KB}/" "$CONTROL_FILE" mkdir -p "$OUT_DIR" DEB_PATH="$OUT_DIR/${PKG_NAME}_amd64.deb" rm -f "$DEB_PATH" echo "Building package $DEB_PATH" dpkg-deb --build --root-owner-group "$PKG_ROOT" "$OUT_DIR" echo "Done. Package created at $DEB_PATH" ================================================ FILE: app/scripts/rebuild_and_test.sh ================================================ #!/usr/bin/env bash set -euo pipefail script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" repo_root="$(cd "${script_dir}/../.." && pwd)" build_dir="${repo_root}/build-tests" echo "[INFO] Configuring tests build directory at ${build_dir}" cmake -S "${repo_root}/app" -B "${build_dir}" -DAI_FILE_SORTER_BUILD_TESTS=ON echo "[INFO] Building tests" cmake --build "${build_dir}" echo "[INFO] Running ctest" ctest --test-dir "${build_dir}" ================================================ FILE: app/scripts/run_aifilesorter.sh.in ================================================ #!/bin/sh @APP_DIR_DECLARATION@ CPU_LIB_DIR="$APP_DIR/lib/precompiled/cpu/bin" CUDA_LIB_DIR="$APP_DIR/lib/precompiled/cuda/bin" VULKAN_LIB_DIR="$APP_DIR/lib/precompiled/vulkan/bin" PRECOMPILED_ROOT_DIR="$APP_DIR/lib/precompiled" PLATFORM_CANDIDATES="/usr/lib/x86_64-linux-gnu/qt6/plugins /usr/lib/qt6/plugins /lib/x86_64-linux-gnu/qt6/plugins" select_cuda_dir() { if [ -d "$CUDA_LIB_DIR" ]; then if command -v ldconfig >/dev/null 2>&1 && ldconfig -p 2>/dev/null | grep -q libcudart; then echo "$CUDA_LIB_DIR" return fi for candidate in /usr/local/cuda*/targets/x86_64-linux/lib/libcudart.so*; do [ "$candidate" = "/usr/local/cuda*/targets/x86_64-linux/lib/libcudart.so*" ] && break if [ -e "$candidate" ]; then echo "$CUDA_LIB_DIR" return fi done fi echo "" } select_vulkan_dir() { if [ -d "$VULKAN_LIB_DIR" ]; then if command -v ldconfig >/dev/null 2>&1 && ldconfig -p 2>/dev/null | grep -q libvulkan; then echo "$VULKAN_LIB_DIR" return fi for candidate in /usr/lib/x86_64-linux-gnu/libvulkan.so* /usr/lib/libvulkan.so* /lib/x86_64-linux-gnu/libvulkan.so*; do [ "$candidate" = "/usr/lib/x86_64-linux-gnu/libvulkan.so*" ] && break if [ -e "$candidate" ]; then echo "$VULKAN_LIB_DIR" return fi done fi echo "" } CUDA_OVERRIDE="" VULKAN_OVERRIDE="" for arg in "$@"; do case "$arg" in --cuda=on|cuda=on) CUDA_OVERRIDE="on" ;; --cuda=off|cuda=off) CUDA_OVERRIDE="off" ;; --vulkan=on|vulkan=on) VULKAN_OVERRIDE="on" ;; --vulkan=off|vulkan=off) VULKAN_OVERRIDE="off" ;; esac done if [ "$CUDA_OVERRIDE" = "on" ] && [ "$VULKAN_OVERRIDE" = "on" ]; then echo "Cannot force both CUDA and Vulkan simultaneously." >&2 exit 1 fi SELECTED_CUDA_DIR="$(select_cuda_dir)" SELECTED_VK_DIR="$(select_vulkan_dir)" USE_CUDA=0 USE_VULKAN=0 GPU_BACKEND="cpu" GGML_VARIANT="wocuda" LLAMA_DEVICE="" if [ -n "$SELECTED_VK_DIR" ]; then USE_VULKAN=1 elif [ -n "$SELECTED_CUDA_DIR" ]; then USE_CUDA=1 fi if [ "$CUDA_OVERRIDE" = "on" ]; then if [ -n "$SELECTED_CUDA_DIR" ]; then USE_CUDA=1 USE_VULKAN=0 else echo "Warning: CUDA forced but not detected; falling back." >&2 USE_CUDA=0 fi elif [ "$CUDA_OVERRIDE" = "off" ]; then USE_CUDA=0 fi if [ "$VULKAN_OVERRIDE" = "on" ]; then if [ -n "$SELECTED_VK_DIR" ]; then USE_VULKAN=1 if [ "$CUDA_OVERRIDE" != "off" ]; then USE_CUDA=0 fi else echo "Warning: Vulkan forced but not detected; falling back." >&2 USE_VULKAN=0 fi elif [ "$VULKAN_OVERRIDE" = "off" ]; then USE_VULKAN=0 fi if [ $USE_CUDA -eq 0 ] && [ $USE_VULKAN -eq 0 ]; then if [ "$VULKAN_OVERRIDE" != "off" ] && [ -n "$SELECTED_VK_DIR" ]; then USE_VULKAN=1 elif [ "$CUDA_OVERRIDE" != "off" ] && [ -n "$SELECTED_CUDA_DIR" ]; then USE_CUDA=1 fi fi if [ $USE_CUDA -eq 1 ]; then echo "Using CUDA backend." >&2 unset GGML_DISABLE_CUDA GPU_BACKEND="cuda" GGML_VARIANT="wcuda" LLAMA_DEVICE="cuda" elif [ $USE_VULKAN -eq 1 ]; then echo "Using Vulkan backend." >&2 export GGML_DISABLE_CUDA=1 GPU_BACKEND="vulkan" GGML_VARIANT="wvulkan" LLAMA_DEVICE="vulkan" else echo "Using CPU backend." >&2 export GGML_DISABLE_CUDA=1 GPU_BACKEND="cpu" GGML_VARIANT="wocuda" LLAMA_DEVICE="" fi export AI_FILE_SORTER_GPU_BACKEND="$GPU_BACKEND" export AI_FILE_SORTER_GGML_DIR="$APP_DIR/lib/ggml/$GGML_VARIANT" if [ -n "$LLAMA_DEVICE" ]; then export LLAMA_ARG_DEVICE="$LLAMA_DEVICE" else unset LLAMA_ARG_DEVICE fi LIB_PATH="$CPU_LIB_DIR:$PRECOMPILED_ROOT_DIR" if [ $USE_CUDA -eq 1 ] && [ -n "$SELECTED_CUDA_DIR" ]; then LIB_PATH="$SELECTED_CUDA_DIR:$LIB_PATH" elif [ $USE_VULKAN -eq 1 ] && [ -n "$SELECTED_VK_DIR" ]; then LIB_PATH="$SELECTED_VK_DIR:$LIB_PATH" fi if [ -n "$LD_LIBRARY_PATH" ]; then export LD_LIBRARY_PATH="$LIB_PATH:$LD_LIBRARY_PATH" else export LD_LIBRARY_PATH="$LIB_PATH" fi if [ -z "$QT_QPA_PLATFORM_PLUGIN_PATH" ]; then for candidate in $PLATFORM_CANDIDATES; do if [ -d "$candidate/platforms" ]; then export QT_QPA_PLATFORM_PLUGIN_PATH="$candidate/platforms" break fi done fi if [ -n "$QT_QPA_PLATFORM_PLUGIN_PATH" ] && [ ! -f "$QT_QPA_PLATFORM_PLUGIN_PATH/libqxcb.so" ]; then if [ -n "$WAYLAND_DISPLAY" ] || [ "$XDG_SESSION_TYPE" = "wayland" ]; then export QT_QPA_PLATFORM="wayland" else echo "Qt xcb platform plugin (libqxcb.so) not found in $QT_QPA_PLATFORM_PLUGIN_PATH ($QT_QPA_PLATFORM_PLUGIN_PATH)." >&2 echo "Install a Qt 6 XCB platform plugin or run under a Wayland session." >&2 exit 1 fi fi exec "$APP_DIR/bin/@WRAPPED_BINARY@" "$@" ================================================ FILE: app/scripts/vendor_doc_deps.ps1 ================================================ param( [string]$LibzipVersion = "1.11.4", [string]$PugixmlVersion = "1.15", [string]$PdfiumRelease = "latest", [string]$PdfiumMacX64Archive = "pdfium-mac-x64.tgz" ) $ErrorActionPreference = "Stop" $rootDir = Resolve-Path (Join-Path $PSScriptRoot "..\..") $externalDir = Join-Path $rootDir "external" $libzipDir = Join-Path $externalDir "libzip" $pugixmlDir = Join-Path $externalDir "pugixml" $pdfiumDir = Join-Path $externalDir "pdfium" $licenseDir = Join-Path $externalDir "THIRD_PARTY_LICENSES" function Ensure-Dir([string]$Path) { if (-not (Test-Path $Path)) { New-Item -ItemType Directory -Path $Path -Force | Out-Null } } function Require-Tool([string]$Name) { $tool = Get-Command $Name -ErrorAction SilentlyContinue if (-not $tool) { throw "$Name not found. Install it or ensure it is available in PATH." } } function Download-File([string]$Url, [string]$Destination) { Write-Output "Downloading $Url" Invoke-WebRequest -Uri $Url -OutFile $Destination } Require-Tool "tar" Ensure-Dir $externalDir Ensure-Dir $libzipDir Ensure-Dir $pugixmlDir Ensure-Dir $licenseDir Ensure-Dir (Join-Path $pdfiumDir "linux-x64") Ensure-Dir (Join-Path $pdfiumDir "windows-x64") Ensure-Dir (Join-Path $pdfiumDir "macos-arm64") Ensure-Dir (Join-Path $pdfiumDir "macos-x64") $tempDir = Join-Path $env:TEMP "aifilesorter-docdeps" Ensure-Dir $tempDir $libzipArchive = Join-Path $tempDir "libzip-$LibzipVersion.tar.xz" Download-File "https://libzip.org/download/libzip-$LibzipVersion.tar.xz" $libzipArchive & tar -xf $libzipArchive -C $libzipDir --strip-components=1 if (Test-Path (Join-Path $libzipDir "LICENSE")) { Copy-Item (Join-Path $libzipDir "LICENSE") (Join-Path $licenseDir "libzip-LICENSE") -Force } $pugixmlArchive = Join-Path $tempDir "pugixml-$PugixmlVersion.tar.gz" Download-File "https://github.com/zeux/pugixml/releases/download/v$PugixmlVersion/pugixml-$PugixmlVersion.tar.gz" $pugixmlArchive & tar -xf $pugixmlArchive -C $pugixmlDir --strip-components=1 if (Test-Path (Join-Path $pugixmlDir "LICENSE.md")) { Copy-Item (Join-Path $pugixmlDir "LICENSE.md") (Join-Path $licenseDir "pugixml-LICENSE.md") -Force } elseif (Test-Path (Join-Path $pugixmlDir "LICENSE")) { Copy-Item (Join-Path $pugixmlDir "LICENSE") (Join-Path $licenseDir "pugixml-LICENSE") -Force } $pdfiumLinuxArchive = Join-Path $tempDir "pdfium-linux-x64.tgz" Download-File "https://github.com/bblanchon/pdfium-binaries/releases/$PdfiumRelease/download/pdfium-linux-x64.tgz" $pdfiumLinuxArchive & tar -xf $pdfiumLinuxArchive -C (Join-Path $pdfiumDir "linux-x64") $pdfiumWinArchive = Join-Path $tempDir "pdfium-win-x64.tgz" Download-File "https://github.com/bblanchon/pdfium-binaries/releases/$PdfiumRelease/download/pdfium-win-x64.tgz" $pdfiumWinArchive & tar -xf $pdfiumWinArchive -C (Join-Path $pdfiumDir "windows-x64") $pdfiumMacArchive = Join-Path $tempDir "pdfium-mac-arm64.tgz" Download-File "https://github.com/bblanchon/pdfium-binaries/releases/$PdfiumRelease/download/pdfium-mac-arm64.tgz" $pdfiumMacArchive & tar -xf $pdfiumMacArchive -C (Join-Path $pdfiumDir "macos-arm64") $pdfiumMacX64Archive = Join-Path $tempDir $PdfiumMacX64Archive Download-File "https://github.com/bblanchon/pdfium-binaries/releases/$PdfiumRelease/download/$PdfiumMacX64Archive" $pdfiumMacX64Archive & tar -xf $pdfiumMacX64Archive -C (Join-Path $pdfiumDir "macos-x64") if (Test-Path (Join-Path $pdfiumDir "linux-x64\LICENSE")) { Copy-Item (Join-Path $pdfiumDir "linux-x64\LICENSE") (Join-Path $licenseDir "pdfium-LICENSE") -Force } elseif (Test-Path (Join-Path $pdfiumDir "linux-x64\LICENSE.txt")) { Copy-Item (Join-Path $pdfiumDir "linux-x64\LICENSE.txt") (Join-Path $licenseDir "pdfium-LICENSE.txt") -Force } $pdfiumReadme = @" # PDFium prebuilts This folder is populated by `app/scripts/vendor_doc_deps.sh` or `app/scripts/vendor_doc_deps.ps1`. Expected layout: - linux-x64/ - windows-x64/ - macos-arm64/ - macos-x64/ Each folder should contain `include/` and the platform PDFium library under `lib/`: - Linux: `lib/libpdfium.so` - Windows: `bin/pdfium.dll` + `lib/pdfium.dll.lib` - macOS: `lib/libpdfium.dylib` (arm64 or x64) "@ Set-Content -Path (Join-Path $pdfiumDir "README.md") -Value $pdfiumReadme Write-Output "Done. You can now commit external/libzip, external/pugixml, and external/pdfium." ================================================ FILE: app/scripts/vendor_doc_deps.sh ================================================ #!/usr/bin/env bash set -euo pipefail LIBZIP_VERSION="1.11.4" PUGIXML_VERSION="1.15" PDFIUM_RELEASE="latest" ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" LIBZIP_DIR="$ROOT_DIR/external/libzip" PUGIXML_DIR="$ROOT_DIR/external/pugixml" PDFIUM_DIR="$ROOT_DIR/external/pdfium" LICENSE_DIR="$ROOT_DIR/external/THIRD_PARTY_LICENSES" mkdir -p "$LIBZIP_DIR" "$PUGIXML_DIR" "$LICENSE_DIR" \ "$PDFIUM_DIR/linux-x64" "$PDFIUM_DIR/windows-x64" "$PDFIUM_DIR/macos-arm64" "$PDFIUM_DIR/macos-x64" curl -L --fail "https://libzip.org/download/libzip-${LIBZIP_VERSION}.tar.xz" \ -o "/tmp/libzip-${LIBZIP_VERSION}.tar.xz" tar -xf "/tmp/libzip-${LIBZIP_VERSION}.tar.xz" --strip-components=1 -C "$LIBZIP_DIR" if [ -f "$LIBZIP_DIR/LICENSE" ]; then cp "$LIBZIP_DIR/LICENSE" "$LICENSE_DIR/libzip-LICENSE" fi curl -L --fail "https://github.com/zeux/pugixml/releases/download/v${PUGIXML_VERSION}/pugixml-${PUGIXML_VERSION}.tar.gz" \ -o "/tmp/pugixml-${PUGIXML_VERSION}.tar.gz" tar -xf "/tmp/pugixml-${PUGIXML_VERSION}.tar.gz" --strip-components=1 -C "$PUGIXML_DIR" if [ -f "$PUGIXML_DIR/LICENSE.md" ]; then cp "$PUGIXML_DIR/LICENSE.md" "$LICENSE_DIR/pugixml-LICENSE.md" elif [ -f "$PUGIXML_DIR/LICENSE" ]; then cp "$PUGIXML_DIR/LICENSE" "$LICENSE_DIR/pugixml-LICENSE" fi curl -L --fail "https://github.com/bblanchon/pdfium-binaries/releases/${PDFIUM_RELEASE}/download/pdfium-linux-x64.tgz" \ -o "/tmp/pdfium-linux-x64.tgz" tar -xf "/tmp/pdfium-linux-x64.tgz" -C "$PDFIUM_DIR/linux-x64" if [ -f "$PDFIUM_DIR/linux-x64/LICENSE" ]; then cp "$PDFIUM_DIR/linux-x64/LICENSE" "$LICENSE_DIR/pdfium-LICENSE" elif [ -f "$PDFIUM_DIR/linux-x64/LICENSE.txt" ]; then cp "$PDFIUM_DIR/linux-x64/LICENSE.txt" "$LICENSE_DIR/pdfium-LICENSE.txt" fi curl -L --fail "https://github.com/bblanchon/pdfium-binaries/releases/${PDFIUM_RELEASE}/download/pdfium-win-x64.tgz" \ -o "/tmp/pdfium-win-x64.tgz" tar -xf "/tmp/pdfium-win-x64.tgz" -C "$PDFIUM_DIR/windows-x64" curl -L --fail "https://github.com/bblanchon/pdfium-binaries/releases/${PDFIUM_RELEASE}/download/pdfium-mac-arm64.tgz" \ -o "/tmp/pdfium-mac-arm64.tgz" tar -xf "/tmp/pdfium-mac-arm64.tgz" -C "$PDFIUM_DIR/macos-arm64" PDFIUM_MAC_X64_TGZ="${PDFIUM_MAC_X64_TGZ:-pdfium-mac-x64.tgz}" curl -L --fail "https://github.com/bblanchon/pdfium-binaries/releases/${PDFIUM_RELEASE}/download/${PDFIUM_MAC_X64_TGZ}" \ -o "/tmp/${PDFIUM_MAC_X64_TGZ}" tar -xf "/tmp/${PDFIUM_MAC_X64_TGZ}" -C "$PDFIUM_DIR/macos-x64" cat > "$PDFIUM_DIR/README.md" <<'DOC' # PDFium prebuilts This folder is populated by `app/scripts/vendor_doc_deps.sh` or `app/scripts/vendor_doc_deps.ps1`. Expected layout: - linux-x64/ - windows-x64/ - macos-arm64/ - macos-x64/ Each folder should contain `include/` and the platform PDFium library under `lib/`: - Linux: `lib/libpdfium.so` - Windows: `bin/pdfium.dll` + `lib/pdfium.dll.lib` - macOS: `lib/libpdfium.dylib` (arm64 or x64) DOC printf "Done. You can now commit external/libzip, external/pugixml, and external/pdfium.\n" ================================================ FILE: app/startapp_linux.cpp ================================================ #include #include #include #include #include #include #include #include #include #include enum class BackendSelection { Cpu, Cuda, Vulkan }; std::string getExecutableDirectory() { char result[PATH_MAX]; ssize_t count = readlink("/proc/self/exe", result, PATH_MAX); std::string path(result, (count > 0) ? count : 0); size_t pos = path.find_last_of("/\\"); return path.substr(0, pos); } bool fileExists(const std::string& path) { struct stat buffer; return (stat(path.c_str(), &buffer) == 0); } void addToLdLibraryPath(const std::string& dir) { const char* oldPath = getenv("LD_LIBRARY_PATH"); std::string newPath = dir; if (oldPath) { newPath = std::string(oldPath) + ":" + dir; } setenv("LD_LIBRARY_PATH", newPath.c_str(), 1); } bool isCudaInstalled() { return system("ldconfig -p | grep -q libcudart") == 0; } bool isVulkanAvailable() { void* handle = dlopen("libvulkan.so.1", RTLD_NOW | RTLD_LOCAL); if (!handle) { handle = dlopen("libvulkan.so", RTLD_NOW | RTLD_LOCAL); } if (!handle) { return false; } dlclose(handle); return true; } extern char **environ; std::vector collect_environment_variables() { std::vector envVars; for (char **env = environ; *env != nullptr; ++env) { envVars.emplace_back(*env); } return envVars; } void ensure_executable(const std::string& exePath) { if (access(exePath.c_str(), X_OK) != 0) { std::fprintf(stderr, "App is not executable: %s\n", exePath.c_str()); perror("access"); exit(EXIT_FAILURE); } } void set_or_append_env(std::vector& envVars, const std::string& prefix, const std::string& value) { for (auto& env : envVars) { if (env.rfind(prefix, 0) == 0) { env = prefix + value; return; } } envVars.push_back(prefix + value); } std::vector build_envp(std::vector& envVars) { std::vector envp; envp.reserve(envVars.size() + 1); for (auto &s : envVars) { envp.push_back(s.data()); } envp.push_back(nullptr); return envp; } std::vector build_argv(const std::string& exePath, int argc, char** argv) { std::vector arg_storage; arg_storage.push_back(exePath); for (int i = 1; i < argc; ++i) { if (argv[i]) { arg_storage.emplace_back(argv[i]); } } std::vector argv_ptrs; argv_ptrs.reserve(arg_storage.size() + 1); for (auto& arg : arg_storage) { argv_ptrs.push_back(arg.data()); } argv_ptrs.push_back(nullptr); return argv_ptrs; } void launch_with_env(const std::string& exePath, std::vector& argv_ptrs, std::vector& envp) { execve(exePath.c_str(), argv_ptrs.data(), envp.data()); std::fprintf(stderr, "execve failed\n"); perror("execve failed"); exit(EXIT_FAILURE); } void launchMainApp(const std::string& exeDir, const std::string& libPath, int argc, char** argv, bool disable_cuda, const std::string& backend_tag, const std::string& ggml_dir, const std::string& llama_device) { const std::string exePath = exeDir + "/bin/aifilesorter"; ensure_executable(exePath); std::vector envVars = collect_environment_variables(); set_or_append_env(envVars, "LD_LIBRARY_PATH=", libPath); set_or_append_env(envVars, "GGML_DISABLE_CUDA=", disable_cuda ? "1" : "0"); set_or_append_env(envVars, "AI_FILE_SORTER_GPU_BACKEND=", backend_tag); set_or_append_env(envVars, "AI_FILE_SORTER_GGML_DIR=", ggml_dir); set_or_append_env(envVars, "LLAMA_ARG_DEVICE=", llama_device); std::vector envp = build_envp(envVars); std::vector argv_ptrs = build_argv(exePath, argc, argv); launch_with_env(exePath, argv_ptrs, envp); } void launchMainApp(const std::string& exeDir, const std::string& libPath, int argc, char** argv, bool disable_cuda, const std::string& backend_tag, const std::string& ggml_dir, const std::string& llama_device); struct BackendOverrideFlags { std::optional cuda; std::optional vulkan; }; BackendOverrideFlags parse_backend_overrides(int argc, char* argv[]) { BackendOverrideFlags overrides; for (int i = 1; i < argc; ++i) { const std::string arg = argv[i] ? argv[i] : ""; if (arg.rfind("--cuda=", 0) == 0) { overrides.cuda = (arg.substr(7) == "on"); } else if (arg.rfind("--vulkan=", 0) == 0) { overrides.vulkan = (arg.substr(9) == "on"); } } return overrides; } bool validate_overrides(const BackendOverrideFlags& overrides) { if (overrides.cuda.has_value() && overrides.vulkan.has_value() && overrides.cuda.value() && overrides.vulkan.value()) { std::cerr << "Cannot force both CUDA and Vulkan simultaneously." << std::endl; return false; } return true; } struct BackendState { bool cuda_available{false}; bool vulkan_available{false}; BackendSelection selection{BackendSelection::Cpu}; std::string ggml_subdir; std::string backend_tag{"cpu"}; std::string llama_device; }; BackendState decide_backend(const BackendOverrideFlags& overrides, const std::string& baseLibDir) { BackendState state; state.cuda_available = isCudaInstalled(); state.vulkan_available = isVulkanAvailable(); bool useCuda = state.cuda_available; bool useVulkan = !useCuda && state.vulkan_available; if (overrides.cuda.has_value()) { useCuda = overrides.cuda.value(); if (useCuda && !state.cuda_available) { std::cerr << "Warning: CUDA forced but not detected; falling back." << std::endl; useCuda = false; } } if (overrides.vulkan.has_value()) { useVulkan = overrides.vulkan.value(); if (useVulkan && !state.vulkan_available) { std::cerr << "Warning: Vulkan forced but not detected; falling back." << std::endl; useVulkan = false; } } if (useCuda && useVulkan) { useVulkan = false; // CUDA has priority } if (useCuda) { state.selection = BackendSelection::Cuda; state.ggml_subdir = baseLibDir + "/ggml/wcuda"; state.backend_tag = "cuda"; state.llama_device = "cuda"; std::cout << "Using CUDA backend." << std::endl; } else if (useVulkan) { state.selection = BackendSelection::Vulkan; state.ggml_subdir = baseLibDir + "/ggml/wvulkan"; state.backend_tag = "vulkan"; state.llama_device = "vulkan"; std::cout << "Using Vulkan backend." << std::endl; } else { state.selection = BackendSelection::Cpu; state.ggml_subdir = baseLibDir + "/ggml/wocuda"; state.backend_tag = "cpu"; state.llama_device.clear(); std::cout << "Using CPU backend." << std::endl; } return state; } int main(int argc, char* argv[]) { const std::string exeDir = getExecutableDirectory(); const std::string baseLibDir = exeDir + "/lib"; BackendOverrideFlags overrides = parse_backend_overrides(argc, argv); if (!validate_overrides(overrides)) { return EXIT_FAILURE; } BackendState backend = decide_backend(overrides, baseLibDir); const std::string fullLdPath = backend.ggml_subdir + ":" + baseLibDir; const bool disableCudaEnv = (backend.selection != BackendSelection::Cuda); launchMainApp(exeDir, fullLdPath, argc, argv, disableCudaEnv, QString::fromStdString(backend.backend_tag), QString::fromStdString(backend.ggml_subdir), QString::fromStdString(backend.llama_device)); return EXIT_SUCCESS; } ================================================ FILE: app/startapp_windows.cpp ================================================ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "UpdaterLaunchOptions.hpp" #include #include #ifndef DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 #define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 ((HANDLE)-4) #endif using SetProcessDpiAwarenessContextFn = BOOL (WINAPI *)(HANDLE); using SetProcessDpiAwarenessFn = HRESULT (WINAPI *)(int); // 2 = PROCESS_PER_MONITOR_DPI_AWARE namespace { enum class BackendOverride { None, ForceOn, ForceOff }; enum class BackendSelection { Cpu, Cuda, Vulkan }; BackendOverride parseBackendOverride(QString value) { value = value.trimmed().toLower(); if (value == QLatin1String("on")) { return BackendOverride::ForceOn; } if (value == QLatin1String("off")) { return BackendOverride::ForceOff; } return BackendOverride::None; } bool enableSecureDllSearch() { #if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0602 return SetDefaultDllDirectories(LOAD_LIBRARY_SEARCH_DEFAULT_DIRS) != 0; #else // Only available on Windows 7+ with KB2533623. Try to enable if present. typedef BOOL (WINAPI *SetDefaultDllDirectoriesFunc)(DWORD); if (const HMODULE kernel32 = GetModuleHandleW(L"kernel32.dll")) { if (const auto fn = reinterpret_cast( GetProcAddress(kernel32, "SetDefaultDllDirectories"))) { return fn(LOAD_LIBRARY_SEARCH_DEFAULT_DIRS) != 0; } } return false; #endif } void addDllDirectoryChecked(const QString& directory) { if (directory.isEmpty()) { return; } const std::wstring wideDir = QDir::toNativeSeparators(directory).toStdWString(); if (AddDllDirectory(wideDir.c_str()) == nullptr) { qWarning().noquote() << "AddDllDirectory failed for" << QDir::toNativeSeparators(directory) << "- error" << GetLastError(); } else { qInfo().noquote() << "Registered DLL directory" << QDir::toNativeSeparators(directory); } } bool tryLoadLibrary(const QString& name) { QLibrary lib(name); const bool loaded = lib.load(); if (loaded) { lib.unload(); } return loaded; } QStringList candidateGgmlDirectories(const QString& exeDir, const QString& variant) { QStringList candidates; candidates << QDir(exeDir).filePath(QStringLiteral("lib/ggml/%1").arg(variant)); candidates << QDir(exeDir).filePath(QStringLiteral("ggml/%1").arg(variant)); return candidates; } const QList& knownCudaRuntimeVersions() { static const QList versions = { 75, 80, 90, 91, 92, // CUDA 7.5–9.2 100, 101, 102, // CUDA 10.x 110, 111, 112, 113, 114, 115, 116, 117, 118, // CUDA 11.x variants 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130 // CUDA 12.x variants }; return versions; } const QList& requiredCudaRuntimeVersions() { static const QList versions = { 120 }; // keep in sync with build script (CUDA 12.x) return versions; } bool isCudaRuntimePresent(const QList& versions, QString *loadedRuntime = nullptr) { for (int version : versions) { const QString runtime = QStringLiteral("cudart64_%1").arg(version); if (tryLoadLibrary(runtime)) { if (loadedRuntime) { *loadedRuntime = runtime; } return true; } } return false; } bool isCudaAvailable(QString *loadedRuntime = nullptr) { return isCudaRuntimePresent(knownCudaRuntimeVersions(), loadedRuntime); } bool isRequiredCudaRuntimePresent(QString *loadedRuntime = nullptr) { return isCudaRuntimePresent(requiredCudaRuntimeVersions(), loadedRuntime); } bool loadVulkanLibrary(const QString& path) { const std::wstring native = QDir::toNativeSeparators(path).toStdWString(); HMODULE module = LoadLibraryW(native.c_str()); if (!module) { return false; } FreeLibrary(module); return true; } bool isVulkanRuntimeAvailable(const QString& exeDir) { if (loadVulkanLibrary(QStringLiteral("vulkan-1.dll"))) { qInfo().noquote() << "Detected system Vulkan runtime via PATH."; return true; } const QStringList bundledCandidates = { QDir(exeDir).filePath(QStringLiteral("lib/precompiled/vulkan/bin/vulkan-1.dll")), }; QStringList ggmlCandidates = candidateGgmlDirectories(exeDir, QStringLiteral("wvulkan")); for (QString& root : ggmlCandidates) { root = QDir(root).filePath(QStringLiteral("vulkan-1.dll")); } for (const QString& candidate : bundledCandidates + ggmlCandidates) { if (QFileInfo::exists(candidate)) { qInfo().noquote() << "Detected bundled Vulkan runtime at" << QDir::toNativeSeparators(candidate); return true; } } return false; } bool isNvidiaDriverAvailable() { static const QStringList driverCandidates = { QStringLiteral("nvml"), QStringLiteral("nvcuda"), QStringLiteral("nvapi64") }; for (const QString& dll : driverCandidates) { if (tryLoadLibrary(dll)) { return true; } } return false; } void appendToProcessPath(const QString& directory) { if (directory.isEmpty()) { return; } QByteArray path = qgetenv("PATH"); if (!path.isEmpty()) { path.append(';'); } path.append(QDir::toNativeSeparators(directory).toUtf8()); qputenv("PATH", path); qInfo().noquote() << "Added to PATH:" << QDir::toNativeSeparators(directory); qInfo().noquote() << "Current PATH:" << QString::fromUtf8(qgetenv("PATH")); } bool promptCudaDownload() { const auto response = QMessageBox::warning( nullptr, QObject::tr("CUDA Toolkit Missing"), QObject::tr("A compatible NVIDIA GPU was detected, but the CUDA Toolkit is missing.\n\n" "CUDA is required for GPU acceleration in this application.\n\n" "Would you like to download and install it now?"), QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Ok); if (response == QMessageBox::Ok) { QDesktopServices::openUrl(QUrl(QStringLiteral("https://developer.nvidia.com/cuda-downloads"))); return true; } return false; } bool launchMainExecutable(const QString& executablePath, const QStringList& arguments, bool disableCuda, const QString& backendTag, const QString& ggmlDir, const QString& llamaDevice, const QProcessEnvironment& extraEnvironment) { QFileInfo exeInfo(executablePath); if (!exeInfo.exists()) { return false; } QProcessEnvironment environment = QProcessEnvironment::systemEnvironment(); environment.insert(QStringLiteral("PATH"), QString::fromUtf8(qgetenv("PATH"))); environment.insert(QStringLiteral("GGML_DISABLE_CUDA"), disableCuda ? QStringLiteral("1") : QStringLiteral("0")); environment.insert(QStringLiteral("AI_FILE_SORTER_GPU_BACKEND"), backendTag); environment.insert(QStringLiteral("AI_FILE_SORTER_GGML_DIR"), ggmlDir); environment.insert(QStringLiteral("LLAMA_ARG_DEVICE"), llamaDevice); for (const QString& key : extraEnvironment.keys()) { environment.insert(key, extraEnvironment.value(key)); } QProcess process; process.setProcessEnvironment(environment); process.setProgram(executablePath); process.setArguments(arguments); process.setWorkingDirectory(exeInfo.absolutePath()); return process.startDetached(); } QString resolveExecutableName(const QString& baseDir) { const QStringList candidates = { QStringLiteral("aifilesorter.exe"), QStringLiteral("AI File Sorter.exe") }; for (const QString& candidate : candidates) { const QString fullPath = QDir(baseDir).filePath(candidate); if (QFileInfo::exists(fullPath)) { return fullPath; } } return QDir(baseDir).filePath(candidates.front()); } struct BackendOverrides { BackendOverride cuda{BackendOverride::None}; BackendOverride vulkan{BackendOverride::None}; QStringList observedArgs; }; struct UpdaterLiveTestArgs { bool enabled{false}; QString installerUrl; QString installerSha256; QString currentVersion; QString minVersion; }; struct BackendAvailability { bool hasNvidiaDriver{false}; bool cudaRuntimeDetected{false}; bool runtimeCompatible{false}; bool cudaAvailable{false}; bool vulkanAvailable{false}; bool cudaInitiallyAvailable{false}; bool vulkanInitiallyAvailable{false}; QString detectedCudaRuntime; }; BackendOverrides parse_backend_overrides(int argc, char* argv[]) { BackendOverrides overrides; for (int i = 1; i < argc; ++i) { const QString arg = QString::fromLocal8Bit(argv[i]); overrides.observedArgs << arg; if (arg.startsWith(QStringLiteral("--cuda="))) { overrides.cuda = parseBackendOverride(arg.mid(7)); } else if (arg.startsWith(QStringLiteral("--vulkan="))) { overrides.vulkan = parseBackendOverride(arg.mid(9)); } } return overrides; } bool consume_flag_value(const QString& argument, const char* prefix, QString& target) { const QString prefix_text = QString::fromLatin1(prefix); if (!argument.startsWith(prefix_text)) { return false; } target = argument.mid(prefix_text.size()); return true; } UpdaterLiveTestArgs parse_updater_live_test_args(int argc, char* argv[]) { UpdaterLiveTestArgs args; for (int i = 1; i < argc; ++i) { const QString argument = QString::fromLocal8Bit(argv[i]); if (argument == QLatin1String(UpdaterLaunchOptions::kLiveTestFlag)) { args.enabled = true; continue; } if (consume_flag_value(argument, UpdaterLaunchOptions::kLiveTestUrlFlag, args.installerUrl)) { continue; } if (consume_flag_value(argument, UpdaterLaunchOptions::kLiveTestSha256Flag, args.installerSha256)) { continue; } if (consume_flag_value(argument, UpdaterLaunchOptions::kLiveTestVersionFlag, args.currentVersion)) { continue; } if (consume_flag_value(argument, UpdaterLaunchOptions::kLiveTestMinVersionFlag, args.minVersion)) { continue; } } return args; } QProcessEnvironment build_updater_live_test_environment(const UpdaterLiveTestArgs& args) { QProcessEnvironment environment; if (!args.enabled) { return environment; } environment.insert(QString::fromLatin1(UpdaterLaunchOptions::kLiveTestModeEnv), QStringLiteral("1")); if (!args.installerUrl.isEmpty()) { environment.insert(QString::fromLatin1(UpdaterLaunchOptions::kLiveTestUrlEnv), args.installerUrl); } if (!args.installerSha256.isEmpty()) { environment.insert(QString::fromLatin1(UpdaterLaunchOptions::kLiveTestSha256Env), args.installerSha256); } if (!args.currentVersion.isEmpty()) { environment.insert(QString::fromLatin1(UpdaterLaunchOptions::kLiveTestVersionEnv), args.currentVersion); } if (!args.minVersion.isEmpty()) { environment.insert(QString::fromLatin1(UpdaterLaunchOptions::kLiveTestMinVersionEnv), args.minVersion); } return environment; } void log_observed_arguments(const QStringList& args) { if (args.isEmpty()) { return; } qInfo().noquote() << "Starter arguments:" << args.join(QLatin1Char(' ')); } bool maybe_prompt_cuda_download(const BackendOverrides& overrides, const BackendAvailability& availability) { if (!availability.hasNvidiaDriver) { return false; } const bool runtimeMissing = !availability.cudaRuntimeDetected; const bool runtimeIncompatible = availability.cudaRuntimeDetected && !availability.runtimeCompatible; if (!runtimeMissing && !runtimeIncompatible) { return false; } if (overrides.cuda == BackendOverride::ForceOff) { return false; } const bool cudaRequested = overrides.cuda == BackendOverride::ForceOn; const bool vulkanUnavailable = !availability.vulkanAvailable; if (!cudaRequested && !vulkanUnavailable) { return false; } return promptCudaDownload(); } bool validate_override_conflict(const BackendOverrides& overrides) { if (overrides.cuda == BackendOverride::ForceOn && overrides.vulkan == BackendOverride::ForceOn) { QMessageBox::critical(nullptr, QObject::tr("Launch Error"), QObject::tr("Cannot enable both CUDA and Vulkan simultaneously.")); return false; } return true; } BackendAvailability detect_backend_availability(const QString& exeDir, bool hasNvidiaDriver, bool cudaRuntimeDetected, const QString& detectedRuntimeName) { BackendAvailability availability; availability.hasNvidiaDriver = hasNvidiaDriver; availability.cudaRuntimeDetected = cudaRuntimeDetected; QString compatibleRuntime; availability.runtimeCompatible = isRequiredCudaRuntimePresent(&compatibleRuntime); availability.detectedCudaRuntime = availability.runtimeCompatible ? compatibleRuntime : detectedRuntimeName; availability.cudaAvailable = availability.runtimeCompatible && hasNvidiaDriver; availability.vulkanAvailable = isVulkanRuntimeAvailable(exeDir); availability.cudaInitiallyAvailable = availability.cudaAvailable; availability.vulkanInitiallyAvailable = availability.vulkanAvailable; if (hasNvidiaDriver && cudaRuntimeDetected && !availability.runtimeCompatible) { const QString requiredRuntime = QStringLiteral("cudart64_%1.dll").arg(requiredCudaRuntimeVersions().constFirst()); qWarning().noquote() << "Detected CUDA runtime" << (availability.detectedCudaRuntime.isEmpty() ? QStringLiteral("") : availability.detectedCudaRuntime) << "but the bundled GGML build requires" << requiredRuntime << "." << "Falling back to alternate backend."; } return availability; } void apply_override_flags(const BackendOverrides& overrides, BackendAvailability& availability) { if (overrides.cuda == BackendOverride::ForceOff) { availability.cudaAvailable = false; qInfo().noquote() << "CUDA manually disabled via --cuda=off."; } if (overrides.vulkan == BackendOverride::ForceOff) { availability.vulkanAvailable = false; qInfo().noquote() << "Vulkan manually disabled via --vulkan=off."; } } BackendSelection resolve_backend_selection(const BackendOverrides& overrides, const BackendAvailability& availability) { BackendSelection selection = BackendSelection::Cpu; if (overrides.vulkan == BackendOverride::ForceOn) { if (availability.vulkanAvailable) { return BackendSelection::Vulkan; } qWarning().noquote() << "Vulkan forced but not detected; ignoring request."; } if (overrides.cuda == BackendOverride::ForceOn) { if (availability.cudaAvailable) { return BackendSelection::Cuda; } qWarning().noquote() << "CUDA forced but not detected; ignoring request."; } if (availability.vulkanAvailable) { return BackendSelection::Vulkan; } if (availability.cudaAvailable) { return BackendSelection::Cuda; } return selection; } QString incompatible_runtime_message(const BackendAvailability& availability) { if (availability.cudaRuntimeDetected && !availability.runtimeCompatible) { return QStringLiteral("CUDA runtime ignored due to incompatibility; using CPU backend."); } return QStringLiteral("No GPU runtime detected; using CPU backend."); } QString cpu_backend_message(const BackendAvailability& availability) { if (!availability.cudaAvailable && !availability.vulkanAvailable) { return incompatible_runtime_message(availability); } if (availability.cudaInitiallyAvailable && !availability.cudaAvailable) { return QStringLiteral("CUDA runtime ignored due to override; using CPU backend."); } if (availability.vulkanInitiallyAvailable && !availability.vulkanAvailable) { return QStringLiteral("Vulkan runtime ignored due to override; using CPU backend."); } return QStringLiteral("CUDA and Vulkan explicitly disabled; using CPU backend."); } void enable_per_monitor_dpi_awareness() { HMODULE user32 = GetModuleHandleW(L"user32.dll"); if (user32) { const auto set_ctx = reinterpret_cast( GetProcAddress(user32, "SetProcessDpiAwarenessContext")); if (set_ctx && set_ctx(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2)) { return; } } HMODULE shcore = LoadLibraryW(L"Shcore.dll"); if (shcore) { const auto set_awareness = reinterpret_cast( GetProcAddress(shcore, "SetProcessDpiAwareness")); if (set_awareness) { set_awareness(2); // PROCESS_PER_MONITOR_DPI_AWARE } FreeLibrary(shcore); } } void log_runtime_availability(const BackendAvailability& availability, BackendSelection selection) { const QString availabilityLine = QStringLiteral("Runtime availability: CUDA=%1 Vulkan=%2") .arg(availability.cudaInitiallyAvailable ? QStringLiteral("yes") : QStringLiteral("no")) .arg(availability.vulkanInitiallyAvailable ? QStringLiteral("yes") : QStringLiteral("no")); qInfo().noquote() << availabilityLine; switch (selection) { case BackendSelection::Vulkan: qInfo().noquote() << "Backend selection: Vulkan (priority order Vulkan → CUDA → CPU)."; break; case BackendSelection::Cuda: qInfo().noquote() << "Backend selection: CUDA (Vulkan unavailable)."; break; case BackendSelection::Cpu: default: qInfo().noquote() << cpu_backend_message(availability); break; } } QString ggml_variant_for_selection(BackendSelection selection) { switch (selection) { case BackendSelection::Cuda: return QStringLiteral("wcuda"); case BackendSelection::Vulkan: return QStringLiteral("wvulkan"); case BackendSelection::Cpu: default: return QStringLiteral("wocuda"); } } QString resolve_ggml_directory(const QString& exeDir, const QString& variant, bool showError = true) { const QStringList candidates = candidateGgmlDirectories(exeDir, variant); for (const QString& candidate : candidates) { if (QDir(candidate).exists()) { if (candidate != candidates.front()) { qInfo().noquote() << "Primary GGML directory missing; using fallback" << QDir::toNativeSeparators(candidate); } return candidate; } } if (showError) { QMessageBox::critical( nullptr, QObject::tr("Missing GGML Runtime"), QObject::tr("Could not locate the backend runtime DLLs.\nTried:\n%1\n%2") .arg(QDir::toNativeSeparators(candidates.value(0)), QDir::toNativeSeparators(candidates.value(1)))); } return QString(); } void configure_runtime_paths(const QString& exeDir, const QString& ggmlPath, bool secureSearchEnabled, bool useCuda, bool useVulkan) { appendToProcessPath(ggmlPath); if (secureSearchEnabled) { addDllDirectoryChecked(ggmlPath); } QStringList additionalDllRoots; additionalDllRoots << QDir(exeDir).filePath(QStringLiteral("lib/precompiled/cpu/bin")); if (useCuda) { additionalDllRoots << QDir(exeDir).filePath(QStringLiteral("lib/precompiled/cuda/bin")); } if (useVulkan) { additionalDllRoots << QDir(exeDir).filePath(QStringLiteral("lib/precompiled/vulkan/bin")); } additionalDllRoots << QDir(exeDir).filePath(QStringLiteral("bin")); additionalDllRoots << exeDir; for (const QString& dir : additionalDllRoots) { if (!QDir(dir).exists()) { continue; } appendToProcessPath(dir); if (secureSearchEnabled) { addDllDirectoryChecked(dir); } } } QStringList build_forwarded_args(int argc, char* argv[], bool &console_log_flag) { QStringList forwardedArgs; console_log_flag = false; for (int i = 1; i < argc; ++i) { const QString arg = QString::fromLocal8Bit(argv[i]); if (arg == QStringLiteral("--console-log")) { console_log_flag = true; } forwardedArgs.append(arg); } forwardedArgs.prepend(QStringLiteral("--allow-direct-launch")); if (console_log_flag && !forwardedArgs.contains(QStringLiteral("--console-log"))) { forwardedArgs.append(QStringLiteral("--console-log")); } return forwardedArgs; } QString backend_tag_for_selection(BackendSelection selection) { switch (selection) { case BackendSelection::Cuda: return QStringLiteral("cuda"); case BackendSelection::Vulkan: return QStringLiteral("vulkan"); case BackendSelection::Cpu: default: return QStringLiteral("cpu"); } } QString llama_device_for_selection(BackendSelection selection) { switch (selection) { case BackendSelection::Cuda: return QStringLiteral("cuda"); case BackendSelection::Vulkan: return QStringLiteral("vulkan"); case BackendSelection::Cpu: default: return QString(); } } bool launch_main_process(const QString& mainExecutable, const QStringList& forwardedArgs, BackendSelection selection, const QString& ggmlPath, const UpdaterLiveTestArgs& updaterLiveTest) { const bool disableCudaEnv = (selection != BackendSelection::Cuda); const QString backendTag = backend_tag_for_selection(selection); const QString llamaDevice = llama_device_for_selection(selection); if (!launchMainExecutable(mainExecutable, forwardedArgs, disableCudaEnv, backendTag, ggmlPath, llamaDevice, build_updater_live_test_environment(updaterLiveTest))) { QMessageBox::critical(nullptr, QObject::tr("Launch Failed"), QObject::tr("Failed to launch the main application executable:\n%1").arg(mainExecutable)); return false; } return true; } } // namespace int main(int argc, char* argv[]) { enable_per_monitor_dpi_awareness(); QApplication app(argc, argv); app.setQuitOnLastWindowClosed(false); const QString exeDir = QCoreApplication::applicationDirPath(); QDir::setCurrent(exeDir); QString detectedCudaRuntime; const bool cudaRuntimeDetected = isCudaAvailable(&detectedCudaRuntime); const bool hasNvidiaDriver = isNvidiaDriverAvailable(); const bool secureSearchEnabled = enableSecureDllSearch(); if (!secureSearchEnabled) { qWarning() << "SetDefaultDllDirectories unavailable; relying on PATH order for DLL resolution."; } BackendOverrides overrides = parse_backend_overrides(argc, argv); const UpdaterLiveTestArgs updaterLiveTest = parse_updater_live_test_args(argc, argv); log_observed_arguments(overrides.observedArgs); if (!validate_override_conflict(overrides)) { return EXIT_FAILURE; } BackendAvailability availability = detect_backend_availability(exeDir, hasNvidiaDriver, cudaRuntimeDetected, detectedCudaRuntime); apply_override_flags(overrides, availability); if (maybe_prompt_cuda_download(overrides, availability)) { return EXIT_SUCCESS; } BackendSelection selection = resolve_backend_selection(overrides, availability); QString ggmlVariant = ggml_variant_for_selection(selection); QString ggmlPath = resolve_ggml_directory(exeDir, ggmlVariant, /*showError=*/false); if (ggmlPath.isEmpty()) { qWarning().noquote() << "Backend runtime directory missing for selection" << ggmlVariant << "- attempting fallback."; BackendSelection fallbackSelection = BackendSelection::Cpu; if (selection == BackendSelection::Vulkan && availability.cudaAvailable) { fallbackSelection = BackendSelection::Cuda; } else if (selection == BackendSelection::Cuda && availability.vulkanAvailable) { fallbackSelection = BackendSelection::Vulkan; } if (fallbackSelection != selection) { qInfo().noquote() << "Falling back to backend" << backend_tag_for_selection(fallbackSelection) << "due to missing runtime directory."; selection = fallbackSelection; ggmlVariant = ggml_variant_for_selection(selection); } else { qInfo().noquote() << "Falling back to CPU backend."; selection = BackendSelection::Cpu; ggmlVariant = ggml_variant_for_selection(selection); } ggmlPath = resolve_ggml_directory(exeDir, ggmlVariant, /*showError=*/true); if (ggmlPath.isEmpty()) { return EXIT_FAILURE; } } log_runtime_availability(availability, selection); const bool useCuda = (selection == BackendSelection::Cuda); const bool useVulkan = (selection == BackendSelection::Vulkan); configure_runtime_paths(exeDir, ggmlPath, secureSearchEnabled, useCuda, useVulkan); bool console_log_flag = false; QStringList forwardedArgs = build_forwarded_args(argc, argv, console_log_flag); if (console_log_flag) { AttachConsole(ATTACH_PARENT_PROCESS); FILE* f = nullptr; freopen_s(&f, "CONOUT$", "w", stdout); freopen_s(&f, "CONOUT$", "w", stderr); freopen_s(&f, "CONIN$", "r", stdin); } const QString mainExecutable = resolveExecutableName(exeDir); if (!launch_main_process(mainExecutable, forwardedArgs, selection, ggmlPath, updaterLiveTest)) { return EXIT_FAILURE; } return EXIT_SUCCESS; } ================================================ FILE: app/vcpkg.json ================================================ { "name": "ai-file-sorter", "version-string": "0.1.0", "description": "AI File Sorter (Qt6) - Windows build dependencies", "builtin-baseline": "3b9d086009cc1c2256e9c28ad44a00036fbd9b26", "dependencies": [ "qtbase", "qttools", "curl", "jsoncpp", "sqlite3", "openssl", "zlib", "fmt", "spdlog", "gettext", "libmediainfo" ] } ================================================ FILE: external/README-doc-deps.md ================================================ # Vendored document-analysis dependencies This repo vendors the following dependencies for embedded document extraction: - libzip (ZIP container access) - pugixml (XML parsing) - PDFium (PDF text extraction) Use `app/scripts/vendor_doc_deps.sh` (or `app/scripts/vendor_doc_deps.ps1` on Windows) to download and populate `external/`. The script also stages third-party license files under `external/THIRD_PARTY_LICENSES`. Commit the populated directories for release builds (Linux/Windows/macOS ARM). ================================================ FILE: external/THIRD_PARTY_LICENSES/libzip-LICENSE ================================================ Copyright (C) 1999-2020 Dieter Baron and Thomas Klausner The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: external/THIRD_PARTY_LICENSES/pdfium-LICENSE ================================================ Copyright 2014-2025 Benoit Blanchon Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. This package also includes third-party software. See the licenses/ directory for their respective licenses. ================================================ FILE: external/THIRD_PARTY_LICENSES/pugixml-LICENSE.md ================================================ MIT License Copyright (c) 2006-2025 Arseny Kapoulkine Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: external/libzip/.clang-format ================================================ BasedOnStyle: LLVM IndentWidth: 4 ColumnLimit: 2000 AlwaysBreakAfterReturnType: TopLevelDefinitions KeepEmptyLinesAtTheStartOfBlocks: false MaxEmptyLinesToKeep: 2 BreakBeforeBraces: Custom BraceWrapping: BeforeElse: true AlignEscapedNewlines: Left UseTab: Never #PPDirectiveIndentStyle: AfterHash ================================================ FILE: external/libzip/.github/ISSUE_TEMPLATE/bug-report.md ================================================ --- name: Bug Report about: Report where libzip didn't behave like you expected. title: '' labels: bug assignees: '' --- **Describe the Bug** A clear and concise description of what the bug is. **Expected Behavior** A clear and concise description of what you expected to happen. **Observed Behavior** A clear and concise description of what actually happened. **To Reproduce** Short program or code snippet that reproduces the problem. **libzip Version** Version of libzip or revision repository used. **Operating System** Operating system and version, used compiler. **Test Files** If applicable, attach and describe zip archives that trigger the problem. **Additional context** Add any other context about the problem here. ================================================ FILE: external/libzip/.github/ISSUE_TEMPLATE/compile-error.md ================================================ --- name: Compile Error about: Report when libzip does not compile. title: '' labels: compile assignees: '' --- **Compiler Error** Output from the compiler, including exact and complete error message, file name and line number. **libzip Version** Version of libzip or revision repository used. **Operating System and Compiler** The operating system and compiler used, including version number. Also, any flags passed to `cmake`. **Autodetected Configuration** Attach `CmakeCache.txt` from your build directory. This list everything `cmake` detected on your system. **Additional context** Add any other context about the problem here. ================================================ FILE: external/libzip/.github/ISSUE_TEMPLATE/feature-request.md ================================================ --- name: Feature Request about: Suggest an idea for this project. title: '' labels: enhancement assignees: '' --- **Description** A clear and concise description of what you want to achieve, why the current features are insufficient, and why you think it is generally useful. Also, have you checked whether the feature is already mentioned in TODO.md? If so, only submit a new issue if you expand on it. **Solution** A clear and concise description of what you want to happen. **Describe alternatives you've considered** A clear and concise description of any alternative solutions or features you've considered. **Additional context** Add any other context about the feature request here. ================================================ FILE: external/libzip/.github/ISSUE_TEMPLATE/other.md ================================================ --- name: Other about: If you have a question about libzip , consider using Discussions instead. title: '' labels: '' assignees: '' --- ================================================ FILE: external/libzip/.github/workflows/CIFuzz.yml ================================================ name: CIFuzz on: [pull_request] permissions: contents: read jobs: Fuzzing: runs-on: ubuntu-latest steps: - name: Build Fuzzers uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master with: oss-fuzz-project-name: 'libzip' dry-run: false - name: Run Fuzzers uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master with: oss-fuzz-project-name: 'libzip' fuzz-seconds: 600 dry-run: false - name: Upload Crash uses: actions/upload-artifact@v4 if: failure() with: name: artifacts path: ./out/artifacts ================================================ FILE: external/libzip/.github/workflows/bsd.yml ================================================ name: BSD on: [push] permissions: contents: read jobs: NetBSD: runs-on: ubuntu-latest steps: - name: checkout uses: actions/checkout@v4 - name: NetBSD test uses: vmactions/netbsd-vm@v1 with: usesh: true copyback: false prepare: | /usr/sbin/pkg_add cmake zstd py313-pip /usr/pkg/bin/pip-3.13 install nihtest # https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/workflow-commands-for-github-actions#adding-a-system-path echo "/usr/pkg/bin" >> "$GITHUB_PATH" run: | cmake -E make_directory ${{runner.workspace}}/build cmake ${{ matrix.cmake_extra }} ${{github.workspace}} cmake --build . --config Release ctest --output-on-failure -V -C Release ================================================ FILE: external/libzip/.github/workflows/build.yml ================================================ name: build on: [push] permissions: contents: read jobs: all: runs-on: ${{ matrix.os }} name: ${{ matrix.os }}${{ matrix.name_extra }} strategy: fail-fast: false matrix: # os: [macos-latest, ubuntu-latest, windows-latest] os: [macos-latest, ubuntu-latest] cmake_extra: [""] name_extra: [""] # include: # - os: windows-latest # cmake_extra: "-T ClangCl" # name_extra: " clang-cl" steps: - name: checkout uses: actions/checkout@v4 - name: install python and pip uses: actions/setup-python@v5 with: python-version: '3.11' - name: install dependencies (Linux) if: ${{ runner.os == 'Linux' }} run: | sudo apt-get install libzstd-dev - name: install latest CMake and Ninja for lukka/run-vcpkg (Windows) if: ${{ runner.os == 'Windows' }} uses: lukka/get-cmake@latest - name: install dependencies (Windows) if: ${{ runner.os == 'Windows' }} uses: lukka/run-vcpkg@v11 with: vcpkgGitCommitId: 2cf957350da28ad032178a974607f59f961217d9 - name: prepare build directory and install nihtest run: | cmake -E make_directory ${{runner.workspace}}/build pip install nihtest - name: configure (Unix) if: ${{ runner.os != 'Windows' }} working-directory: ${{runner.workspace}}/build run: | cmake ${{ matrix.cmake_extra }} ${{github.workspace}} - name: configure (Windows) if: ${{ runner.os == 'Windows' }} working-directory: ${{runner.workspace}}/build run: | cmake ${{ matrix.cmake_extra }} -DCMAKE_TOOLCHAIN_FILE=${{env.VCPKG_ROOT}}/scripts/buildsystems/vcpkg.cmake ${{github.workspace}} - name: build working-directory: ${{runner.workspace}}/build run: | cmake --build . --config Release - name: Archive production artifacts uses: actions/upload-artifact@v4 with: name: regress-directory-${{ matrix.os }}-${{ matrix.name_extra }} path: | ${{runner.workspace}}/build/regress - name: test working-directory: ${{runner.workspace}}/build run: | ctest --output-on-failure -V -C Release ================================================ FILE: external/libzip/.github/workflows/codeql-analysis.yml ================================================ # For most projects, this workflow file will not need changing; you simply need # to commit it to your repository. # # You may wish to alter this file to override the set of languages analyzed, # or to provide custom queries or build logic. name: "CodeQL" on: push: branches: [master] pull_request: # The branches below must be a subset of the branches above branches: [master] schedule: - cron: '0 10 * * 4' permissions: contents: read jobs: analyze: name: Analyze runs-on: ubuntu-latest permissions: actions: read contents: read security-events: write strategy: fail-fast: false matrix: # Override automatic language detection by changing the below list # Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python'] language: ['cpp'] # Learn more... # https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection steps: - name: Checkout repository uses: actions/checkout@v4 with: # We must fetch at least the immediate parents so that if this is # a pull request then we can checkout the head. fetch-depth: 2 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL uses: github/codeql-action/init@v3 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. # By default, queries listed here will override any specified in a config file. # Prefix the list here with "+" to use these queries and those in the config file. # queries: ./path/to/local/query, your-org/your-repo/queries@main # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild uses: github/codeql-action/autobuild@v3 # ℹ️ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines # and modify them (or add more) to build your code if your project # uses a compiled language #- run: | # make bootstrap # make release - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v3 ================================================ FILE: external/libzip/.github/workflows/coverity.yml ================================================ name: Coverity on: schedule: - cron: '0 3 * * 1' # Mondays at 03:00 workflow_dispatch: permissions: contents: read jobs: build: name: Coverity runs-on: ubuntu-latest environment: coverity env: TOKEN: ${{ secrets.COVERITY_TOKEN }} PROJECT: libzip SHORT_PROJECT: libzip EMAIL: wiz@gatalith.at COV_TOOLS: cov-tools COV_RESULTS: cov-int steps: - name: Check Secret run: | [ -n "${{ secrets.COVERITY_TOKEN }}" ] - name: Checkout Code uses: actions/checkout@v4 - name: Install Dependencies run: | sudo apt-get install libzstd-dev - name: Configure run: | cmake -E make_directory ${{runner.workspace}}/build cmake ${{ matrix.cmake_extra }} ${{github.workspace}} - name: Download Coverity run: | wget --quiet https://scan.coverity.com/download/linux64 --post-data "token=$TOKEN&project=$PROJECT" -O "$COV_TOOLS.tar.gz" mkdir "$COV_TOOLS" tar xzf "$COV_TOOLS.tar.gz" --strip 1 -C "$COV_TOOLS" ls -l "$COV_TOOLS" - name: Build with Coverity run: | export PATH="$(pwd)/$COV_TOOLS/bin:$PATH" cov-build --dir $COV_RESULTS make -j ${{steps.cpu-cores.outputs.count}} # Filter out private info sed -E -i 's/TOKEN=([-_A-Za-z0-9]+)/TOKEN=XXX/g' cov-int/build-log.txt - name: Upload build log uses: actions/upload-artifact@v4 with: name: build-log path: cov-int/build-log.txt retention-days: 10 - name: Submit Results run: | tar -czf $SHORT_PROJECT.tgz $COV_RESULTS ls -lh $SHORT_PROJECT.tgz git config --global --add safe.directory "$GITHUB_WORKSPACE" GIT_HASH="$(git rev-parse --short HEAD)" echo "HASH: $GIT_HASH" GIT_DESC="$(git log -n1 --format="%s" $GIT_HASH)" echo "DESC: $GIT_DESC" curl --fail --output curl.log \ --form token=$TOKEN \ --form email=$EMAIL \ --form file=@$SHORT_PROJECT.tgz \ --form version="$GIT_HASH" \ --form description="$GIT_DESC" \ https://scan.coverity.com/builds?project=$PROJECT # If we go over quota, alert the user cat curl.log grep -qv "quota.*reached" curl.log || false ================================================ FILE: external/libzip/API-CHANGES.md ================================================ # libzip API changes This file describes changes in the libzip API and how to adapt your code for them. You can define `ZIP_DISABLE_DEPRECATED` before including `` to hide prototypes for deprecated functions, to find out about functions that might be removed at some point. ## Changed in libzip-1.10.0 ### deprecated `zip_source_zip` and `zip_source_zip_create` These functions were replaced with `zip_source_zip_file` and `zip_source_zip_file_create`. The implicit handling of the flag `ZIP_FL_COMPRESSED` was removed, the flag can now be specified explicitly. If you want to get the compressed data for the whole file, use ```C zip_source_zip_file(za, source_archive, source_index, ZIP_FL_COMPRESSED, 0, -1, NULL) ``` ## Changed in libzip-1.0 ### new type `zip_error_t` Error information is stored in the newly public type `zip_error_t`. Use this to access information about an error, instead of the deprecated functions that operated on two ints. deprecated functions: - `zip_error_get_sys_type()` - `zip_error_get()` - `zip_error_to_str()` - `zip_file_error_get()` See their man pages for instructions on how to replace them. The most common affected use is `zip_open`. The new recommended usage is: ```c int err; if ((za = zip_open(archive, flags, &err)) == NULL) { zip_error_t error; zip_error_init_with_code(&error, err); fprintf(stderr, "can't open zip archive '%s': %s\n", archive, zip_error_strerror(&error)); zip_error_fini(&error); } ``` ### more typedefs The following typedefs have been added for better readability: ```c typedef struct zip zip_t; typedef struct zip_file zip_file_t; typedef struct zip_source zip_source_t; typedef struct zip_stat zip_stat_t; ``` This means you can use "`zip_t`" instead of "`struct zip`", etc. ### torrentzip support removed torrentzip depends on a particular zlib version which is by now quite old. ## Changed in libzip-0.11 ### new type `zip_flags_t` The functions which have flags now use the `zip_flags_t` type for this. All old flags fit; you need only to adapt code if you were saving flags in a local variable. Use `zip_flags_t` for such a variable. This affects: - `zip_fopen()` - `zip_fopen_encrypted()` - `zip_fopen_index()` - `zip_fopen_index_encrypted()` - `zip_get_archive_comment()` - `zip_get_archive_flag()` - `zip_get_num_entries()` - `zip_get_name()` - `zip_name_locate()` - `zip_set_archive_flag()` - `zip_source_zip()` - `zip_stat()` - `zip_stat_index()` #### `ZIP_FL_*`, `ZIP_AFL_*`, `ZIP_STAT_*` are now unsigned constants To match the new `zip_flags_t` type. #### `zip_add()`, `zip_add_dir()` These functions were replaced with `zip_file_add()` and `zip_dir_add()`, respectively, to add a flags argument. #### `zip_rename()`, `zip_replace()` These functions were replaced with `zip_file_rename()` and `zip_file_replace()`, respectively, to add a flags argument. #### `zip_get_file_comment()` This function was replaced with `zip_file_get_comment()`; one argument was promoted from `int` to `zip_uint32_t`, the other is now a `zip_flags_t`. #### `zip_set_file_comment()` This function was replaced with `zip_file_set_comment()`; an argument was promoted from `int` to `zip_uint16_t`, and a `zip_flags_t` argument was added. ### integer type size changes Some argument and return values were not the right size or sign. #### `zip_name_locate()` The return value was `int`, which can be too small. The function now returns `zip_int64_t`. #### `zip_get_num_entries()` The return type is now signed, to allow signaling errors. #### `zip_set_archive_comment()` The last argument changed from `int` to `zip_uint16_t`. ### extra field handling rewritten The `zip_get_file_extra()` and `zip_set_file_extra()` functions were removed. They only worked on the whole extra field set. Instead, you can now set, get, count, and delete each extra field separately, using the functions: - `zip_file_extra_field_delete()` - `zip_file_extra_field_delete_by_id()` - `zip_file_extra_field_get()` - `zip_file_extra_field_get_by_id()` - `zip_file_extra_fields_count()` - `zip_file_extra_fields_count_by_id()` - `zip_file_extra_field_set()` Please read the corresponding man pages for details. ### new functions #### `zip_discard()` The new `zip_discard()` function closes an archive without committing the scheduled changes. #### `zip_set_file_compression()` The new `zip_set_file_compression()` function allows setting compression levels for files. ### argument changes #### file names File names arguments are now allowed to be `NULL` to have an empty file name. This mostly affects `zip_file_add()`, `zip_dir_add()`, and `zip_file_rename()`. For `zip_get_name()`, `zip_file_get_comment()`, and `zip_get_archive_comment()`, if the file name or comment is empty, a string of length 0 is returned. `NULL` is returned for errors only. Previously, `NULL` was returned for empty/unset file names and comments and errors, leaving no way to differentiate between the two. ================================================ FILE: external/libzip/AUTHORS ================================================ Dieter Baron Thomas Klausner ================================================ FILE: external/libzip/CMakeLists.txt ================================================ cmake_minimum_required(VERSION 3.10) list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake) if (${CMAKE_VERSION} VERSION_LESS "3.17.0") list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake-compat) endif() project(libzip VERSION 1.11.4 LANGUAGES C) if(NOT libzip_VERSION_PATCH) set(libzip_VERSION_PATCH 0) endif() option(ENABLE_COMMONCRYPTO "Enable use of CommonCrypto" ON) option(ENABLE_GNUTLS "Enable use of GnuTLS" ON) option(ENABLE_MBEDTLS "Enable use of mbed TLS" ON) option(ENABLE_OPENSSL "Enable use of OpenSSL" ON) option(ENABLE_WINDOWS_CRYPTO "Enable use of Windows cryptography libraries" ON) option(ENABLE_BZIP2 "Enable use of BZip2" ON) option(ENABLE_LZMA "Enable use of LZMA" ON) option(ENABLE_ZSTD "Enable use of Zstandard" ON) option(ENABLE_FDOPEN "Enable zip_fdopen, which is not allowed in Microsoft CRT secure libraries" ON) option(BUILD_TOOLS "Build tools in the src directory (zipcmp, zipmerge, ziptool)" ON) option(BUILD_REGRESS "Build regression tests" ON) option(BUILD_OSSFUZZ "Build fuzzers for ossfuzz" ON) option(BUILD_EXAMPLES "Build examples" ON) option(BUILD_DOC "Build documentation" ON) include(CheckFunctionExists) include(CheckIncludeFiles) include(CheckLibraryExists) include(CheckSymbolExists) include(CheckTypeSize) include(CheckCSourceRuns) include(CheckCSourceCompiles) include(CheckStructHasMember) include(TestBigEndian) include(GNUInstallDirs) if(ENABLE_COMMONCRYPTO) check_include_files(CommonCrypto/CommonCrypto.h COMMONCRYPTO_FOUND) endif() if(ENABLE_GNUTLS) find_package(Nettle 3.0) find_package(GnuTLS) endif() if(ENABLE_MBEDTLS) find_package(MbedTLS 1.0) endif() if(ENABLE_OPENSSL) find_package(OpenSSL) endif() if(WIN32) if(ENABLE_WINDOWS_CRYPTO) set(WINDOWS_CRYPTO_FOUND TRUE) endif() endif() option(BUILD_SHARED_LIBS "Build shared libraries" ON) option(LIBZIP_DO_INSTALL "Install libzip and the related files" ON) option(SHARED_LIB_VERSIONNING "Add SO version in .so build" ON) find_program(MDOCTOOL NAMES mandoc groff) if (MDOCTOOL) set(DOCUMENTATION_FORMAT "mdoc" CACHE STRING "Documentation format") else() find_program(MANTOOL NAMES nroff) if (MANTOOL) set(DOCUMENTATION_FORMAT "man" CACHE STRING "Documentation format") else() set(DOCUMENTATION_FORMAT "html" CACHE STRING "Documentation format") endif() endif() include(Dist) Dist(${CMAKE_PROJECT_NAME}-${CMAKE_PROJECT_VERSION}) #ADD_CUSTOM_TARGET(uninstall # COMMAND cat ${PROJECT_BINARY_DIR}/install_manifest.txt | xargs rm # WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} # ) if(BUILD_SHARED_LIBS) set(HAVE_SHARED TRUE) else() set(ZIP_STATIC TRUE) endif() # Checks # Request ISO C secure library functions (memcpy_s &c) list(APPEND CMAKE_REQUIRED_DEFINITIONS -D__STDC_WANT_LIB_EXT1__=1) check_function_exists(_close HAVE__CLOSE) check_function_exists(_dup HAVE__DUP) check_function_exists(_fdopen HAVE__FDOPEN) check_function_exists(_fileno HAVE__FILENO) check_function_exists(_fseeki64 HAVE__FSEEKI64) check_function_exists(_fstat64 HAVE__FSTAT64) check_function_exists(_setmode HAVE__SETMODE) check_function_exists(_stat64 HAVE__STAT64) check_symbol_exists(_snprintf stdio.h HAVE__SNPRINTF) check_symbol_exists(_snprintf_s stdio.h HAVE__SNPRINTF_S) check_symbol_exists(_snwprintf_s stdio.h HAVE__SNWPRINTF_S) check_function_exists(_strdup HAVE__STRDUP) check_symbol_exists(_stricmp string.h HAVE__STRICMP) check_function_exists(_strtoi64 HAVE__STRTOI64) check_function_exists(_strtoui64 HAVE__STRTOUI64) check_function_exists(_unlink HAVE__UNLINK) check_function_exists(arc4random HAVE_ARC4RANDOM) check_function_exists(clonefile HAVE_CLONEFILE) check_function_exists(explicit_bzero HAVE_EXPLICIT_BZERO) check_function_exists(explicit_memset HAVE_EXPLICIT_MEMSET) check_function_exists(fchmod HAVE_FCHMOD) check_function_exists(fileno HAVE_FILENO) check_function_exists(fseeko HAVE_FSEEKO) check_function_exists(ftello HAVE_FTELLO) check_function_exists(getprogname HAVE_GETPROGNAME) check_function_exists(GetSecurityInfo HAVE_GETSECURITYINFO) check_symbol_exists(localtime_r time.h HAVE_LOCALTIME_R) check_symbol_exists(localtime_s time.h HAVE_LOCALTIME_S) check_function_exists(memcpy_s HAVE_MEMCPY_S) check_function_exists(random HAVE_RANDOM) check_function_exists(setmode HAVE_SETMODE) check_symbol_exists(snprintf stdio.h HAVE_SNPRINTF) check_symbol_exists(snprintf_s stdio.h HAVE_SNPRINTF_S) check_symbol_exists(strcasecmp strings.h HAVE_STRCASECMP) check_function_exists(strdup HAVE_STRDUP) check_function_exists(strerror_s HAVE_STRERROR_S) check_function_exists(strerrorlen_s HAVE_STRERRORLEN_S) check_function_exists(stricmp HAVE_STRICMP) check_function_exists(strncpy_s HAVE_STRNCPY_S) check_function_exists(strtoll HAVE_STRTOLL) check_function_exists(strtoull HAVE_STRTOULL) check_include_files("sys/types.h;sys/stat.h;fts.h" HAVE_FTS_H) # fts functions may be in external library if(HAVE_FTS_H) check_function_exists(fts_open HAVE_FTS_OPEN) if(NOT HAVE_FTS_OPEN) check_library_exists(fts fts_open "" HAVE_LIB_FTS) else(NOT HAVE_FTS_OPEN) set(HAVE_LIB_FTS "" CACHE INTERNAL "") endif(NOT HAVE_FTS_OPEN) else(HAVE_FTS_H) set(HAVE_LIB_FTS "" CACHE INTERNAL "") endif(HAVE_FTS_H) if(HAVE_LIB_FTS) set(FTS_LIB fts CACHE INTERNAL "") else() set(FTS_LIB "" CACHE INTERNAL "") endif() check_include_files(stdbool.h HAVE_STDBOOL_H) check_include_files(strings.h HAVE_STRINGS_H) check_include_files(unistd.h HAVE_UNISTD_H) check_include_files(inttypes.h HAVE_INTTYPES_H_LIBZIP) check_include_files(stdint.h HAVE_STDINT_H_LIBZIP) check_include_files(sys/types.h HAVE_SYS_TYPES_H_LIBZIP) # TODO: fix test # this test does not find __progname even when it exists #check_symbol_exists(__progname stdlib.h HAVE___PROGNAME) check_type_size(__int8 __INT8_LIBZIP) check_type_size(int8_t INT8_T_LIBZIP) check_type_size(uint8_t UINT8_T_LIBZIP) check_type_size(__int16 __INT16_LIBZIP) check_type_size(int16_t INT16_T_LIBZIP) check_type_size(uint16_t UINT16_T_LIBZIP) check_type_size(__int32 __INT32_LIBZIP) check_type_size(int32_t INT32_T_LIBZIP) check_type_size(uint32_t UINT32_T_LIBZIP) check_type_size(__int64 __INT64_LIBZIP) check_type_size(int64_t INT64_T_LIBZIP) check_type_size(uint64_t UINT64_T_LIBZIP) check_type_size("short" SHORT_LIBZIP) check_type_size("int" INT_LIBZIP) check_type_size("long" LONG_LIBZIP) check_type_size("long long" LONG_LONG_LIBZIP) check_type_size("off_t" SIZEOF_OFF_T) check_type_size("size_t" SIZEOF_SIZE_T) check_c_source_compiles("#include #include int main(int argc, char *argv[]) { unsigned long x = FICLONERANGE; }" HAVE_FICLONERANGE) test_big_endian(WORDS_BIGENDIAN) find_package(ZLIB 1.1.2 REQUIRED) # so developers on systems where zlib is named differently (Windows, sometimes) # can override the name used in the pkg-config file if (NOT ZLIB_LINK_LIBRARY_NAME) set(ZLIB_LINK_LIBRARY_NAME "z") # Get the correct name in common cases list(LENGTH ZLIB_LIBRARIES N_ZLIB_LIBRARIES) if(N_ZLIB_LIBRARIES EQUAL 1) set(ZLIB_FILENAME ${ZLIB_LIBRARIES}) elseif(N_ZLIB_LIBRARIES EQUAL 4) # ZLIB_LIBRARIES might have the target_link_library() format like # "optimized;path/to/zlib.lib;debug;path/to/zlibd.lib". Use the 'optimized' # case unless we know we are in a Debug build. if(CMAKE_BUILD_TYPE STREQUAL "Debug") list(FIND ZLIB_LIBRARIES "debug" ZLIB_LIBRARIES_INDEX_OF_CONFIG) else() list(FIND ZLIB_LIBRARIES "optimized" ZLIB_LIBRARIES_INDEX_OF_CONFIG) endif() if(ZLIB_LIBRARIES_INDEX_OF_CONFIG GREATER_EQUAL 0) math(EXPR ZLIB_FILENAME_INDEX "${ZLIB_LIBRARIES_INDEX_OF_CONFIG}+1") list(GET ZLIB_LIBRARIES ${ZLIB_FILENAME_INDEX} ZLIB_FILENAME) endif() endif() if(ZLIB_FILENAME) get_filename_component(ZLIB_FILENAME ${ZLIB_FILENAME} NAME_WE) string(REGEX REPLACE "^lib" "" ZLIB_LINK_LIBRARY_NAME ${ZLIB_FILENAME}) endif() endif(NOT ZLIB_LINK_LIBRARY_NAME) if(ENABLE_BZIP2) find_package(BZip2) if(BZIP2_FOUND) set(HAVE_LIBBZ2 1) else() message(WARNING "-- bzip2 library not found; bzip2 support disabled") endif(BZIP2_FOUND) endif(ENABLE_BZIP2) if(ENABLE_LZMA) find_package(LibLZMA 5.2) if(LIBLZMA_FOUND) set(HAVE_LIBLZMA 1) else() message(WARNING "-- lzma library not found; lzma/xz support disabled") endif(LIBLZMA_FOUND) endif(ENABLE_LZMA) if(ENABLE_ZSTD) find_package(zstd 1.4.0) if(zstd_FOUND) set(HAVE_LIBZSTD 1) if(TARGET zstd::libzstd_shared AND BUILD_SHARED_LIBS) set(zstd_TARGET zstd::libzstd_shared) else() set(zstd_TARGET zstd::libzstd_static) endif() else() message(WARNING "-- zstd library not found; zstandard support disabled") endif(zstd_FOUND) endif(ENABLE_ZSTD) if (COMMONCRYPTO_FOUND) set(HAVE_CRYPTO 1) set(HAVE_COMMONCRYPTO 1) elseif (WINDOWS_CRYPTO_FOUND) set(HAVE_CRYPTO 1) set(HAVE_WINDOWS_CRYPTO 1) elseif (OPENSSL_FOUND) set(HAVE_CRYPTO 1) set(HAVE_OPENSSL 1) elseif (GNUTLS_FOUND AND NETTLE_FOUND) set(HAVE_CRYPTO 1) set(HAVE_GNUTLS 1) elseif (MBEDTLS_FOUND) set(HAVE_CRYPTO 1) set(HAVE_MBEDTLS 1) endif() if ((ENABLE_COMMONCRYPTO OR ENABLE_GNUTLS OR ENABLE_MBEDTLS OR ENABLE_OPENSSL OR ENABLE_WINDOWS_CRYPTO) AND NOT HAVE_CRYPTO) message(WARNING "-- neither Common Crypto, GnuTLS, mbed TLS, OpenSSL, nor Windows Cryptography found; AES support disabled") endif() if(MSVC) add_compile_definitions(_CRT_SECURE_NO_WARNINGS) add_compile_definitions(_CRT_NONSTDC_NO_DEPRECATE) endif(MSVC) if(WIN32) if(CMAKE_SYSTEM_NAME MATCHES WindowsPhone OR CMAKE_SYSTEM_NAME MATCHES WindowsStore) add_compile_definitions(MS_UWP) endif(CMAKE_SYSTEM_NAME MATCHES WindowsPhone OR CMAKE_SYSTEM_NAME MATCHES WindowsStore) endif(WIN32) # rpath handling: use rpath in installed binaries if(NOT CMAKE_SYSTEM_NAME MATCHES Linux) set(CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}) set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) endif() # for code completion frameworks set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # Testing ENABLE_TESTING() # Targets ADD_SUBDIRECTORY(lib) if(BUILD_DOC) ADD_SUBDIRECTORY(man) endif() if(BUILD_TOOLS) ADD_SUBDIRECTORY(src) else(BUILD_TOOLS) if(BUILD_REGRESS) message(WARNING "-- tools build has been disabled, but they are needed for regression tests; regression testing disabled") set(BUILD_REGRESS OFF) endif(BUILD_REGRESS) endif() find_program(NIHTEST nihtest) if(BUILD_REGRESS AND NOT NIHTEST) message(WARNING "-- nihtest not found, regression testing disabled") set(BUILD_REGRESS OFF) endif() if(BUILD_REGRESS) add_subdirectory(regress) endif() if(BUILD_OSSFUZZ) add_subdirectory(ossfuzz) endif() if(BUILD_EXAMPLES) add_subdirectory(examples) endif() # pkgconfig file file(RELATIVE_PATH pc_relative_bindir ${CMAKE_INSTALL_PREFIX} ${CMAKE_INSTALL_FULL_BINDIR}) set(bindir "\${prefix}/${pc_relative_bindir}") file(RELATIVE_PATH pc_relative_libdir ${CMAKE_INSTALL_PREFIX} ${CMAKE_INSTALL_FULL_LIBDIR}) set(libdir "\${prefix}/${pc_relative_libdir}") file(RELATIVE_PATH pc_relative_includedir ${CMAKE_INSTALL_PREFIX} ${CMAKE_INSTALL_FULL_INCLUDEDIR}) set(includedir "\${prefix}/${pc_relative_includedir}") if(CMAKE_SYSTEM_NAME MATCHES BSD) set(PKG_CONFIG_RPATH "-Wl,-R\${libdir}") endif(CMAKE_SYSTEM_NAME MATCHES BSD) get_target_property(LIBS_PRIVATE zip LINK_LIBRARIES) foreach(LIB ${LIBS_PRIVATE}) if(LIB MATCHES "^/") get_filename_component(LIB ${LIB} NAME_WE) string(REGEX REPLACE "^lib" "" LIB ${LIB}) endif() set(LIBS "${LIBS} -l${LIB}") endforeach() STRING(CONCAT zlib_link_name "-l" ${ZLIB_LINK_LIBRARY_NAME}) string(REGEX REPLACE "-lBZip2::BZip2" "-lbz2" LIBS ${LIBS}) string(REGEX REPLACE "-lLibLZMA::LibLZMA" "-llzma" LIBS ${LIBS}) if(zstd_TARGET) string(REGEX REPLACE "-l${zstd_TARGET}" "-lzstd" LIBS ${LIBS}) endif() string(REGEX REPLACE "-lOpenSSL::Crypto" "-lssl -lcrypto" LIBS ${LIBS}) string(REGEX REPLACE "-lZLIB::ZLIB" ${zlib_link_name} LIBS ${LIBS}) string(REGEX REPLACE "-lGnuTLS::GnuTLS" "-lgnutls" LIBS ${LIBS}) string(REGEX REPLACE "-lNettle::Nettle" "-lnettle" LIBS ${LIBS}) configure_file(libzip.pc.in libzip.pc @ONLY) if(LIBZIP_DO_INSTALL) install(FILES ${PROJECT_BINARY_DIR}/libzip.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) endif() # fixed size integral types if(HAVE_INTTYPES_H_LIBZIP) set(LIBZIP_TYPES_INCLUDE "#if !defined(__STDC_FORMAT_MACROS) #define __STDC_FORMAT_MACROS 1 #endif #include ") elseif(HAVE_STDINT_H_LIBZIP) set(LIBZIP_TYPES_INCLUDE "#include ") elseif(HAVE_SYS_TYPES_H_LIBZIP) set(LIBZIP_TYPES_INCLUDE "#include ") endif() if(HAVE_INT8_T_LIBZIP) set(ZIP_INT8_T int8_t) elseif(HAVE___INT8_LIBZIP) set(ZIP_INT8_T __int8) else() set(ZIP_INT8_T "signed char") endif() if(HAVE_UINT8_T_LIBZIP) set(ZIP_UINT8_T uint8_t) elseif(HAVE___INT8_LIBZIP) set(ZIP_UINT8_T "unsigned __int8") else() set(ZIP_UINT8_T "unsigned char") endif() if(HAVE_INT16_T_LIBZIP) set(ZIP_INT16_T int16_t) elseif(HAVE___INT16_LIBZIP) set(INT16_T_LIBZIP __int16) elseif(SHORT_LIBZIP EQUAL 2) set(INT16_T_LIBZIP short) endif() if(HAVE_UINT16_T_LIBZIP) set(ZIP_UINT16_T uint16_t) elseif(HAVE___INT16_LIBZIP) set(UINT16_T_LIBZIP "unsigned __int16") elseif(SHORT_LIBZIP EQUAL 2) set(UINT16_T_LIBZIP "unsigned short") endif() if(HAVE_INT32_T_LIBZIP) set(ZIP_INT32_T int32_t) elseif(HAVE___INT32_LIBZIP) set(ZIP_INT32_T __int32) elseif(INT_LIBZIP EQUAL 4) set(ZIP_INT32_T int) elseif(LONG_LIBZIP EQUAL 4) set(ZIP_INT32_T long) endif() if(HAVE_UINT32_T_LIBZIP) set(ZIP_UINT32_T uint32_t) elseif(HAVE___INT32_LIBZIP) set(ZIP_UINT32_T "unsigned __int32") elseif(INT_LIBZIP EQUAL 4) set(ZIP_UINT32_T "unsigned int") elseif(LONG_LIBZIP EQUAL 4) set(ZIP_UINT32_T "unsigned long") endif() if(HAVE_INT64_T_LIBZIP) set(ZIP_INT64_T int64_t) elseif(HAVE___INT64_LIBZIP) set(ZIP_INT64_T __int64) elseif(LONG_LIBZIP EQUAL 8) set(ZIP_INT64_T long) elseif(LONG_LONG_LIBZIP EQUAL 8) set(ZIP_INT64_T "long long") endif() if(HAVE_UINT64_T_LIBZIP) set(ZIP_UINT64_T uint64_t) elseif(HAVE___INT64_LIBZIP) set(ZIP_UINT64_T "unsigned __int64") elseif(LONG_LIBZIP EQUAL 8) set(ZIP_UINT64_T "unsigned long") elseif(LONG_LONG_LIBZIP EQUAL 8) set(ZIP_UINT64_T "unsigned long long") endif() # write out config file configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${PROJECT_BINARY_DIR}/config.h) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/zipconf.h.in ${PROJECT_BINARY_DIR}/zipconf.h) # for tests set(srcdir ${CMAKE_CURRENT_SOURCE_DIR}/regress) set(abs_srcdir ${CMAKE_CURRENT_SOURCE_DIR}/regress) set(top_builddir ${PROJECT_BINARY_DIR}) # used to find config.h # create package config file include(CMakePackageConfigHelpers) write_basic_package_version_file("${PROJECT_BINARY_DIR}/${PROJECT_NAME}-config-version.cmake" COMPATIBILITY AnyNewerVersion) if(LIBZIP_DO_INSTALL) configure_package_config_file("${PROJECT_NAME}-config.cmake.in" "${PROJECT_BINARY_DIR}/${PROJECT_NAME}-config.cmake" INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/libzip) # Install Find* modules, they are required by libzip-config.cmake to resolve dependencies install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/cmake/FindNettle.cmake ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Findzstd.cmake ${CMAKE_CURRENT_SOURCE_DIR}/cmake/FindMbedTLS.cmake DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/libzip/modules ) # Add targets to the build-tree export set export(TARGETS zip FILE "${PROJECT_BINARY_DIR}/${PROJECT_NAME}-targets.cmake") # installation install(FILES ${PROJECT_BINARY_DIR}/zipconf.h DESTINATION include) install(FILES ${PROJECT_BINARY_DIR}/${PROJECT_NAME}-config.cmake ${PROJECT_BINARY_DIR}/${PROJECT_NAME}-config-version.cmake DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME} ) install(EXPORT ${PROJECT_NAME}-targets NAMESPACE libzip:: FILE ${PROJECT_NAME}-targets.cmake DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME} ) if(BUILD_TOOLS) install(EXPORT ${PROJECT_NAME}-bin-targets NAMESPACE libzip:: FILE ${PROJECT_NAME}-bin-targets.cmake DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME} ) endif() endif() ================================================ FILE: external/libzip/INSTALL.md ================================================ libzip uses [cmake](https://cmake.org) to build. You'll need [zlib](http://www.zlib.net/) (at least version 1.1.2). It comes with most operating systems. For supporting bzip2-compressed zip archives, you need [bzip2](http://bzip.org/). For supporting lzma- and xz-compressed zip archives, you need [liblzma](https://tukaani.org/xz/) which is part of xz, at least version 5.2. For supporting zstd-compressed zip archives, you need [zstd](https://github.com/facebook/zstd/). For AES (encryption) support, you need one of these cryptographic libraries, listed in order of preference: - Apple's CommonCrypto (available on macOS and iOS) - Microsoft Windows Cryptography Framework - [OpenSSL](https://www.openssl.org/) >= 1.0. - [GnuTLS](https://www.gnutls.org/) and [Nettle](https://www.lysator.liu.se/~nisse/nettle/) (at least nettle 3.0) - [mbed TLS](https://tls.mbed.org/) If you don't want a library even if it is installed, you can pass `-DENABLE_=OFF` to cmake, where `` is one of `COMMONCRYPTO`, `GNUTLS`, `MBEDTLS`, or `OPENSSL`. For running the tests, you need to have [Python](https://www.python.org/) and [nihtest](https://pypi.org/project/nihtest/) installed. The basic usage is ```sh mkdir build cd build cmake .. make make test make install ``` Some useful parameters you can pass to `cmake` with `-Dparameter=value`: - `BUILD_SHARED_LIBS`: set to `ON` or `OFF` to enable/disable building of shared libraries, defaults to `ON` - `CMAKE_INSTALL_PREFIX`: for setting the installation path - `DOCUMENTATION_FORMAT`: choose one of `man`, `mdoc`, and `html` for the installed documentation (default: decided by cmake depending on available tools) - `LIBZIP_DO_INSTALL`: If you include libzip as a subproject, link it statically and do not want to let it install its files, set this variable to `OFF`. Defaults to `ON`. If you want to compile with custom `CFLAGS`, set them in the environment before running `cmake`: ```sh CFLAGS=-DMY_CUSTOM_FLAG cmake .. ``` If you are compiling on a system with a small stack size, add `-DZIP_ALLOCATE_BUFFER` to `CFLAGS`. If you are building on a 32-bit Linux system it might be necessary to define `_FILE_OFFSET_BITS` to `64`. Your distro will need to provide a `fts.h` file that is new enough to support this, or the build will break in `zipcmp`. You can get verbose build output with by passing `VERBOSE=1` to `make`. You can also check the [cmake FAQ](https://gitlab.kitware.com/cmake/community/-/wikis/FAQ). ================================================ FILE: external/libzip/LICENSE ================================================ Copyright (C) 1999-2020 Dieter Baron and Thomas Klausner The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: external/libzip/NEWS.md ================================================ # 1.11.4 [2025-05-23] * Use separate cmake package files for library and programs. * Improve documentation. # 1.11.3 [2025-01-20] * Report read error for corrupted encrypted file data. * Avoid unnecessary seeks when writing archive. * Don't hardcode `_Nullable` support in `zip.h` to allow it to be used with different compilers. * Improve check for GetSecurityInformation availability on Windows. # 1.11.2 [2024-10-31] * Fix performance regression in `zip_stat` introduced in 1.11. # 1.11.1 [2024-09-19] * Fix zipconf.h for version number with missing third component. # 1.11 [2024-09-19] * Stop searching after finding acceptable central directory, even if it contains inconsistencies. * Only write Zip64 EOCD if fields don't fit in normal EOCD. Previously libzip also wrote it when any directory entry required Zip64. * Allow bytes from 0x00-0x1F as UTF-8. * Add new error code `ZIP_ER_TRUNCATED_ZIP` for files that start with a valid local header signature. * `zipcmp`: add `-T` option for comparing timestamps. * `zip_file_replace` now removes the target's extra field information. # 1.10.1 [2023-08-23] * Add `ZIP_LENGTH_TO_END` and `ZIP_LENGTH_UNCHECKED`. Unless `ZIP_LENGTH_UNCHECKED` is used as `length`, it is an error for a file to shrink between the time when the source is created and when its data is read. * Fix test on Windows. # 1.10.0 [2023-06-23] * Make support for layered sources public. * Add `zip_source_zip_file` and `zip_source_zip_file_create`, deprecate `zip_source_zip` and `zip_source_zip_create`. * Allow reading changed file data. * Fix handling of files of size 4294967295. * `zipmerge`: copy extra fields. * `zipmerge`: add option to keep files uncompressed. * Switch test framework to use nihtest instead of Perl. * Fix reading/writing compressed data with buffers > 4GiB. * Restore support for torrentzip. * Add warnings when using deprecated functions. * Allow keeping files for empty archives. * Support mbedTLS>=3.3.0. * Support OpenSSL 3. * Use ISO C secure library functions, if available. # 1.9.2 [2022-06-28] * Fix version number in header file. # 1.9.1 [2022-06-28] * Fix `zip_file_is_seekable()`. # 1.9.0 [2022-06-13] * Add `zip_file_is_seekable()`. * Improve compatibility with WinAES. * Fix encoding handling in `zip_name_locate()`. * Add option to `zipcmp` to output summary of changes. * Various bug fixes and documentation improvements. # 1.8.0 [2021-06-18] * Add support for zstd (Zstandard) compression. * Add support for lzma (ID 14) compression. * Add `zip_source_window_create()`. * Add `zip_source_zip_create()` variant to `zip_source_zip()`. * Allow method specific `comp_flags` in `zip_set_file_compression()`. * Allow `zip_source_tell()` on sources that don't support seeking and `zip_ftell()` on compressed data. * Provide more details for consistency check errors. * Improve output of `zipcmp`. * In `zipcmp`, don’t ignore empty directories when comparing directory listing. * Treat empty string as no password given in `zip_file_set_encryption()`, `zip_fopen_encrypted()`, and `zip_set_default_password()`. # 1.7.3 [2020-07-15] * Support cmake < 3.17 again. * Fix pkgconfig file (regression in 1.7.2). # 1.7.2 [2020-07-11] * Fixes for the CMake `find_project()` files. * libzip moved to the CMake `libzip::` `NAMESPACE`. * CMake usage best practice cleanups. # 1.7.1 [2020-06-13] * Restore `LIBZIP_VERSION_{MAJOR,MINOR,MICRO}` symbols. * Fixes warnings reported by PVS-Studio. * Add `LIBZIP_DO_INSTALL` build setting to make it easier to use libzip as subproject. # 1.7.0 [2020-06-05] * Add support for encrypting using traditional PKWare encryption. * Add `zip_compression_method_supported()`. * Add `zip_encryption_method_supported()`. * Add the `ZIP_SOURCE_GET_FILE_ATTRIBUTES` source command. * Refactor stdio file backend. * Add CMake find_project() support. # 1.6.1 [2020-02-03] * Bugfix for double-free in `zipcmp(1)` during cleanup. # 1.6.0 [2020-01-24] * Avoid using `umask()` since it's not thread-safe. * Set close-on-exec flag when opening files. * Do not accept empty files as valid zip archives any longer. * Add support for XZ compressed files (using liblzma). * Add support for cancelling while closing zip archives. * Add support for setting the time in the on-disk format. # 1.5.2 [2019-03-12] * Fix bug in AES encryption affecting certain file sizes * Keep file permissions when modifying zip archives * Support systems with small stack size. * Support mbed TLS as crypto backend. * Add nullability annotations. # 1.5.1 [2018-04-11] * Choose format of installed documentation based on available tools. * Fix visibility of symbols. * Fix zipcmp directory support. * Don't set RPATH on Linux. * Use Libs.private for link dependencies in pkg-config file. * Fix build with LibreSSL. * Various bugfixes. # 1.5.0 [2018-03-11] * Use standard cryptographic library instead of custom AES implementation. This also simplifies the license. * Use `clang-format` to format the source code. * More Windows improvements. # 1.4.0 [2017-12-29] * Improve build with cmake * Retire autoconf/automake build system * Add `zip_source_buffer_fragment()`. * Add support to clone unchanged beginning of archive (instead of rewriting it). Supported for buffer sources and on Apple File System. * Add support for Microsoft Universal Windows Platform. # 1.3.2 [2017-11-20] * Fix bug introduced in last: zip_t was erroneously freed if zip_close() failed. # 1.3.1 [2017-11-19] * Install zipconf.h into ${PREFIX}/include * Add zip_libzip_version() * Fix AES tests on Linux # 1.3.0 [2017-09-02] * Support bzip2 compressed zip archives * Improve file progress callback code * Fix zip_fdopen() * CVE-2017-12858: Fix double free() * CVE-2017-14107: Improve EOCD64 parsing # 1.2.0 [2017-02-19] * Support for AES encryption (Winzip version), both encryption and decryption * Support legacy zip files with >64k entries * Fix seeking in zip_source_file if start > 0 * Add zip_fseek() for seeking in uncompressed data * Add zip_ftell() for telling position in uncompressed data * Add zip_register_progress_callback() for UI updates during zip_close() # 1.1.3 [2016-05-28] * Fix build on Windows when using autoconf # 1.1.2 [2016-02-19] * Improve support for 3MF files # 1.1.1 [2016-02-07] * Build fixes for Linux * Fix some warnings reported by PVS-Studio # 1.1 [2016-01-26] * ziptool(1): command line tool to modify zip archives * Speedups for archives with many entries * Coverity fixes * Better APK support * Support for running tests on Windows * More build fixes for Windows * Portability fixes * Documentation improvements # 1.0.1 [2015-05-04] * Build fixes for Windows # 1.0 [2015-05-03] * Implemented an I/O abstraction layer * Added support for native Windows API for files * Added support for setting the last modification time for a file * Added a new type zip_error_t for errors * Added more typedefs for structs * Torrentzip support was removed * CVE-2015-2331 was fixed * Addressed all Coverity CIDs # 0.11.2 [2013-12-19] * Support querying/setting operating system and external attributes * For newly added files, set operating system to UNIX, permissions to 0666 (0777 for directories) * Fix bug when writing zip archives containing files bigger than 4GB # 0.11.1 [2013-04-27] * Fix bugs in zip_set_file_compression() * Include Xcode build infrastructure # 0.11 [2013-03-23] * Added Zip64 support (large file support) * Added UTF-8 support for file names, file comments, and archive comments * Changed API for name and comment related functions for UTF-8 support * Added zip_discard() * Added ZIP_TRUNCATE for zip_open() * Added zip_set_file_compression() * Added API for accessing and modifying extra fields * Improved API type consistency * Use gcc4's visibility __attribute__ * More changes for Windows support * Additional test cases # 0.10.1 [2012-03-20] * Fixed CVE-2012-1162 * Fixed CVE-2012-1163 # 0.10 [2010-03-18] * Added zip_get_num_entries(), deprecated zip_get_num_files() * Better windows support * Support for traditional PKWARE encryption added * Fix opening archives with more than 65535 entries * Fix some memory leaks * Fix cmake build and installation * Fix memory leak in error case in zip_open() * Fixed CVE-2011-0421 (no security implications though) * More documentation # 0.9.3 [2010-02-01] * Include m4/ directory in distribution; some packagers need it # 0.9.2 [2010-01-31] * Avoid passing uninitialized data to deflate() * Fix memory leak when closing zip archives # 0.9.1 [2010-01-24] * Fix infinite loop on reading some broken files * Optimization in time conversion (don't call localtime()) * Clear data descriptor flag in central directory, fixing Open Office files * Allow more than 64k entries # 0.9 [2008-07-25] * on Windows, explicitly set dllimport/dllexport * remove erroneous references to GPL * add support for torrentzip * new functions: zip_get_archive_flag, zip_set_archive_flag * zip_source_zip: add flag to force recompression * zip_sorce_file: only keep file open while reading from it # 0.8 [2007-06-06] * fix for zip archives larger than 2GiB * fix zip_error_strerror to include libzip error string * add support for reading streamed zip files * new functions: zip_add_dir, zip_error_clear, zip_file_error_clear * add basic support for building with CMake (incomplete) # 0.7.1 [2006-05-18] * bugfix for zip_close # 0.7 [2006-05-06] * struct zip_stat increased for future encryption support * zip_add return value changed (now returns new index of added file) * shared library major bump because of previous two * added functions for reading and writing file and archive comments New functions: zip_get_archive_comment, zip_get_file_comment, zip_set_archive_comment, zip_set_file_comment, zip_unchange_archive # 0.6.1 [2005-07-14] * various bug fixes # 0.6 [2005-06-09] * first standalone release * changed license to three-clause BSD * overhauled API * added man pages * install zipcmp and zipmerge ================================================ FILE: external/libzip/README.md ================================================ # libzip ## A C Library for Reading, Creating, and Modifying Zip Archives ## Why Use libzip? libzip has been continuously developed since 2005. It is efficient, small, and flexible. It is usable on Linux, macOS, and Windows and many other operating systems. The main design criteria are: - Maintain a stable API without breaking backwards compatibility. - Do not create corrupt files, even in case of errors. - Do not delete data. - Be efficient. It supports the following features: - Reading archives and file data from files or memory buffers - Reverting unsaved changes - Zip64 large archives - Deflate, bzip2, LZMA, and zstd compression - Winzip AES and legacy PKWARE encryption The [BSD license](LICENSE) used for libzip allows its use in commercial products. ## Who Uses libzip? libzip is used in major open source projects like [KDE](https://kde.org/), [Chromium](https://www.chromium.org/Home), [ImageMagick](https://github.com/ImageMagick/ImageMagick/), and [VeraCrypt](https://www.veracrypt.fr/). Commercial products using libzip include [Lightroom from Adobe](https://lightroom.adobe.com/) and the [Kobo eReader](http://www.kobo.com/desktop). There are also bindings for other programming languages: [Python](https://github.com/KOLANICH-libs/libzip.py), [Ruby](http://rubygems.org/gems/zipruby/), [Lua](https://github.com/brimworks/lua-zip), [PHP](http://pecl.php.net/package/zip), and others. There is a more complete [list of projects](https://libzip.org/users/). ## Getting Started Most Linux and other Unix distributions include libzip in their package distributions, it is usually called `libzip` or `libzip-dev`. On macOS, it is included in both Homebrew and Mac Ports. On Windows, it is in vcpkg. A list of available packages can be found on [Repology](https://repology.org/project/libzip/versions). For building and installing libzip from source, see the [INSTALL.md](INSTALL.md) file. ## Using libzip libzip is fully documented via man pages. HTML versions of the man pages are on [libzip.org](https://libzip.org/documentation/) and in the [man](man) directory. You can start with [libzip(3)](https://libzip.org/documentation/libzip.html), which lists all others. Example source code is in the [examples](examples) and [src](src) subdirectories. If you have developed an application using libzip, you can find out about API changes and how to adapt your code for them in the included file [API-CHANGES.md](API-CHANGES.md). ## Staying in Touch More information and the latest version can always be found on [libzip.org](https://libzip.org). The official repository is at [GitHub](https://github.com/nih-at/libzip/). If you want to reach the authors in private, use . [![Packaging status](https://repology.org/badge/tiny-repos/libzip.svg)](https://repology.org/project/libzip/versions) [![Github Actions Build Status](https://github.com/nih-at/libzip/workflows/build/badge.svg)](https://github.com/nih-at/libzip/actions?query=workflow%3Abuild) [![Appveyor Build status](https://ci.appveyor.com/api/projects/status/f1bqqt9djvf22f5g?svg=true)](https://ci.appveyor.com/project/nih-at/libzip) [![Coverity Status](https://scan.coverity.com/projects/127/badge.svg)](https://scan.coverity.com/projects/libzip) [![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/libzip.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:libzip) ================================================ FILE: external/libzip/SECURITY.md ================================================ # Security Policy ## Supported Versions We are not maintaining multiple branches, so all fixes will be committed to head and included in the next release. We take great care to maintain backwards compatibility, so we expect our users to use the latest version. ## Reporting a Vulnerability You can reach us per email at info@libzip.org. For less sensitive reports, you can also open an issue or pull request on GitHub. ================================================ FILE: external/libzip/THANKS ================================================ Thanks to Info-ZIP for info on the DOS-time/date conversion code, and some other general information gathered from their sources. Thanks to these people for suggestions, testing, and bug reports: ag2s20150909 Agostino Sarubbo Alberto Spin Alexander Galanin Alexandr Shadchin Alexey Bykov Andreas Deininger Andreas Falkenhahn Andrew Brampton Andrew Molyneux Ankur Kothari Antonin Décimo Arseniy Terekhin BALATON Zoltan Benjamin Gilbert Beuc Boaz Stolk Bob Friesenhahn Bogdan Brian 'geeknik' Carpenter BruceFan Carl Mastrangelo Cédric Tabin celan69 chaoticgd Charlie Li ChrisAm1224 Chris Mayo Chris Nehren Christoph Cullmann Christoph M. Becker Corentin Schreiber Coverity cryi ctenter-scs Dane Springmeyer Daniel Russel Ларионов Даниил David Demelier Dean Ellis Declan Moran Del Merritt Devin Davila Dmytro Rybachenko Dylan T. Eelco Dolstra Elvis Angelaccio Erin Melucci Erwin Haid Eun-cheol Joo Fabrice Fontaine Filip Niksic Florian Delizy Force Charlie François Simon Frederik Ramm Gabriela Gutierrez Gerard ODonnell Giovanni gk7huki Hanno Böck HeeMyung Heiko Becker Heiko Hund hongjunwang Ilya Voronin Info-ZIP group Ivan Kolesnikov Jan Weiß Jay Freeman (saurik) jloqfjgk@github Joachim Reichel João Custódio Joel Ebrahimi Jono Spiro Julien Matthey Julien Schueller Justin Cohen Kate Raggett kensington Kei Takahashi Keith Jones Khaled Mardam-Bey Kohei Yoshida Krzesimir Nowak Leith Bade Lubomir I. Ivanov Lucas Bustamante Ludovic LANGE M. Reiningħaus Maël Nison Manuel Massing Marcin Kowalczyk Mark A. Tsuchida Martin Buchholz Martin Herkt Martin Szulecki Mathieu Pujol Michael Balzer Michael Beck Michael Heimpold Michał Janiszewski Michal Vyskocil Mikhail Gusarov . Miklos Vajna Morris Hafner Muhammad Arslan Kabeer Mykyta Mudryi nieder Oliver Kaiser Oliver Kuckertz OSS-Fuzz Team Ørjan Malde Pascal Terjan Patrick Spendrin Paul Harris Paul Sheppard Pavel Raiskup Pierre Joye Pierre Wendling Pierre-Louis Cabelguen PW Hu Rafał Mikrut ralfjunker Randy Remi Collet rezso Richard Schütz Rick Carback Rikard Falkeborn Robert Norris Roberto Tirabassi robhz786 Roland Ortloff Rosen Penev Rudi Heitbaum Ryan Burns Sam James Sam Sappenfield Sandro Mani scribam Sebastian Kemper Sebastian Schmitt Sergei Ozerov shenlebantongying Shimi Simon Talbot SpaceIm Stephen Bryant sxkan Tabata Shintaro takase1121 Tarmo Pikaro Taylor C. Richberger TC Thomas Debesse Tim Lunn Timo Warns Timofey Tom Callaway Tomas Hoger Tomáš Malý Torsten Paul Transporter Vassili Courzakis Vinpasso Vitaly Murashev William Lee William Ouwehand Wojciech Michalski Wolfgang Glunz Yufan You ================================================ FILE: external/libzip/TODO.md ================================================ ## Fuzzing - improve AES and PKWARE encryption tests - add more - review memset() uses ### Torrentzip - Handle data sources with unknown uncompressed size: if we forced ZIP64 and don't need it, return specific error (so calling code can decide what to do (e. g. clear torrentzip flag and call `zip_close()` again)). ## Other - split `zip_source_t` in main part and reference so we can keep track which reference called open and we can invalidate references if the underlying source gets invalidated (e. g. by `zip_close`). ## Prefixes For example for adding extractors for self-extracting zip archives. ````c zip_set_archive_prefix(struct zip *za, const zip_uint8_t *data, zip_uint64_t length); const zip_uint8_t *zip_get_archive_prefix(struct zip *za, zip_uint64_t *lengthp); ```` ## Compression * add lzma2 support * add deflate64 support (https://github.com/madler/zlib/blob/master/contrib/infback9/infback9.h) ## API Issues * Add `zip_file_use_password` to set per-file password to use if libzip needs to decrypt the file (e.g. when changing encryption or compression method). * `zip_get_archive_comment` has `int *lenp` argument. Cleaner would be `zip_uint32_t *`. rename and fix. which other functions for naming consistency? * rename remaining `zip_XXX_{file,archive}_*` to `zip_{file,archive}_XXX_*`? * compression/crypt implementations: how to set error code on failure * compression/crypt error messages a la `ZIP_ER_ZLIB` (no detailed info passing) ## Features * consistently use `_zip_crypto_clear()` for passwords * support setting extra fields from `zip_source` * introduce layers of extra fields: * original * from `zip_source` * manually set * when querying extra fields, search all of them in reverse order * add whiteout (deleted) flag * allow invalid data flag, used when computing extra field size before writing data * new command `ZIP_SOURCE_EXTRA_FIELDS` * no support for multiple copies of same extra field * function to copy file from one archive to another * set `O_CLOEXEC` flag after fopen and mkstemp * support streaming output (creating new archive to e.g. stdout) * add function to read/set ASCII file flag * add custom compression function support * `zip_source_zip()`: allow rewinding * `zipcmp`: add option for file content comparison * `zipcmp`: add more paranoid checks: * external attributes/opsys * version needed/made by * general purpose bit flags * add more consistency checks: * for stored files, test compressed = uncompressed * data descriptor * local headers come before central dir * support for old compression methods? ## Bugs * ensure that nentries is small enough not to cause overflow (size_t for entry, uint64 for CD on disk) * check for limits imposed by format (central dir size, file size, extra fields, ...) * `_zip_u2d_time()`: handle `localtime(3)` failure * POSIX: `zip_open()`: check whether file can be created and fail if not * fix inconsistent usage of valid flags (not checked in many places) * `cdr == NULL` -> `ER_NOENT` vs. `idx > cdir->nentry` -> `ER_INVAL` inconsistent (still there?) ## Cleanup * go over cdir parser and rename various offset/size variables to make it clearer * use bool * use `ZIP_SOURCE_SUPPORTS_{READABLE,SEEKABLE,WRITABLE}` * use `zip_source_seek_compute_offset()` * get rid of `zip_get_encryption_implementation()` * use `zip_*int*_t` internally * `zip_source_file()`: don't allow write if start/len specify a part of the file ## Documentation * document valid file paths * document: `zip_source_write()`: length can't be > `ZIP_INT64_MAX` * document: `ZIP_SOURCE_CLOSE` implementation can't return error * keep error codes in man pages in sync * document error codes in new man pages ## Infrastructure * add coverage reports, e.g. using gcovr or https://github.com/eddyxu/cpp-coveralls (coveralls.io) * review guidelines/community standards - [Linux Foundation Core Infrastructure Initiative Best Practices](https://bestpractices.coreinfrastructure.org/) - [Readme Maturity Level](https://github.com/LappleApple/feedmereadmes/blob/master/README-maturity-model.md) - [Github Community Profile](https://github.com/nih-at/libzip/community) * test different crypto backends with GitHub actions. * improve man page formatting of tagged lists on webpage (`
`) * rewrite `make_zip_errors.sh` in cmake * script to check if all exported symbols are marked with `ZIP_EXTERN`, add to `make distcheck` ## macOS / iOS framework * get cmake to optionally build frameworks ## Test Case Issues * add test cases for all `ZIP_INCONS` detail errors * `incons-local-filename-short.zzip` doesn't test short filename, since extra fields fail to parse. * test error cases with special source - tell it which command should fail - use it both as source for `zip_add` and `zip_open_from_source` - `ziptool_regress`: - `-e error_spec`: source containing zip fails depending on `error_spec` - `add_with_error name content error_spec`: add content to archive, where source fails depending on `error_spec` - `add_file_with_error name file_to_add offset len error_spec`: add file to archive, len bytes starting from offset, where source fails depending on `error_spec` - `error_spec`: - source command that fails - error code that source returns - conditions that must be met for error to trigger - Nth call of command - read/write: total byte count so far - state of source (opened, EOF reached, ...) * test for zipcmp reading directory (requires fts) * add test case for clone with files > 4k * consider testing for `malloc`/`realloc` failures * Winzip AES support * test cases decryption: <=20, >20, stat for both * test cases encryption: no password, default password, file-specific password, 128/192/256, <=20, >20 * support testing on macOS * add test cases for lots of files (including too many) * add test cases for holes (between files, between files and cdir, between cdir and eocd, + zip64 where appropriate) * test seek in `zip_source_crc_create()` * test cases for `set_extra*`, `delete_extra*`, `*extra_field*` * test cases for in memory archives * add * delete * delete all * modify * use gcov output to increase test coverage * add test case to change values for newly added files (name, compression method, comment, mtime, . . .) * `zip_open()` file less than `EOCDLEN` bytes long * test calls against old API * rename file to dir/ and vice versa (fails) * fix comment test to be newline insensitive * check if http://bugs.python.org/issue20078 provides ideas for new tests * (`add`, `replace`) * add to empty zip * add to existing zip * add w/ existing file name [E] * replace ok * replace w/ illegal index [E] * replace w/ deleted name [E] * unchange added/replaced file * (`close`) * copy zip file * open copy * rename, delete, replace, add w/ new name, add w/ deleted name * close * zipcmp copy expected * remove copy * (`error_get`) * (`error_get_sys_type`) * (`error_to_str`) * (`extra_fields`) * (`file_error_get`) * (`file_strerror`) * (`replace`) * (`source_buffer`) * (`source_file`) * (`source_filep`) * (`source_free`) * (`source_function`) * (`source_zip`) * (`strerror`) * (`unchange`) * (`unchange_all`) * `open(ZIP_RDONLY)` * I/O abstraction layer * `zip_open_from_source` * read two zip entries interleaved * test `zip_file_is_seekable` (via `ziptool`?) ================================================ FILE: external/libzip/android/do.sh ================================================ # Author: Declan Moran # www.silverglint.com # Thanks to damaex (https://github.com/damaex), for significant contributions ANDROID_NDK_ROOT=/home/android/android-ndk-r19c INSTALL_DIR=install BUILD_DIR=build START_DIR=$(pwd) rm -rf $INSTALL_DIR rm -rf $BUILD_DIR mkdir -p $BUILD_DIR #"${ANDROID_TARGET_PLATFORM}" #-------------------------------------------------------------------- build_it() { # builds either a static or shared lib depending on parm passed (ON or OFF) want_shared=$1 cmake -DCMAKE_TOOLCHAIN_FILE=${ANDROID_NDK_ROOT}/build/cmake/android.toolchain.cmake \ -DCMAKE_INSTALL_PREFIX:PATH=$(pwd)/../../${INSTALL_DIR}/${ANDROID_TARGET_PLATFORM} \ -DANDROID_ABI=${ANDROID_TARGET_PLATFORM} \ -DENABLE_OPENSSL:BOOL=OFF \ -DENABLE_COMMONCRYPTO:BOOL=OFF \ -DENABLE_GNUTLS:BOOL=OFF \ -DENABLE_MBEDTLS:BOOL=OFF \ -DENABLE_OPENSSL:BOOL=OFF \ -DENABLE_WINDOWS_CRYPTO:BOOL=OFF \ -DBUILD_TOOLS:BOOL=OFF \ -DBUILD_REGRESS:BOOL=OFF \ -DBUILD_EXAMPLES:BOOL=OFF \ -DBUILD_SHARED_LIBS:BOOL=$want_shared \ -DBUILD_DOC:BOOL=OFF \ -DANDROID_TOOLCHAIN=clang cmake -H.. -B$BUILD_DIR/${ANDROID_TARGET_PLATFORM} #run make with all system threads and install cd $BUILD_DIR/${ANDROID_TARGET_PLATFORM} make install -j$(nproc --all) cd $START_DIR } #-------------------------------------------------------------------- for ANDROID_TARGET_PLATFORM in armeabi-v7a arm64-v8a x86 x86_64 do echo "Building libzip for ${ANDROID_TARGET_PLATFORM}" build_it ON build_it OFF if [ $? -ne 0 ]; then echo "Error executing: cmake" exit 1 fi if [ $? -ne 0 ]; then echo "Error executing make install for platform: ${ANDROID_TARGET_PLATFORM}" exit 1 fi done ================================================ FILE: external/libzip/android/docker/Dockerfile ================================================ # Version: 1.0 # Dockerfile for building libzip for android # https://github.com/dec1/libzip.git # creates docker container with all tools, libraries and sources required to build libzip for android. # Author: Declan Moran # www.silverglint.com # Usage: #--------- # download the libzip repository # > git clone https://github.com/dec1/libzip.git # > cd libzip # # build docker image "my_img_zip" from the dockerfile in "docker" dir # > docker build -t my_img_zip ./android/docker # # run docker container "my_ctr_zip" from this image, mounting the current dir. (Need to pass absolute host paths to mount volume- hence "pwd") # > docker run -v $(pwd):/home/docker-share/libzip -it --entrypoint=/bin/bash --name my_ctr_zip my_img_zip # # Now inside docker container # $ cd /home/docker-share/libzip/android # # Modify ./do.sh (on host), to match the boost and android ndk versions/paths in the "Configure here" section below # Build from running docker container. # $./do.sh # # "./build" dir contains required build, but owned by root. chown to your username/group # > sudo chown -R : ./build # > sudo chown -R : ./install # # Exit container, when build is finished. # $ exit # FROM ubuntu:18.04 ## -------------------------------------------------------------------- ## Configure here # --------------------------------------------------------------------- # --------------------------------------------------------------------- # Here you can speciofy exactly what android ndk (and sdk) version you want to use. # (2) Android SDK # https://developer.android.com/studio#downloads ARG SDK_URL_BASE=https://dl.google.com/android/repository ARG SDK_FILE=sdk-tools-linux-4333796.zip # the sdk platform to use # https://developer.android.com/guide/topics/manifest/uses-sdk-element ARG ANDROID_SDK_PLATFORM_VERS="platforms;android-28" # (3) Android NDK # https://developer.android.com/ndk/downloads ARG NDK_URL_BASE=https://dl.google.com/android/repository ARG NDK_FILE=android-ndk-r19c-linux-x86_64.zip # --------------------------------------------------------------------- ## -------------------------------------------------------------------- RUN apt-get update RUN apt-get -y dist-upgrade # for downloading archives RUN apt-get -y install wget # for unzipping downloaded android archives RUN apt-get -y install zip RUN apt-get -y install cmake RUN apt-get -y install lib32z1 # need this this to install some (32 bit) prerequisites for android builds RUN dpkg --add-architecture i386 RUN apt-get update RUN apt-get -y dist-upgrade RUN apt-get install -y libc6:i386 libncurses5:i386 libstdc++6:i386 libbz2-1.0:i386 # need c compiler to set up create boost build system (before building boost with it and android toolchain) RUN apt-get -y install build-essential RUN apt-get -y install libc6-dev-i386 RUN apt-get -y install clang RUN apt-get -y install openjdk-8-jdk #-------------------------------------- ARG ANDROID_HOME=/home/android WORKDIR ${ANDROID_HOME} # SDK # ---- # download android sdk command line tools RUN wget ${SDK_URL_BASE}/$SDK_FILE RUN unzip $SDK_FILE ENV PATH ${PATH}:${ANDROID_HOME}/tools:${ANDROID_HOME}/tools/bin:${ANDROID_HOME}/platform-tools RUN yes | sdkmanager --licenses RUN sdkmanager "platform-tools" $ANDROID_SDK_PLATFORM_VERS #RUN sdkmanager "platform-tools" "platforms;android-28" # NDK # ---- RUN wget ${NDK_URL_BASE}/$NDK_FILE RUN unzip $NDK_FILE ================================================ FILE: external/libzip/android/readme.txt ================================================ Cross compile libzip for android. -------------------------------- Modify "do.sh" as appropriate if you need to specify a different ndk dir or wish to specify different build parameters Prerequisites for the development machine - see docker/Dockerfile You can either set you host machine up with these prerequisites or simply use docker (in which case you need not install anything on your host machine except docker itself). See "Usage" in docker/Dockerfile for detailed instructions. Please note: The libzip development team does not use Android, so this script is provided as is, as we cannot properly maintain it. We will, however, gladly accept fixes and try to work with users to resolve any issues they may have. ================================================ FILE: external/libzip/appveyor.yml ================================================ os: - Visual Studio 2019 environment: PATH: C:\Python311-x64\Scripts;C:\Python311-arm\Scripts;$(PATH) VCPKG_BINARY_SOURCES: clear;files,C:\vcpkg.cache,readwrite matrix: - GENERATOR: "Visual Studio 16 2019" PLATFORM: x64 TRIPLET: x64-windows CMAKE_OPTS: "-DBUILD_SHARED_LIBS=off" CMAKE_CONFIG: Release RUN_TESTS: yes TOXENV: py311 - GENERATOR: "Visual Studio 16 2019" PLATFORM: x64 TRIPLET: x64-uwp CMAKE_OPTS: "-DCMAKE_SYSTEM_NAME=WindowsStore -DCMAKE_SYSTEM_VERSION=10.0" CMAKE_CONFIG: Release RUN_TESTS: no TOXENV: py311 - GENERATOR: "Visual Studio 16 2019" PLATFORM: Win32 TRIPLET: x86-windows CMAKE_OPTS: "-DBUILD_SHARED_LIBS=off" CMAKE_CONFIG: Release RUN_TESTS: yes TOXENV: py311 - GENERATOR: "Visual Studio 16 2019" PLATFORM: Win32 TRIPLET: x86-uwp CMAKE_OPTS: "-DCMAKE_SYSTEM_NAME=WindowsStore -DCMAKE_SYSTEM_VERSION=10.0" CMAKE_CONFIG: Release RUN_TESTS: no TOXENV: py311 - GENERATOR: "Visual Studio 16 2019" PLATFORM: ARM TRIPLET: arm-windows CMAKE_OPTS: "-DENABLE_OPENSSL=off" CMAKE_CONFIG: Release RUN_TESTS: no TOXENV: py311 - GENERATOR: "Visual Studio 16 2019" PLATFORM: ARM TRIPLET: arm-uwp CMAKE_OPTS: "-DCMAKE_SYSTEM_NAME=WindowsStore -DCMAKE_SYSTEM_VERSION=10.0 -DENABLE_OPENSSL=off" CMAKE_CONFIG: Release RUN_TESTS: no TOXENV: py311 - GENERATOR: "Visual Studio 16 2019" PLATFORM: ARM64 TRIPLET: arm64-windows CMAKE_OPTS: "-DENABLE_OPENSSL=off" CMAKE_CONFIG: Release RUN_TESTS: no TOXENV: py311 - GENERATOR: "Visual Studio 16 2019" PLATFORM: ARM64 TRIPLET: arm64-uwp CMAKE_OPTS: "-DCMAKE_SYSTEM_NAME=WindowsStore -DCMAKE_SYSTEM_VERSION=10.0 -DENABLE_OPENSSL=off" CMAKE_CONFIG: Release RUN_TESTS: no TOXENV: py311 before_build: cmd: >- py -m pip install nihtest mkdir build cd build cmake -DCMAKE_TOOLCHAIN_FILE=C:/tools/vcpkg/scripts/buildsystems/vcpkg.cmake .. -G "%GENERATOR%" -A "%PLATFORM%" %CMAKE_OPTS% appveyor PushArtifact config.h appveyor PushArtifact CMakeCache.txt build_script: cmd: >- cmake --build . --config %CMAKE_CONFIG% --target INSTALL cmake --build . --config %CMAKE_CONFIG% test_script: cmd: >- set VERBOSE=yes IF %RUN_TESTS%==yes ( ctest -C %CMAKE_CONFIG% --output-on-failure ) cache: - c:\vcpkg.cache -> vcpkg.json ================================================ FILE: external/libzip/cmake/Dist.cmake ================================================ # Copyright (C) 2020 Dieter Baron and Thomas Klausner # # The authors can be contacted at # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in # the documentation and/or other materials provided with the # distribution. # # 3. The names of the authors may not be used to endorse or promote # products derived from this software without specific prior # written permission. # # THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER # IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR # OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN # IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #[=======================================================================[.rst: Dist ------- Provide ``dist`` and ``distcheck`` targets similar to autoconf/automake functionality. The ``dist`` target creates tarballs of the project in ``.tar.gz`` and ``.tar.xz`` formats. The ``distcheck`` target extracts one of created tarballs, builds the software using its defaults, and runs the tests. Both targets use Unix shell commands. The Dist target takes one argument, the file name (before the extension). The ``distcheck`` target creates (and removes) ``${ARCHIVE_NAME}-build`` and ``${ARCHIVE_NAME}-dest``. #]=======================================================================] function(Dist ARCHIVE_NAME) if(NOT TARGET dist AND NOT TARGET distcheck) add_custom_target(dist COMMAND git config tar.tar.xz.command "xz -c" COMMAND git archive --prefix=${ARCHIVE_NAME}/ -o ${CMAKE_BINARY_DIR}/${ARCHIVE_NAME}.tar.gz HEAD COMMAND git archive --prefix=${ARCHIVE_NAME}/ -o ${CMAKE_BINARY_DIR}/${ARCHIVE_NAME}.tar.xz HEAD WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} ) add_custom_target(distcheck COMMAND chmod -R u+w ${ARCHIVE_NAME} ${ARCHIVE_NAME}-build ${ARCHIVE_NAME}-dest 2>/dev/null || true COMMAND rm -rf ${ARCHIVE_NAME} ${ARCHIVE_NAME}-build ${ARCHIVE_NAME}-dest COMMAND ${CMAKE_COMMAND} -E tar xf ${CMAKE_BINARY_DIR}/${ARCHIVE_NAME}.tar.gz COMMAND chmod -R u-w ${ARCHIVE_NAME} COMMAND mkdir ${ARCHIVE_NAME}-build COMMAND mkdir ${ARCHIVE_NAME}-dest COMMAND ${CMAKE_COMMAND} -DCMAKE_INSTALL_PREFIX=${ARCHIVE_NAME}-dest ${ARCHIVE_NAME} -B ${ARCHIVE_NAME}-build COMMAND make -C ${ARCHIVE_NAME}-build -j4 COMMAND make -C ${ARCHIVE_NAME}-build test COMMAND make -C ${ARCHIVE_NAME}-build install # COMMAND make -C ${ARCHIVE_NAME}-build uninstall # COMMAND if [ `find ${ARCHIVE_NAME}-dest ! -type d | wc -l` -ne 0 ]; then echo leftover files in ${ARCHIVE_NAME}-dest; false; fi COMMAND make -C ${ARCHIVE_NAME}-build clean COMMAND chmod -R u+w ${ARCHIVE_NAME} ${ARCHIVE_NAME}-build ${ARCHIVE_NAME}-dest COMMAND rm -rf ${ARCHIVE_NAME} ${ARCHIVE_NAME}-build ${ARCHIVE_NAME}-dest COMMAND echo "${ARCHIVE_NAME}.tar.gz is ready for distribution." WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} ) add_dependencies(distcheck dist) endif() endfunction() ================================================ FILE: external/libzip/cmake/FindMbedTLS.cmake ================================================ # Copyright (C) 2020 Dieter Baron and Thomas Klausner # # The authors can be contacted at # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in # the documentation and/or other materials provided with the # distribution. # # 3. The names of the authors may not be used to endorse or promote # products derived from this software without specific prior # written permission. # # THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER # IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR # OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN # IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #[=======================================================================[.rst: FindMbedTLS ------- Finds the Mbed TLS library. Imported Targets ^^^^^^^^^^^^^^^^ This module provides the following imported targets, if found: ``MbedTLS::MbedTLS`` The Mbed TLS library Result Variables ^^^^^^^^^^^^^^^^ This will define the following variables: ``MbedTLS_FOUND`` True if the system has the Mbed TLS library. ``MbedTLS_VERSION`` The version of the Mbed TLS library which was found. ``MbedTLS_INCLUDE_DIRS`` Include directories needed to use Mbed TLS. ``MbedTLS_LIBRARIES`` Libraries needed to link to Mbed TLS. Cache Variables ^^^^^^^^^^^^^^^ The following cache variables may also be set: ``MbedTLS_INCLUDE_DIR`` The directory containing ``mbedtls/aes.h``. ``MbedTLS_LIBRARY`` The path to the Mbed TLS library. #]=======================================================================] # I'm not aware of a pkg-config file for mbedtls as of 2020/07/08. #find_package(PkgConfig) #pkg_check_modules(PC_MbedTLS QUIET mbedtls) find_path(MbedTLS_INCLUDE_DIR NAMES mbedtls/aes.h # PATHS ${PC_MbedTLS_INCLUDE_DIRS} ) find_library(MbedTLS_LIBRARY NAMES mbedcrypto # PATHS ${PC_MbedTLS_LIBRARY_DIRS} ) # Extract version information from the header file if(MbedTLS_INCLUDE_DIR) # for major version 3 if(EXISTS ${MbedTLS_INCLUDE_DIR}/mbedtls/build_info.h) file(STRINGS ${MbedTLS_INCLUDE_DIR}/mbedtls/build_info.h _ver_line REGEX "^#define MBEDTLS_VERSION_STRING *\"[0-9]+\\.[0-9]+\\.[0-9]+\"" LIMIT_COUNT 1) string(REGEX MATCH "[0-9]+\\.[0-9]+\\.[0-9]+" MbedTLS_VERSION "${_ver_line}") unset(_ver_line) # for major version 2 elseif(EXISTS ${MbedTLS_INCLUDE_DIR}/mbedtls/version.h) file(STRINGS ${MbedTLS_INCLUDE_DIR}/mbedtls/version.h _ver_line REGEX "^#define MBEDTLS_VERSION_STRING *\"[0-9]+\\.[0-9]+\\.[0-9]+\"" LIMIT_COUNT 1) string(REGEX MATCH "[0-9]+\\.[0-9]+\\.[0-9]+" MbedTLS_VERSION "${_ver_line}") unset(_ver_line) else() if(PC_MbedTLS_VERSION) set(MbedTLS_VERSION ${PC_MbedTLS_VERSION}) else() # version unknown set(MbedTLS_VERSION "0.0") endif() endif() endif() include(FindPackageHandleStandardArgs) find_package_handle_standard_args(MbedTLS FOUND_VAR MbedTLS_FOUND REQUIRED_VARS MbedTLS_LIBRARY MbedTLS_INCLUDE_DIR VERSION_VAR MbedTLS_VERSION ) if(MbedTLS_FOUND) set(MbedTLS_LIBRARIES ${MbedTLS_LIBRARY}) set(MbedTLS_INCLUDE_DIRS ${MbedTLS_INCLUDE_DIR}) # set(MbedTLS_DEFINITIONS ${PC_MbedTLS_CFLAGS_OTHER}) endif() if(MbedTLS_FOUND AND NOT TARGET MbedTLS::MbedTLS) add_library(MbedTLS::MbedTLS UNKNOWN IMPORTED) set_target_properties(MbedTLS::MbedTLS PROPERTIES IMPORTED_LOCATION "${MbedTLS_LIBRARY}" # INTERFACE_COMPILE_OPTIONS "${PC_MbedTLS_CFLAGS_OTHER}" INTERFACE_INCLUDE_DIRECTORIES "${MbedTLS_INCLUDE_DIR}" ) endif() mark_as_advanced( MbedTLS_INCLUDE_DIR MbedTLS_LIBRARY ) ================================================ FILE: external/libzip/cmake/FindNettle.cmake ================================================ # Copyright (C) 2020 Dieter Baron and Thomas Klausner # # The authors can be contacted at # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in # the documentation and/or other materials provided with the # distribution. # # 3. The names of the authors may not be used to endorse or promote # products derived from this software without specific prior # written permission. # # THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER # IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR # OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN # IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #[=======================================================================[.rst: FindNettle ------- Finds the Nettle library. Imported Targets ^^^^^^^^^^^^^^^^ This module provides the following imported targets, if found: ``Nettle::Nettle`` The Nettle library Result Variables ^^^^^^^^^^^^^^^^ This will define the following variables: ``Nettle_FOUND`` True if the system has the Nettle library. ``Nettle_VERSION`` The version of the Nettle library which was found. ``Nettle_INCLUDE_DIRS`` Include directories needed to use Nettle. ``Nettle_LIBRARIES`` Libraries needed to link to Nettle. Cache Variables ^^^^^^^^^^^^^^^ The following cache variables may also be set: ``Nettle_INCLUDE_DIR`` The directory containing ``nettle/aes.h``. ``Nettle_LIBRARY`` The path to the Nettle library. #]=======================================================================] find_package(PkgConfig) pkg_check_modules(PC_Nettle QUIET nettle) find_path(Nettle_INCLUDE_DIR NAMES nettle/aes.h nettle/md5.h nettle/pbkdf2.h nettle/ripemd160.h nettle/sha.h PATHS ${PC_Nettle_INCLUDE_DIRS} ) find_library(Nettle_LIBRARY NAMES nettle PATHS ${PC_Nettle_LIBRARY_DIRS} ) if(Nettle_INCLUDE_DIR) if(PC_Nettle_VERSION) set(Nettle_VERSION ${PC_Nettle_VERSION}) elseif(EXISTS ${Nettle_INCLUDE_DIR}/nettle/version.h) # Extract version information from the header file # This file only exists in nettle>=3.0 file(STRINGS ${Nettle_INCLUDE_DIR}/nettle/version.h _ver_major_line REGEX "^#define NETTLE_VERSION_MAJOR *[0-9]+" LIMIT_COUNT 1) string(REGEX MATCH "[0-9]+" Nettle_MAJOR_VERSION "${_ver_major_line}") file(STRINGS ${Nettle_INCLUDE_DIR}/nettle/version.h _ver_minor_line REGEX "^#define NETTLE_VERSION_MINOR *[0-9]+" LIMIT_COUNT 1) string(REGEX MATCH "[0-9]+" Nettle_MINOR_VERSION "${_ver_minor_line}") set(Nettle_VERSION "${Nettle_MAJOR_VERSION}.${Nettle_MINOR_VERSION}") unset(_ver_major_line) unset(_ver_minor_line) else() set(Nettle_VERSION "1.0") endif() endif() include(FindPackageHandleStandardArgs) find_package_handle_standard_args(Nettle FOUND_VAR Nettle_FOUND REQUIRED_VARS Nettle_LIBRARY Nettle_INCLUDE_DIR VERSION_VAR Nettle_VERSION ) if(Nettle_FOUND) set(Nettle_LIBRARIES ${Nettle_LIBRARY}) set(Nettle_INCLUDE_DIRS ${Nettle_INCLUDE_DIR}) set(Nettle_DEFINITIONS ${PC_Nettle_CFLAGS_OTHER}) endif() if(Nettle_FOUND AND NOT TARGET Nettle::Nettle) add_library(Nettle::Nettle UNKNOWN IMPORTED) set_target_properties(Nettle::Nettle PROPERTIES IMPORTED_LOCATION "${Nettle_LIBRARY}" INTERFACE_COMPILE_OPTIONS "${PC_Nettle_CFLAGS_OTHER}" INTERFACE_INCLUDE_DIRECTORIES "${Nettle_INCLUDE_DIR}" ) endif() mark_as_advanced( Nettle_INCLUDE_DIR Nettle_LIBRARY ) # compatibility variables set(Nettle_VERSION_STRING ${Nettle_VERSION}) ================================================ FILE: external/libzip/cmake/Findzstd.cmake ================================================ # Copyright (C) 2020 Dieter Baron and Thomas Klausner # # The authors can be contacted at # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in # the documentation and/or other materials provided with the # distribution. # # 3. The names of the authors may not be used to endorse or promote # products derived from this software without specific prior # written permission. # # THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER # IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR # OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN # IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #[=======================================================================[.rst: Findzstd ------- Finds the Zstandard (zstd) library. Imported Targets ^^^^^^^^^^^^^^^^ This module provides the following imported targets, if found: ``zstd::libzstd_shared`` The shared Zstandard library ``zstd::libzstd_static`` The shared Zstandard library Result Variables ^^^^^^^^^^^^^^^^ This will define the following variables: ``zstd_FOUND`` True if the system has the Zstandard library. ``zstd_VERSION`` The version of the Zstandard library which was found. Cache Variables ^^^^^^^^^^^^^^^ The following cache variables may also be set: ``zstd_INCLUDE_DIR`` The directory containing ``zstd.h``. ``zstd_STATIC_LIBRARY`` The path to the Zstandard static library. ``zstd_SHARED_LIBRARY`` The path to the Zstandard shared library. ``zstd_DLL`` The path to the Zstandard DLL. #]=======================================================================] find_package(PkgConfig) pkg_check_modules(PC_zstd QUIET libzstd) find_path(zstd_INCLUDE_DIR NAMES zstd.h HINTS ${PC_zstd_INCLUDE_DIRS} ) find_file(zstd_DLL NAMES libzstd.dll zstd.dll PATH_SUFFIXES bin HINTS ${PC_zstd_PREFIX} ) # On Windows, we manually define the library names to avoid mistaking the # implib for the static library if(zstd_DLL) set(_zstd_win_static_name zstd-static) set(_zstd_win_shared_name zstd) else() # vcpkg removes the -static suffix in static builds set(_zstd_win_static_name zstd zstd_static) set(_zstd_win_shared_name) endif() set(_previous_suffixes ${CMAKE_FIND_LIBRARY_SUFFIXES}) set(CMAKE_FIND_LIBRARY_SUFFIXES ".so" ".dylib" ".dll.a" ".lib") find_library(zstd_SHARED_LIBRARY NAMES zstd ${_zstd_win_shared_name} HINTS ${PC_zstd_LIBDIR} ) set(CMAKE_FIND_LIBRARY_SUFFIXES ".a" ".lib") find_library(zstd_STATIC_LIBRARY NAMES zstd ${_zstd_win_static_name} HINTS ${PC_zstd_LIBDIR} ) set(CMAKE_FIND_LIBRARY_SUFFIXES ${_previous_suffixes}) # Set zstd_LIBRARY to the shared library or fall back to the static library if(zstd_SHARED_LIBRARY) set(_zstd_LIBRARY ${zstd_SHARED_LIBRARY}) else() set(_zstd_LIBRARY ${zstd_STATIC_LIBRARY}) endif() # Extract version information from the header file if(zstd_INCLUDE_DIR) file(STRINGS ${zstd_INCLUDE_DIR}/zstd.h _ver_major_line REGEX "^#define ZSTD_VERSION_MAJOR *[0-9]+" LIMIT_COUNT 1) string(REGEX MATCH "[0-9]+" zstd_MAJOR_VERSION "${_ver_major_line}") file(STRINGS ${zstd_INCLUDE_DIR}/zstd.h _ver_minor_line REGEX "^#define ZSTD_VERSION_MINOR *[0-9]+" LIMIT_COUNT 1) string(REGEX MATCH "[0-9]+" zstd_MINOR_VERSION "${_ver_minor_line}") file(STRINGS ${zstd_INCLUDE_DIR}/zstd.h _ver_release_line REGEX "^#define ZSTD_VERSION_RELEASE *[0-9]+" LIMIT_COUNT 1) string(REGEX MATCH "[0-9]+" zstd_RELEASE_VERSION "${_ver_release_line}") set(Zstd_VERSION "${zstd_MAJOR_VERSION}.${zstd_MINOR_VERSION}.${zstd_RELEASE_VERSION}") unset(_ver_major_line) unset(_ver_minor_line) unset(_ver_release_line) endif() include(FindPackageHandleStandardArgs) find_package_handle_standard_args(zstd FOUND_VAR zstd_FOUND REQUIRED_VARS _zstd_LIBRARY zstd_INCLUDE_DIR VERSION_VAR zstd_VERSION ) if(zstd_FOUND AND zstd_SHARED_LIBRARY AND NOT TARGET zstd::libzstd_shared) add_library(zstd::libzstd_shared SHARED IMPORTED) if(WIN32) set_target_properties(zstd::libzstd_shared PROPERTIES IMPORTED_LOCATION "${zstd_DLL}" IMPORTED_IMPLIB "${zstd_SHARED_LIBRARY}" ) else() set_target_properties(zstd::libzstd_shared PROPERTIES IMPORTED_LOCATION "${zstd_SHARED_LIBRARY}" ) endif() set_target_properties(zstd::libzstd_shared PROPERTIES INTERFACE_COMPILE_OPTIONS "${PC_zstd_CFLAGS_OTHER}" INTERFACE_INCLUDE_DIRECTORIES "${zstd_INCLUDE_DIR}" ) endif() if(zstd_FOUND AND zstd_STATIC_LIBRARY AND NOT TARGET zstd::libzstd_static) add_library(zstd::libzstd_static STATIC IMPORTED) set_target_properties(zstd::libzstd_static PROPERTIES IMPORTED_LOCATION "${zstd_STATIC_LIBRARY}" INTERFACE_COMPILE_OPTIONS "${PC_zstd_CFLAGS_OTHER}" INTERFACE_INCLUDE_DIRECTORIES "${zstd_INCLUDE_DIR}" ) endif() mark_as_advanced( zstd_INCLUDE_DIR zstd_DLL zstd_SHARED_LIBRARY zstd_STATIC_LIBRARY ) ================================================ FILE: external/libzip/cmake/GenerateZipErrorStrings.cmake ================================================ # create zip_err_str.c from zip.h and zipint.h file(READ ${PROJECT_SOURCE_DIR}/lib/zip.h zip_h) string(REGEX MATCHALL "#define ZIP_ER_([A-Z0-9_]+) ([0-9]+)[ \t]+/([-*0-9a-zA-Z, ']*)/" zip_h_err ${zip_h}) file(READ ${PROJECT_SOURCE_DIR}/lib/zipint.h zipint_h) string(REGEX MATCHALL "#define ZIP_ER_DETAIL_([A-Z0-9_]+) ([0-9]+)[ \t]+/([-*0-9a-zA-Z, ']*)/" zipint_h_err ${zipint_h}) set(zip_err_str [=[ /* This file was generated automatically by CMake from zip.h and zipint.h\; make changes there. */ #include "zipint.h" #define L ZIP_ET_LIBZIP #define N ZIP_ET_NONE #define S ZIP_ET_SYS #define Z ZIP_ET_ZLIB #define E ZIP_DETAIL_ET_ENTRY #define G ZIP_DETAIL_ET_GLOBAL const struct _zip_err_info _zip_err_str[] = { ]=]) set(zip_err_type) foreach(errln ${zip_h_err}) string(REGEX MATCH "#define ZIP_ER_([A-Z0-9_]+) ([0-9]+)[ \t]+/([-*0-9a-zA-Z, ']*)/" err_t_tt ${errln}) string(REGEX MATCH "([L|N|S|Z]+) ([-0-9a-zA-Z,, ']*)" err_t_tt "${CMAKE_MATCH_3}") string(STRIP "${CMAKE_MATCH_2}" err_t_tt) string(APPEND zip_err_str " { ${CMAKE_MATCH_1}, \"${err_t_tt}\" },\n") endforeach() string(APPEND zip_err_str [=[}\; const int _zip_err_str_count = sizeof(_zip_err_str)/sizeof(_zip_err_str[0])\; const struct _zip_err_info _zip_err_details[] = { ]=]) foreach(errln ${zipint_h_err}) string(REGEX MATCH "#define ZIP_ER_DETAIL_([A-Z0-9_]+) ([0-9]+)[ \t]+/([-*0-9a-zA-Z, ']*)/" err_t_tt ${errln}) string(REGEX MATCH "([E|G]+) ([-0-9a-zA-Z, ']*)" err_t_tt "${CMAKE_MATCH_3}") string(STRIP "${CMAKE_MATCH_2}" err_t_tt) string(APPEND zip_err_str " { ${CMAKE_MATCH_1}, \"${err_t_tt}\" },\n") endforeach() string(APPEND zip_err_str [=[}\; const int _zip_err_details_count = sizeof(_zip_err_details)/sizeof(_zip_err_details[0])\; ]=]) file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/zip_err_str.c ${zip_err_str}) ================================================ FILE: external/libzip/cmake-compat/CMakePushCheckState.cmake ================================================ # Distributed under the OSI-approved BSD 3-Clause License. See accompanying # file Copyright.txt or https://cmake.org/licensing for details. #[=======================================================================[.rst: CMakePushCheckState ------------------- This module defines three macros: ``CMAKE_PUSH_CHECK_STATE()`` ``CMAKE_POP_CHECK_STATE()`` and ``CMAKE_RESET_CHECK_STATE()`` These macros can be used to save, restore and reset (i.e., clear contents) the state of the variables ``CMAKE_REQUIRED_FLAGS``, ``CMAKE_REQUIRED_DEFINITIONS``, ``CMAKE_REQUIRED_LINK_OPTIONS``, ``CMAKE_REQUIRED_LIBRARIES``, ``CMAKE_REQUIRED_INCLUDES`` and ``CMAKE_EXTRA_INCLUDE_FILES`` used by the various Check-files coming with CMake, like e.g. ``check_function_exists()`` etc. The variable contents are pushed on a stack, pushing multiple times is supported. This is useful e.g. when executing such tests in a Find-module, where they have to be set, but after the Find-module has been executed they should have the same value as they had before. ``CMAKE_PUSH_CHECK_STATE()`` macro receives optional argument ``RESET``. Whether it's specified, ``CMAKE_PUSH_CHECK_STATE()`` will set all ``CMAKE_REQUIRED_*`` variables to empty values, same as ``CMAKE_RESET_CHECK_STATE()`` call will do. Usage: .. code-block:: cmake cmake_push_check_state(RESET) set(CMAKE_REQUIRED_DEFINITIONS -DSOME_MORE_DEF) check_function_exists(...) cmake_reset_check_state() set(CMAKE_REQUIRED_DEFINITIONS -DANOTHER_DEF) check_function_exists(...) cmake_pop_check_state() #]=======================================================================] macro(CMAKE_RESET_CHECK_STATE) set(CMAKE_EXTRA_INCLUDE_FILES) set(CMAKE_REQUIRED_INCLUDES) set(CMAKE_REQUIRED_DEFINITIONS) set(CMAKE_REQUIRED_LINK_OPTIONS) set(CMAKE_REQUIRED_LIBRARIES) set(CMAKE_REQUIRED_FLAGS) set(CMAKE_REQUIRED_QUIET) endmacro() macro(CMAKE_PUSH_CHECK_STATE) if(NOT DEFINED _CMAKE_PUSH_CHECK_STATE_COUNTER) set(_CMAKE_PUSH_CHECK_STATE_COUNTER 0) endif() math(EXPR _CMAKE_PUSH_CHECK_STATE_COUNTER "${_CMAKE_PUSH_CHECK_STATE_COUNTER}+1") set(_CMAKE_EXTRA_INCLUDE_FILES_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER} ${CMAKE_EXTRA_INCLUDE_FILES}) set(_CMAKE_REQUIRED_INCLUDES_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER} ${CMAKE_REQUIRED_INCLUDES}) set(_CMAKE_REQUIRED_DEFINITIONS_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER} ${CMAKE_REQUIRED_DEFINITIONS}) set(_CMAKE_REQUIRED_LINK_OPTIONS_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER} ${CMAKE_REQUIRED_LINK_OPTIONS}) set(_CMAKE_REQUIRED_LIBRARIES_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER} ${CMAKE_REQUIRED_LIBRARIES}) set(_CMAKE_REQUIRED_FLAGS_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER} ${CMAKE_REQUIRED_FLAGS}) set(_CMAKE_REQUIRED_QUIET_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER} ${CMAKE_REQUIRED_QUIET}) if (${ARGC} GREATER 0 AND "${ARGV0}" STREQUAL "RESET") cmake_reset_check_state() endif() endmacro() macro(CMAKE_POP_CHECK_STATE) # don't pop more than we pushed if("${_CMAKE_PUSH_CHECK_STATE_COUNTER}" GREATER "0") set(CMAKE_EXTRA_INCLUDE_FILES ${_CMAKE_EXTRA_INCLUDE_FILES_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER}}) set(CMAKE_REQUIRED_INCLUDES ${_CMAKE_REQUIRED_INCLUDES_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER}}) set(CMAKE_REQUIRED_DEFINITIONS ${_CMAKE_REQUIRED_DEFINITIONS_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER}}) set(CMAKE_REQUIRED_LINK_OPTIONS ${_CMAKE_REQUIRED_LINK_OPTIONS_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER}}) set(CMAKE_REQUIRED_LIBRARIES ${_CMAKE_REQUIRED_LIBRARIES_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER}}) set(CMAKE_REQUIRED_FLAGS ${_CMAKE_REQUIRED_FLAGS_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER}}) set(CMAKE_REQUIRED_QUIET ${_CMAKE_REQUIRED_QUIET_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER}}) math(EXPR _CMAKE_PUSH_CHECK_STATE_COUNTER "${_CMAKE_PUSH_CHECK_STATE_COUNTER}-1") endif() endmacro() ================================================ FILE: external/libzip/cmake-compat/CheckLibraryExists.cmake ================================================ # Distributed under the OSI-approved BSD 3-Clause License. See accompanying # file Copyright.txt or https://cmake.org/licensing for details. #[=======================================================================[.rst: CheckLibraryExists ------------------ Check if the function exists. .. command:: CHECK_LIBRARY_EXISTS .. code-block:: cmake CHECK_LIBRARY_EXISTS(LIBRARY FUNCTION LOCATION VARIABLE) :: LIBRARY - the name of the library you are looking for FUNCTION - the name of the function LOCATION - location where the library should be found VARIABLE - variable to store the result Will be created as an internal cache variable. The following variables may be set before calling this macro to modify the way the check is run: :: CMAKE_REQUIRED_FLAGS = string of compile command line flags CMAKE_REQUIRED_DEFINITIONS = list of macros to define (-DFOO=bar) CMAKE_REQUIRED_LINK_OPTIONS = list of options to pass to link command CMAKE_REQUIRED_LIBRARIES = list of libraries to link CMAKE_REQUIRED_QUIET = execute quietly without messages #]=======================================================================] if(__CheckLibraryExists_cmake__) return() endif() set(__CheckLibraryExists_cmake__ TRUE) macro(CHECK_LIBRARY_EXISTS LIBRARY FUNCTION LOCATION VARIABLE) if(NOT DEFINED "${VARIABLE}") set(MACRO_CHECK_LIBRARY_EXISTS_DEFINITION "-DCHECK_FUNCTION_EXISTS=${FUNCTION} ${CMAKE_REQUIRED_FLAGS}") if(NOT CMAKE_REQUIRED_QUIET) message(CHECK_START "Looking for ${FUNCTION} in ${LIBRARY}") endif() set(CHECK_LIBRARY_EXISTS_LINK_OPTIONS) if(CMAKE_REQUIRED_LINK_OPTIONS) set(CHECK_LIBRARY_EXISTS_LINK_OPTIONS LINK_OPTIONS ${CMAKE_REQUIRED_LINK_OPTIONS}) endif() set(CHECK_LIBRARY_EXISTS_LIBRARIES ${LIBRARY}) if(CMAKE_REQUIRED_LIBRARIES) set(CHECK_LIBRARY_EXISTS_LIBRARIES ${CHECK_LIBRARY_EXISTS_LIBRARIES} ${CMAKE_REQUIRED_LIBRARIES}) endif() if(CMAKE_C_COMPILER_LOADED) set(_cle_source ${CMAKE_ROOT}/Modules/CheckFunctionExists.c) elseif(CMAKE_CXX_COMPILER_LOADED) set(_cle_source ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CheckLibraryExists/CheckFunctionExists.cxx) configure_file(${CMAKE_ROOT}/Modules/CheckFunctionExists.c "${_cle_source}" COPYONLY) else() message(FATAL_ERROR "CHECK_FUNCTION_EXISTS needs either C or CXX language enabled") endif() try_compile(${VARIABLE} ${CMAKE_BINARY_DIR} ${_cle_source} COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS} ${CHECK_LIBRARY_EXISTS_LINK_OPTIONS} LINK_LIBRARIES ${CHECK_LIBRARY_EXISTS_LIBRARIES} CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_LIBRARY_EXISTS_DEFINITION} -DLINK_DIRECTORIES:STRING=${LOCATION} OUTPUT_VARIABLE OUTPUT) unset(_cle_source) if(${VARIABLE}) if(NOT CMAKE_REQUIRED_QUIET) message(CHECK_PASS "found") endif() set(${VARIABLE} 1 CACHE INTERNAL "Have library ${LIBRARY}") file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log "Determining if the function ${FUNCTION} exists in the ${LIBRARY} " "passed with the following output:\n" "${OUTPUT}\n\n") else() if(NOT CMAKE_REQUIRED_QUIET) message(CHECK_FAIL "not found") endif() set(${VARIABLE} "" CACHE INTERNAL "Have library ${LIBRARY}") file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log "Determining if the function ${FUNCTION} exists in the ${LIBRARY} " "failed with the following output:\n" "${OUTPUT}\n\n") endif() endif() endmacro() ================================================ FILE: external/libzip/cmake-compat/CheckSymbolExists.cmake ================================================ # Distributed under the OSI-approved BSD 3-Clause License. See accompanying # file Copyright.txt or https://cmake.org/licensing for details. #[=======================================================================[.rst: CheckSymbolExists ----------------- Provides a macro to check if a symbol exists as a function, variable, or macro in ``C``. .. command:: check_symbol_exists .. code-block:: cmake check_symbol_exists( ) Check that the ```` is available after including given header ```` and store the result in a ````. Specify the list of files in one argument as a semicolon-separated list. ```` will be created as an internal cache variable. If the header files define the symbol as a macro it is considered available and assumed to work. If the header files declare the symbol as a function or variable then the symbol must also be available for linking (so intrinsics may not be detected). If the symbol is a type, enum value, or intrinsic it will not be recognized (consider using :module:`CheckTypeSize` or :module:`CheckCSourceCompiles`). If the check needs to be done in C++, consider using :module:`CheckCXXSymbolExists` instead. The following variables may be set before calling this macro to modify the way the check is run: ``CMAKE_REQUIRED_FLAGS`` string of compile command line flags. ``CMAKE_REQUIRED_DEFINITIONS`` a :ref:`;-list ` of macros to define (-DFOO=bar). ``CMAKE_REQUIRED_INCLUDES`` a :ref:`;-list ` of header search paths to pass to the compiler. ``CMAKE_REQUIRED_LINK_OPTIONS`` a :ref:`;-list ` of options to add to the link command. ``CMAKE_REQUIRED_LIBRARIES`` a :ref:`;-list ` of libraries to add to the link command. See policy :policy:`CMP0075`. ``CMAKE_REQUIRED_QUIET`` execute quietly without messages. For example: .. code-block:: cmake include(CheckSymbolExists) # Check for macro SEEK_SET check_symbol_exists(SEEK_SET "stdio.h" HAVE_SEEK_SET) # Check for function fopen check_symbol_exists(fopen "stdio.h" HAVE_FOPEN) #]=======================================================================] if(__CheckSymbolExists_cmake__) return() endif() set(__CheckSymbolExists_cmake__ TRUE) cmake_policy(PUSH) cmake_policy(SET CMP0054 NEW) # if() quoted variables not dereferenced macro(CHECK_SYMBOL_EXISTS SYMBOL FILES VARIABLE) if(CMAKE_C_COMPILER_LOADED) __CHECK_SYMBOL_EXISTS_IMPL("${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckSymbolExists.c" "${SYMBOL}" "${FILES}" "${VARIABLE}" ) elseif(CMAKE_CXX_COMPILER_LOADED) __CHECK_SYMBOL_EXISTS_IMPL("${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckSymbolExists.cxx" "${SYMBOL}" "${FILES}" "${VARIABLE}" ) else() message(FATAL_ERROR "CHECK_SYMBOL_EXISTS needs either C or CXX language enabled") endif() endmacro() macro(__CHECK_SYMBOL_EXISTS_IMPL SOURCEFILE SYMBOL FILES VARIABLE) if(NOT DEFINED "${VARIABLE}" OR "x${${VARIABLE}}" STREQUAL "x${VARIABLE}") set(CMAKE_CONFIGURABLE_FILE_CONTENT "/* */\n") set(MACRO_CHECK_SYMBOL_EXISTS_FLAGS ${CMAKE_REQUIRED_FLAGS}) if(CMAKE_REQUIRED_LINK_OPTIONS) set(CHECK_SYMBOL_EXISTS_LINK_OPTIONS LINK_OPTIONS ${CMAKE_REQUIRED_LINK_OPTIONS}) else() set(CHECK_SYMBOL_EXISTS_LINK_OPTIONS) endif() if(CMAKE_REQUIRED_LIBRARIES) set(CHECK_SYMBOL_EXISTS_LIBS LINK_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES}) else() set(CHECK_SYMBOL_EXISTS_LIBS) endif() if(CMAKE_REQUIRED_INCLUDES) set(CMAKE_SYMBOL_EXISTS_INCLUDES "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_REQUIRED_INCLUDES}") else() set(CMAKE_SYMBOL_EXISTS_INCLUDES) endif() foreach(FILE ${FILES}) string(APPEND CMAKE_CONFIGURABLE_FILE_CONTENT "#include <${FILE}>\n") endforeach() string(APPEND CMAKE_CONFIGURABLE_FILE_CONTENT " int main(int argc, char** argv) { (void)argv;") set(_CSE_CHECK_NON_MACRO "return ((int*)(&${SYMBOL}))[argc];") if("${SYMBOL}" MATCHES "^[a-zA-Z_][a-zA-Z0-9_]*$") # The SYMBOL has a legal macro name. Test whether it exists as a macro. string(APPEND CMAKE_CONFIGURABLE_FILE_CONTENT " #ifndef ${SYMBOL} ${_CSE_CHECK_NON_MACRO} #else (void)argc; return 0; #endif") else() # The SYMBOL cannot be a macro (e.g., a template function). string(APPEND CMAKE_CONFIGURABLE_FILE_CONTENT " ${_CSE_CHECK_NON_MACRO}") endif() string(APPEND CMAKE_CONFIGURABLE_FILE_CONTENT " }") unset(_CSE_CHECK_NON_MACRO) configure_file("${CMAKE_ROOT}/Modules/CMakeConfigurableFile.in" "${SOURCEFILE}" @ONLY) if(NOT CMAKE_REQUIRED_QUIET) message(CHECK_START "Looking for ${SYMBOL}") endif() try_compile(${VARIABLE} ${CMAKE_BINARY_DIR} "${SOURCEFILE}" COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS} ${CHECK_SYMBOL_EXISTS_LINK_OPTIONS} ${CHECK_SYMBOL_EXISTS_LIBS} CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_SYMBOL_EXISTS_FLAGS} "${CMAKE_SYMBOL_EXISTS_INCLUDES}" OUTPUT_VARIABLE OUTPUT) if(${VARIABLE}) if(NOT CMAKE_REQUIRED_QUIET) message(CHECK_PASS "found") endif() set(${VARIABLE} 1 CACHE INTERNAL "Have symbol ${SYMBOL}") file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log "Determining if the ${SYMBOL} " "exist passed with the following output:\n" "${OUTPUT}\nFile ${SOURCEFILE}:\n" "${CMAKE_CONFIGURABLE_FILE_CONTENT}\n") else() if(NOT CMAKE_REQUIRED_QUIET) message(CHECK_FAIL "not found") endif() set(${VARIABLE} "" CACHE INTERNAL "Have symbol ${SYMBOL}") file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log "Determining if the ${SYMBOL} " "exist failed with the following output:\n" "${OUTPUT}\nFile ${SOURCEFILE}:\n" "${CMAKE_CONFIGURABLE_FILE_CONTENT}\n") endif() unset(CMAKE_CONFIGURABLE_FILE_CONTENT) endif() endmacro() cmake_policy(POP) ================================================ FILE: external/libzip/cmake-compat/FindBZip2.cmake ================================================ # Distributed under the OSI-approved BSD 3-Clause License. See accompanying # file Copyright.txt or https://cmake.org/licensing for details. #[=======================================================================[.rst: FindBZip2 --------- Try to find BZip2 IMPORTED Targets ^^^^^^^^^^^^^^^^ This module defines :prop_tgt:`IMPORTED` target ``BZip2::BZip2``, if BZip2 has been found. Result Variables ^^^^^^^^^^^^^^^^ This module defines the following variables: ``BZIP2_FOUND`` system has BZip2 ``BZIP2_INCLUDE_DIRS`` the BZip2 include directories ``BZIP2_LIBRARIES`` Link these to use BZip2 ``BZIP2_NEED_PREFIX`` this is set if the functions are prefixed with ``BZ2_`` ``BZIP2_VERSION_STRING`` the version of BZip2 found Cache variables ^^^^^^^^^^^^^^^ The following cache variables may also be set: ``BZIP2_INCLUDE_DIR`` the BZip2 include directory #]=======================================================================] set(_BZIP2_PATHS PATHS "[HKEY_LOCAL_MACHINE\\SOFTWARE\\GnuWin32\\Bzip2;InstallPath]" ) find_path(BZIP2_INCLUDE_DIR bzlib.h ${_BZIP2_PATHS} PATH_SUFFIXES include) if (NOT BZIP2_LIBRARIES) find_library(BZIP2_LIBRARY_RELEASE NAMES bz2 bzip2 libbz2 libbzip2 ${_BZIP2_PATHS} PATH_SUFFIXES lib) find_library(BZIP2_LIBRARY_DEBUG NAMES bz2d bzip2d libbz2d libbzip2d ${_BZIP2_PATHS} PATH_SUFFIXES lib) include(${CMAKE_CURRENT_LIST_DIR}/SelectLibraryConfigurations.cmake) SELECT_LIBRARY_CONFIGURATIONS(BZIP2) else () file(TO_CMAKE_PATH "${BZIP2_LIBRARIES}" BZIP2_LIBRARIES) endif () if (BZIP2_INCLUDE_DIR AND EXISTS "${BZIP2_INCLUDE_DIR}/bzlib.h") file(STRINGS "${BZIP2_INCLUDE_DIR}/bzlib.h" BZLIB_H REGEX "bzip2/libbzip2 version [0-9]+\\.[^ ]+ of [0-9]+ ") string(REGEX REPLACE ".* bzip2/libbzip2 version ([0-9]+\\.[^ ]+) of [0-9]+ .*" "\\1" BZIP2_VERSION_STRING "${BZLIB_H}") endif () include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake) FIND_PACKAGE_HANDLE_STANDARD_ARGS(BZip2 REQUIRED_VARS BZIP2_LIBRARIES BZIP2_INCLUDE_DIR VERSION_VAR BZIP2_VERSION_STRING) if (BZIP2_FOUND) set(BZIP2_INCLUDE_DIRS ${BZIP2_INCLUDE_DIR}) include(${CMAKE_CURRENT_LIST_DIR}/CheckSymbolExists.cmake) include(${CMAKE_CURRENT_LIST_DIR}/CMakePushCheckState.cmake) cmake_push_check_state() set(CMAKE_REQUIRED_QUIET ${BZip2_FIND_QUIETLY}) set(CMAKE_REQUIRED_INCLUDES ${BZIP2_INCLUDE_DIR}) set(CMAKE_REQUIRED_LIBRARIES ${BZIP2_LIBRARIES}) CHECK_SYMBOL_EXISTS(BZ2_bzCompressInit "bzlib.h" BZIP2_NEED_PREFIX) cmake_pop_check_state() if(NOT TARGET BZip2::BZip2) add_library(BZip2::BZip2 UNKNOWN IMPORTED) set_target_properties(BZip2::BZip2 PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${BZIP2_INCLUDE_DIRS}") if(BZIP2_LIBRARY_RELEASE) set_property(TARGET BZip2::BZip2 APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) set_target_properties(BZip2::BZip2 PROPERTIES IMPORTED_LOCATION_RELEASE "${BZIP2_LIBRARY_RELEASE}") endif() if(BZIP2_LIBRARY_DEBUG) set_property(TARGET BZip2::BZip2 APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG) set_target_properties(BZip2::BZip2 PROPERTIES IMPORTED_LOCATION_DEBUG "${BZIP2_LIBRARY_DEBUG}") endif() if(NOT BZIP2_LIBRARY_RELEASE AND NOT BZIP2_LIBRARY_DEBUG) set_property(TARGET BZip2::BZip2 APPEND PROPERTY IMPORTED_LOCATION "${BZIP2_LIBRARY}") endif() endif() endif () mark_as_advanced(BZIP2_INCLUDE_DIR) ================================================ FILE: external/libzip/cmake-compat/FindGnuTLS.cmake ================================================ # Distributed under the OSI-approved BSD 3-Clause License. See accompanying # file Copyright.txt or https://cmake.org/licensing for details. #[=======================================================================[.rst: FindGnuTLS ---------- Find the GNU Transport Layer Security library (gnutls) IMPORTED Targets ^^^^^^^^^^^^^^^^ This module defines :prop_tgt:`IMPORTED` target ``GnuTLS::GnuTLS``, if gnutls has been found. Result Variables ^^^^^^^^^^^^^^^^ ``GNUTLS_FOUND`` System has gnutls ``GNUTLS_INCLUDE_DIR`` The gnutls include directory ``GNUTLS_LIBRARIES`` The libraries needed to use gnutls ``GNUTLS_DEFINITIONS`` Compiler switches required for using gnutls ``GNUTLS_VERSION`` version of gnutls. #]=======================================================================] # Note that this doesn't try to find the gnutls-extra package. if (GNUTLS_INCLUDE_DIR AND GNUTLS_LIBRARY) # in cache already set(gnutls_FIND_QUIETLY TRUE) endif () if (NOT WIN32) # try using pkg-config to get the directories and then use these values # in the find_path() and find_library() calls # also fills in GNUTLS_DEFINITIONS, although that isn't normally useful find_package(PkgConfig QUIET) PKG_CHECK_MODULES(PC_GNUTLS QUIET gnutls) set(GNUTLS_DEFINITIONS ${PC_GNUTLS_CFLAGS_OTHER}) set(GNUTLS_VERSION ${PC_GNUTLS_VERSION}) # keep for backward compatibility set(GNUTLS_VERSION_STRING ${PC_GNUTLS_VERSION}) endif () find_path(GNUTLS_INCLUDE_DIR gnutls/gnutls.h HINTS ${PC_GNUTLS_INCLUDEDIR} ${PC_GNUTLS_INCLUDE_DIRS} ) find_library(GNUTLS_LIBRARY NAMES gnutls libgnutls HINTS ${PC_GNUTLS_LIBDIR} ${PC_GNUTLS_LIBRARY_DIRS} ) mark_as_advanced(GNUTLS_INCLUDE_DIR GNUTLS_LIBRARY) include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake) FIND_PACKAGE_HANDLE_STANDARD_ARGS(GnuTLS REQUIRED_VARS GNUTLS_LIBRARY GNUTLS_INCLUDE_DIR VERSION_VAR GNUTLS_VERSION_STRING) if(GNUTLS_FOUND) set(GNUTLS_LIBRARIES ${GNUTLS_LIBRARY}) set(GNUTLS_INCLUDE_DIRS ${GNUTLS_INCLUDE_DIR}) if(NOT TARGET GnuTLS::GnuTLS) add_library(GnuTLS::GnuTLS UNKNOWN IMPORTED) set_target_properties(GnuTLS::GnuTLS PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${GNUTLS_INCLUDE_DIRS}" INTERFACE_COMPILE_DEFINITIONS "${GNUTLS_DEFINITIONS}" IMPORTED_LINK_INTERFACE_LANGUAGES "C" IMPORTED_LOCATION "${GNUTLS_LIBRARIES}") endif() endif() ================================================ FILE: external/libzip/cmake-compat/FindLibLZMA.cmake ================================================ # Distributed under the OSI-approved BSD 3-Clause License. See accompanying # file Copyright.txt or https://cmake.org/licensing for details. #[=======================================================================[.rst: FindLibLZMA ----------- Find LZMA compression algorithm headers and library. Imported Targets ^^^^^^^^^^^^^^^^ This module defines :prop_tgt:`IMPORTED` target ``LibLZMA::LibLZMA``, if liblzma has been found. Result variables ^^^^^^^^^^^^^^^^ This module will set the following variables in your project: ``LIBLZMA_FOUND`` True if liblzma headers and library were found. ``LIBLZMA_INCLUDE_DIRS`` Directory where liblzma headers are located. ``LIBLZMA_LIBRARIES`` Lzma libraries to link against. ``LIBLZMA_HAS_AUTO_DECODER`` True if lzma_auto_decoder() is found (required). ``LIBLZMA_HAS_EASY_ENCODER`` True if lzma_easy_encoder() is found (required). ``LIBLZMA_HAS_LZMA_PRESET`` True if lzma_lzma_preset() is found (required). ``LIBLZMA_VERSION_MAJOR`` The major version of lzma ``LIBLZMA_VERSION_MINOR`` The minor version of lzma ``LIBLZMA_VERSION_PATCH`` The patch version of lzma ``LIBLZMA_VERSION_STRING`` version number as a string (ex: "5.0.3") #]=======================================================================] find_path(LIBLZMA_INCLUDE_DIR lzma.h ) if(NOT LIBLZMA_LIBRARY) find_library(LIBLZMA_LIBRARY_RELEASE NAMES lzma liblzma PATH_SUFFIXES lib) find_library(LIBLZMA_LIBRARY_DEBUG NAMES lzmad liblzmad PATH_SUFFIXES lib) include(${CMAKE_CURRENT_LIST_DIR}/SelectLibraryConfigurations.cmake) select_library_configurations(LIBLZMA) else() file(TO_CMAKE_PATH "${LIBLZMA_LIBRARY}" LIBLZMA_LIBRARY) endif() if(LIBLZMA_INCLUDE_DIR AND EXISTS "${LIBLZMA_INCLUDE_DIR}/lzma/version.h") file(STRINGS "${LIBLZMA_INCLUDE_DIR}/lzma/version.h" LIBLZMA_HEADER_CONTENTS REGEX "#define LZMA_VERSION_[A-Z]+ [0-9]+") string(REGEX REPLACE ".*#define LZMA_VERSION_MAJOR ([0-9]+).*" "\\1" LIBLZMA_VERSION_MAJOR "${LIBLZMA_HEADER_CONTENTS}") string(REGEX REPLACE ".*#define LZMA_VERSION_MINOR ([0-9]+).*" "\\1" LIBLZMA_VERSION_MINOR "${LIBLZMA_HEADER_CONTENTS}") string(REGEX REPLACE ".*#define LZMA_VERSION_PATCH ([0-9]+).*" "\\1" LIBLZMA_VERSION_PATCH "${LIBLZMA_HEADER_CONTENTS}") set(LIBLZMA_VERSION_STRING "${LIBLZMA_VERSION_MAJOR}.${LIBLZMA_VERSION_MINOR}.${LIBLZMA_VERSION_PATCH}") unset(LIBLZMA_HEADER_CONTENTS) endif() # We're using new code known now as XZ, even library still been called LZMA # it can be found in http://tukaani.org/xz/ # Avoid using old codebase if (LIBLZMA_LIBRARY) include(${CMAKE_CURRENT_LIST_DIR}/CheckLibraryExists.cmake) set(CMAKE_REQUIRED_QUIET_SAVE ${CMAKE_REQUIRED_QUIET}) set(CMAKE_REQUIRED_QUIET ${LibLZMA_FIND_QUIETLY}) if(NOT LIBLZMA_LIBRARY_RELEASE AND NOT LIBLZMA_LIBRARY_DEBUG) set(LIBLZMA_LIBRARY_check ${LIBLZMA_LIBRARY}) elseif(LIBLZMA_LIBRARY_RELEASE) set(LIBLZMA_LIBRARY_check ${LIBLZMA_LIBRARY_RELEASE}) elseif(LIBLZMA_LIBRARY_DEBUG) set(LIBLZMA_LIBRARY_check ${LIBLZMA_LIBRARY_DEBUG}) endif() CHECK_LIBRARY_EXISTS(${LIBLZMA_LIBRARY_check} lzma_auto_decoder "" LIBLZMA_HAS_AUTO_DECODER) CHECK_LIBRARY_EXISTS(${LIBLZMA_LIBRARY_check} lzma_easy_encoder "" LIBLZMA_HAS_EASY_ENCODER) CHECK_LIBRARY_EXISTS(${LIBLZMA_LIBRARY_check} lzma_lzma_preset "" LIBLZMA_HAS_LZMA_PRESET) unset(LIBLZMA_LIBRARY_check) set(CMAKE_REQUIRED_QUIET ${CMAKE_REQUIRED_QUIET_SAVE}) endif () include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake) find_package_handle_standard_args(LibLZMA REQUIRED_VARS LIBLZMA_LIBRARY LIBLZMA_INCLUDE_DIR LIBLZMA_HAS_AUTO_DECODER LIBLZMA_HAS_EASY_ENCODER LIBLZMA_HAS_LZMA_PRESET VERSION_VAR LIBLZMA_VERSION_STRING ) mark_as_advanced( LIBLZMA_INCLUDE_DIR LIBLZMA_LIBRARY ) if (LIBLZMA_FOUND) set(LIBLZMA_LIBRARIES ${LIBLZMA_LIBRARY}) set(LIBLZMA_INCLUDE_DIRS ${LIBLZMA_INCLUDE_DIR}) if(NOT TARGET LibLZMA::LibLZMA) add_library(LibLZMA::LibLZMA UNKNOWN IMPORTED) set_target_properties(LibLZMA::LibLZMA PROPERTIES INTERFACE_INCLUDE_DIRECTORIES ${LIBLZMA_INCLUDE_DIR} IMPORTED_LINK_INTERFACE_LANGUAGES C) if(LIBLZMA_LIBRARY_RELEASE) set_property(TARGET LibLZMA::LibLZMA APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) set_target_properties(LibLZMA::LibLZMA PROPERTIES IMPORTED_LOCATION_RELEASE "${LIBLZMA_LIBRARY_RELEASE}") endif() if(LIBLZMA_LIBRARY_DEBUG) set_property(TARGET LibLZMA::LibLZMA APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG) set_target_properties(LibLZMA::LibLZMA PROPERTIES IMPORTED_LOCATION_DEBUG "${LIBLZMA_LIBRARY_DEBUG}") endif() if(NOT LIBLZMA_LIBRARY_RELEASE AND NOT LIBLZMA_LIBRARY_DEBUG) set_target_properties(LibLZMA::LibLZMA PROPERTIES IMPORTED_LOCATION "${LIBLZMA_LIBRARY}") endif() endif() endif () ================================================ FILE: external/libzip/cmake-compat/FindPackageHandleStandardArgs.cmake ================================================ # Distributed under the OSI-approved BSD 3-Clause License. See accompanying # file Copyright.txt or https://cmake.org/licensing for details. #[=======================================================================[.rst: FindPackageHandleStandardArgs ----------------------------- This module provides a function intended to be used in :ref:`Find Modules` implementing :command:`find_package()` calls. It handles the ``REQUIRED``, ``QUIET`` and version-related arguments of ``find_package``. It also sets the ``_FOUND`` variable. The package is considered found if all variables listed contain valid results, e.g. valid filepaths. .. command:: find_package_handle_standard_args There are two signatures:: find_package_handle_standard_args( (DEFAULT_MSG|) ... ) find_package_handle_standard_args( [FOUND_VAR ] [REQUIRED_VARS ...] [VERSION_VAR ] [HANDLE_COMPONENTS] [CONFIG_MODE] [NAME_MISMATCHED] [REASON_FAILURE_MESSAGE ] [FAIL_MESSAGE ] ) The ``_FOUND`` variable will be set to ``TRUE`` if all the variables ``...`` are valid and any optional constraints are satisfied, and ``FALSE`` otherwise. A success or failure message may be displayed based on the results and on whether the ``REQUIRED`` and/or ``QUIET`` option was given to the :command:`find_package` call. The options are: ``(DEFAULT_MSG|)`` In the simple signature this specifies the failure message. Use ``DEFAULT_MSG`` to ask for a default message to be computed (recommended). Not valid in the full signature. ``FOUND_VAR `` Obsolete. Specifies either ``_FOUND`` or ``_FOUND`` as the result variable. This exists only for compatibility with older versions of CMake and is now ignored. Result variables of both names are always set for compatibility. ``REQUIRED_VARS ...`` Specify the variables which are required for this package. These may be named in the generated failure message asking the user to set the missing variable values. Therefore these should typically be cache entries such as ``FOO_LIBRARY`` and not output variables like ``FOO_LIBRARIES``. ``VERSION_VAR `` Specify the name of a variable that holds the version of the package that has been found. This version will be checked against the (potentially) specified required version given to the :command:`find_package` call, including its ``EXACT`` option. The default messages include information about the required version and the version which has been actually found, both if the version is ok or not. ``HANDLE_COMPONENTS`` Enable handling of package components. In this case, the command will report which components have been found and which are missing, and the ``_FOUND`` variable will be set to ``FALSE`` if any of the required components (i.e. not the ones listed after the ``OPTIONAL_COMPONENTS`` option of :command:`find_package`) are missing. ``CONFIG_MODE`` Specify that the calling find module is a wrapper around a call to ``find_package( NO_MODULE)``. This implies a ``VERSION_VAR`` value of ``_VERSION``. The command will automatically check whether the package configuration file was found. ``REASON_FAILURE_MESSAGE `` Specify a custom message of the reason for the failure which will be appended to the default generated message. ``FAIL_MESSAGE `` Specify a custom failure message instead of using the default generated message. Not recommended. ``NAME_MISMATCHED`` Indicate that the ```` does not match ``${CMAKE_FIND_PACKAGE_NAME}``. This is usually a mistake and raises a warning, but it may be intentional for usage of the command for components of a larger package. Example for the simple signature: .. code-block:: cmake find_package_handle_standard_args(LibXml2 DEFAULT_MSG LIBXML2_LIBRARY LIBXML2_INCLUDE_DIR) The ``LibXml2`` package is considered to be found if both ``LIBXML2_LIBRARY`` and ``LIBXML2_INCLUDE_DIR`` are valid. Then also ``LibXml2_FOUND`` is set to ``TRUE``. If it is not found and ``REQUIRED`` was used, it fails with a :command:`message(FATAL_ERROR)`, independent whether ``QUIET`` was used or not. If it is found, success will be reported, including the content of the first ````. On repeated CMake runs, the same message will not be printed again. .. note:: If ```` does not match ``CMAKE_FIND_PACKAGE_NAME`` for the calling module, a warning that there is a mismatch is given. The ``FPHSA_NAME_MISMATCHED`` variable may be set to bypass the warning if using the old signature and the ``NAME_MISMATCHED`` argument using the new signature. To avoid forcing the caller to require newer versions of CMake for usage, the variable's value will be used if defined when the ``NAME_MISMATCHED`` argument is not passed for the new signature (but using both is an error).. Example for the full signature: .. code-block:: cmake find_package_handle_standard_args(LibArchive REQUIRED_VARS LibArchive_LIBRARY LibArchive_INCLUDE_DIR VERSION_VAR LibArchive_VERSION) In this case, the ``LibArchive`` package is considered to be found if both ``LibArchive_LIBRARY`` and ``LibArchive_INCLUDE_DIR`` are valid. Also the version of ``LibArchive`` will be checked by using the version contained in ``LibArchive_VERSION``. Since no ``FAIL_MESSAGE`` is given, the default messages will be printed. Another example for the full signature: .. code-block:: cmake find_package(Automoc4 QUIET NO_MODULE HINTS /opt/automoc4) find_package_handle_standard_args(Automoc4 CONFIG_MODE) In this case, a ``FindAutmoc4.cmake`` module wraps a call to ``find_package(Automoc4 NO_MODULE)`` and adds an additional search directory for ``automoc4``. Then the call to ``find_package_handle_standard_args`` produces a proper success/failure message. #]=======================================================================] include(${CMAKE_CURRENT_LIST_DIR}/FindPackageMessage.cmake) # internal helper macro macro(_FPHSA_FAILURE_MESSAGE _msg) set (__msg "${_msg}") if (FPHSA_REASON_FAILURE_MESSAGE) string(APPEND __msg "\n Reason given by package: ${FPHSA_REASON_FAILURE_MESSAGE}\n") endif() if (${_NAME}_FIND_REQUIRED) message(FATAL_ERROR "${__msg}") else () if (NOT ${_NAME}_FIND_QUIETLY) message(STATUS "${__msg}") endif () endif () endmacro() # internal helper macro to generate the failure message when used in CONFIG_MODE: macro(_FPHSA_HANDLE_FAILURE_CONFIG_MODE) # _CONFIG is set, but FOUND is false, this means that some other of the REQUIRED_VARS was not found: if(${_NAME}_CONFIG) _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: missing:${MISSING_VARS} (found ${${_NAME}_CONFIG} ${VERSION_MSG})") else() # If _CONSIDERED_CONFIGS is set, the config-file has been found, but no suitable version. # List them all in the error message: if(${_NAME}_CONSIDERED_CONFIGS) set(configsText "") list(LENGTH ${_NAME}_CONSIDERED_CONFIGS configsCount) math(EXPR configsCount "${configsCount} - 1") foreach(currentConfigIndex RANGE ${configsCount}) list(GET ${_NAME}_CONSIDERED_CONFIGS ${currentConfigIndex} filename) list(GET ${_NAME}_CONSIDERED_VERSIONS ${currentConfigIndex} version) string(APPEND configsText "\n ${filename} (version ${version})") endforeach() if (${_NAME}_NOT_FOUND_MESSAGE) if (FPHSA_REASON_FAILURE_MESSAGE) string(PREPEND FPHSA_REASON_FAILURE_MESSAGE "${${_NAME}_NOT_FOUND_MESSAGE}\n ") else() set(FPHSA_REASON_FAILURE_MESSAGE "${${_NAME}_NOT_FOUND_MESSAGE}") endif() else() string(APPEND configsText "\n") endif() _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE} ${VERSION_MSG}, checked the following files:${configsText}") else() # Simple case: No Config-file was found at all: _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: found neither ${_NAME}Config.cmake nor ${_NAME_LOWER}-config.cmake ${VERSION_MSG}") endif() endif() endmacro() function(FIND_PACKAGE_HANDLE_STANDARD_ARGS _NAME _FIRST_ARG) # Set up the arguments for `cmake_parse_arguments`. set(options CONFIG_MODE HANDLE_COMPONENTS NAME_MISMATCHED) set(oneValueArgs FAIL_MESSAGE REASON_FAILURE_MESSAGE VERSION_VAR FOUND_VAR) set(multiValueArgs REQUIRED_VARS) # Check whether we are in 'simple' or 'extended' mode: set(_KEYWORDS_FOR_EXTENDED_MODE ${options} ${oneValueArgs} ${multiValueArgs} ) list(FIND _KEYWORDS_FOR_EXTENDED_MODE "${_FIRST_ARG}" INDEX) unset(FPHSA_NAME_MISMATCHED_override) if (DEFINED FPHSA_NAME_MISMATCHED) # If the variable NAME_MISMATCHED variable is set, error if it is passed as # an argument. The former is for old signatures, the latter is for new # signatures. list(FIND ARGN "NAME_MISMATCHED" name_mismatched_idx) if (NOT name_mismatched_idx EQUAL "-1") message(FATAL_ERROR "The `NAME_MISMATCHED` argument may only be specified by the argument or " "the variable, not both.") endif () # But use the variable if it is not an argument to avoid forcing minimum # CMake version bumps for calling modules. set(FPHSA_NAME_MISMATCHED_override "${FPHSA_NAME_MISMATCHED}") endif () if(${INDEX} EQUAL -1) set(FPHSA_FAIL_MESSAGE ${_FIRST_ARG}) set(FPHSA_REQUIRED_VARS ${ARGN}) set(FPHSA_VERSION_VAR) else() cmake_parse_arguments(FPHSA "${options}" "${oneValueArgs}" "${multiValueArgs}" ${_FIRST_ARG} ${ARGN}) if(FPHSA_UNPARSED_ARGUMENTS) message(FATAL_ERROR "Unknown keywords given to FIND_PACKAGE_HANDLE_STANDARD_ARGS(): \"${FPHSA_UNPARSED_ARGUMENTS}\"") endif() if(NOT FPHSA_FAIL_MESSAGE) set(FPHSA_FAIL_MESSAGE "DEFAULT_MSG") endif() # In config-mode, we rely on the variable _CONFIG, which is set by find_package() # when it successfully found the config-file, including version checking: if(FPHSA_CONFIG_MODE) list(INSERT FPHSA_REQUIRED_VARS 0 ${_NAME}_CONFIG) list(REMOVE_DUPLICATES FPHSA_REQUIRED_VARS) set(FPHSA_VERSION_VAR ${_NAME}_VERSION) endif() if(NOT FPHSA_REQUIRED_VARS) message(FATAL_ERROR "No REQUIRED_VARS specified for FIND_PACKAGE_HANDLE_STANDARD_ARGS()") endif() endif() if (DEFINED FPHSA_NAME_MISMATCHED_override) set(FPHSA_NAME_MISMATCHED "${FPHSA_NAME_MISMATCHED_override}") endif () if (DEFINED CMAKE_FIND_PACKAGE_NAME AND NOT FPHSA_NAME_MISMATCHED AND NOT _NAME STREQUAL CMAKE_FIND_PACKAGE_NAME) message(AUTHOR_WARNING "The package name passed to `find_package_handle_standard_args` " "(${_NAME}) does not match the name of the calling package " "(${CMAKE_FIND_PACKAGE_NAME}). This can lead to problems in calling " "code that expects `find_package` result variables (e.g., `_FOUND`) " "to follow a certain pattern.") endif () # now that we collected all arguments, process them if("x${FPHSA_FAIL_MESSAGE}" STREQUAL "xDEFAULT_MSG") set(FPHSA_FAIL_MESSAGE "Could NOT find ${_NAME}") endif() list(GET FPHSA_REQUIRED_VARS 0 _FIRST_REQUIRED_VAR) string(TOUPPER ${_NAME} _NAME_UPPER) string(TOLOWER ${_NAME} _NAME_LOWER) if(FPHSA_FOUND_VAR) set(_FOUND_VAR_UPPER ${_NAME_UPPER}_FOUND) set(_FOUND_VAR_MIXED ${_NAME}_FOUND) if(FPHSA_FOUND_VAR STREQUAL _FOUND_VAR_MIXED OR FPHSA_FOUND_VAR STREQUAL _FOUND_VAR_UPPER) set(_FOUND_VAR ${FPHSA_FOUND_VAR}) else() message(FATAL_ERROR "The argument for FOUND_VAR is \"${FPHSA_FOUND_VAR}\", but only \"${_FOUND_VAR_MIXED}\" and \"${_FOUND_VAR_UPPER}\" are valid names.") endif() else() set(_FOUND_VAR ${_NAME_UPPER}_FOUND) endif() # collect all variables which were not found, so they can be printed, so the # user knows better what went wrong (#6375) set(MISSING_VARS "") set(DETAILS "") # check if all passed variables are valid set(FPHSA_FOUND_${_NAME} TRUE) foreach(_CURRENT_VAR ${FPHSA_REQUIRED_VARS}) if(NOT ${_CURRENT_VAR}) set(FPHSA_FOUND_${_NAME} FALSE) string(APPEND MISSING_VARS " ${_CURRENT_VAR}") else() string(APPEND DETAILS "[${${_CURRENT_VAR}}]") endif() endforeach() if(FPHSA_FOUND_${_NAME}) set(${_NAME}_FOUND TRUE) set(${_NAME_UPPER}_FOUND TRUE) else() set(${_NAME}_FOUND FALSE) set(${_NAME_UPPER}_FOUND FALSE) endif() # component handling unset(FOUND_COMPONENTS_MSG) unset(MISSING_COMPONENTS_MSG) if(FPHSA_HANDLE_COMPONENTS) foreach(comp ${${_NAME}_FIND_COMPONENTS}) if(${_NAME}_${comp}_FOUND) if(NOT DEFINED FOUND_COMPONENTS_MSG) set(FOUND_COMPONENTS_MSG "found components:") endif() string(APPEND FOUND_COMPONENTS_MSG " ${comp}") else() if(NOT DEFINED MISSING_COMPONENTS_MSG) set(MISSING_COMPONENTS_MSG "missing components:") endif() string(APPEND MISSING_COMPONENTS_MSG " ${comp}") if(${_NAME}_FIND_REQUIRED_${comp}) set(${_NAME}_FOUND FALSE) string(APPEND MISSING_VARS " ${comp}") endif() endif() endforeach() set(COMPONENT_MSG "${FOUND_COMPONENTS_MSG} ${MISSING_COMPONENTS_MSG}") string(APPEND DETAILS "[c${COMPONENT_MSG}]") endif() # version handling: set(VERSION_MSG "") set(VERSION_OK TRUE) # check with DEFINED here as the requested or found version may be "0" if (DEFINED ${_NAME}_FIND_VERSION) if(DEFINED ${FPHSA_VERSION_VAR}) set(_FOUND_VERSION ${${FPHSA_VERSION_VAR}}) if(${_NAME}_FIND_VERSION_EXACT) # exact version required # count the dots in the version string string(REGEX REPLACE "[^.]" "" _VERSION_DOTS "${_FOUND_VERSION}") # add one dot because there is one dot more than there are components string(LENGTH "${_VERSION_DOTS}." _VERSION_DOTS) if (_VERSION_DOTS GREATER ${_NAME}_FIND_VERSION_COUNT) # Because of the C++ implementation of find_package() ${_NAME}_FIND_VERSION_COUNT # is at most 4 here. Therefore a simple lookup table is used. if (${_NAME}_FIND_VERSION_COUNT EQUAL 1) set(_VERSION_REGEX "[^.]*") elseif (${_NAME}_FIND_VERSION_COUNT EQUAL 2) set(_VERSION_REGEX "[^.]*\\.[^.]*") elseif (${_NAME}_FIND_VERSION_COUNT EQUAL 3) set(_VERSION_REGEX "[^.]*\\.[^.]*\\.[^.]*") else () set(_VERSION_REGEX "[^.]*\\.[^.]*\\.[^.]*\\.[^.]*") endif () string(REGEX REPLACE "^(${_VERSION_REGEX})\\..*" "\\1" _VERSION_HEAD "${_FOUND_VERSION}") unset(_VERSION_REGEX) if (NOT ${_NAME}_FIND_VERSION VERSION_EQUAL _VERSION_HEAD) set(VERSION_MSG "Found unsuitable version \"${_FOUND_VERSION}\", but required is exact version \"${${_NAME}_FIND_VERSION}\"") set(VERSION_OK FALSE) else () set(VERSION_MSG "(found suitable exact version \"${_FOUND_VERSION}\")") endif () unset(_VERSION_HEAD) else () if (NOT ${_NAME}_FIND_VERSION VERSION_EQUAL _FOUND_VERSION) set(VERSION_MSG "Found unsuitable version \"${_FOUND_VERSION}\", but required is exact version \"${${_NAME}_FIND_VERSION}\"") set(VERSION_OK FALSE) else () set(VERSION_MSG "(found suitable exact version \"${_FOUND_VERSION}\")") endif () endif () unset(_VERSION_DOTS) else() # minimum version specified: if (${_NAME}_FIND_VERSION VERSION_GREATER _FOUND_VERSION) set(VERSION_MSG "Found unsuitable version \"${_FOUND_VERSION}\", but required is at least \"${${_NAME}_FIND_VERSION}\"") set(VERSION_OK FALSE) else () set(VERSION_MSG "(found suitable version \"${_FOUND_VERSION}\", minimum required is \"${${_NAME}_FIND_VERSION}\")") endif () endif() else() # if the package was not found, but a version was given, add that to the output: if(${_NAME}_FIND_VERSION_EXACT) set(VERSION_MSG "(Required is exact version \"${${_NAME}_FIND_VERSION}\")") else() set(VERSION_MSG "(Required is at least version \"${${_NAME}_FIND_VERSION}\")") endif() endif() else () # Check with DEFINED as the found version may be 0. if(DEFINED ${FPHSA_VERSION_VAR}) set(VERSION_MSG "(found version \"${${FPHSA_VERSION_VAR}}\")") endif() endif () if(VERSION_OK) string(APPEND DETAILS "[v${${FPHSA_VERSION_VAR}}(${${_NAME}_FIND_VERSION})]") else() set(${_NAME}_FOUND FALSE) endif() # print the result: if (${_NAME}_FOUND) FIND_PACKAGE_MESSAGE(${_NAME} "Found ${_NAME}: ${${_FIRST_REQUIRED_VAR}} ${VERSION_MSG} ${COMPONENT_MSG}" "${DETAILS}") else () if(FPHSA_CONFIG_MODE) _FPHSA_HANDLE_FAILURE_CONFIG_MODE() else() if(NOT VERSION_OK) _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: ${VERSION_MSG} (found ${${_FIRST_REQUIRED_VAR}})") else() _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE} (missing:${MISSING_VARS}) ${VERSION_MSG}") endif() endif() endif () set(${_NAME}_FOUND ${${_NAME}_FOUND} PARENT_SCOPE) set(${_NAME_UPPER}_FOUND ${${_NAME}_FOUND} PARENT_SCOPE) endfunction() ================================================ FILE: external/libzip/cmake-compat/FindPackageMessage.cmake ================================================ # Distributed under the OSI-approved BSD 3-Clause License. See accompanying # file Copyright.txt or https://cmake.org/licensing for details. #[=======================================================================[.rst: FindPackageMessage ------------------ .. code-block:: cmake find_package_message( "message for user" "find result details") This function is intended to be used in FindXXX.cmake modules files. It will print a message once for each unique find result. This is useful for telling the user where a package was found. The first argument specifies the name (XXX) of the package. The second argument specifies the message to display. The third argument lists details about the find result so that if they change the message will be displayed again. The macro also obeys the QUIET argument to the find_package command. Example: .. code-block:: cmake if(X11_FOUND) find_package_message(X11 "Found X11: ${X11_X11_LIB}" "[${X11_X11_LIB}][${X11_INCLUDE_DIR}]") else() ... endif() #]=======================================================================] function(find_package_message pkg msg details) # Avoid printing a message repeatedly for the same find result. if(NOT ${pkg}_FIND_QUIETLY) string(REPLACE "\n" "" details "${details}") set(DETAILS_VAR FIND_PACKAGE_MESSAGE_DETAILS_${pkg}) if(NOT "${details}" STREQUAL "${${DETAILS_VAR}}") # The message has not yet been printed. message(STATUS "${msg}") # Save the find details in the cache to avoid printing the same # message again. set("${DETAILS_VAR}" "${details}" CACHE INTERNAL "Details about finding ${pkg}") endif() endif() endfunction() ================================================ FILE: external/libzip/cmake-compat/SelectLibraryConfigurations.cmake ================================================ # Distributed under the OSI-approved BSD 3-Clause License. See accompanying # file Copyright.txt or https://cmake.org/licensing for details. #[=======================================================================[.rst: SelectLibraryConfigurations --------------------------- .. code-block:: cmake select_library_configurations(basename) This macro takes a library base name as an argument, and will choose good values for the variables :: basename_LIBRARY basename_LIBRARIES basename_LIBRARY_DEBUG basename_LIBRARY_RELEASE depending on what has been found and set. If only ``basename_LIBRARY_RELEASE`` is defined, ``basename_LIBRARY`` will be set to the release value, and ``basename_LIBRARY_DEBUG`` will be set to ``basename_LIBRARY_DEBUG-NOTFOUND``. If only ``basename_LIBRARY_DEBUG`` is defined, then ``basename_LIBRARY`` will take the debug value, and ``basename_LIBRARY_RELEASE`` will be set to ``basename_LIBRARY_RELEASE-NOTFOUND``. If the generator supports configuration types, then ``basename_LIBRARY`` and ``basename_LIBRARIES`` will be set with debug and optimized flags specifying the library to be used for the given configuration. If no build type has been set or the generator in use does not support configuration types, then ``basename_LIBRARY`` and ``basename_LIBRARIES`` will take only the release value, or the debug value if the release one is not set. #]=======================================================================] # This macro was adapted from the FindQt4 CMake module and is maintained by Will # Dicharry . macro(select_library_configurations basename) if(NOT ${basename}_LIBRARY_RELEASE) set(${basename}_LIBRARY_RELEASE "${basename}_LIBRARY_RELEASE-NOTFOUND" CACHE FILEPATH "Path to a library.") endif() if(NOT ${basename}_LIBRARY_DEBUG) set(${basename}_LIBRARY_DEBUG "${basename}_LIBRARY_DEBUG-NOTFOUND" CACHE FILEPATH "Path to a library.") endif() get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) if( ${basename}_LIBRARY_DEBUG AND ${basename}_LIBRARY_RELEASE AND NOT ${basename}_LIBRARY_DEBUG STREQUAL ${basename}_LIBRARY_RELEASE AND ( _isMultiConfig OR CMAKE_BUILD_TYPE ) ) # if the generator is multi-config or if CMAKE_BUILD_TYPE is set for # single-config generators, set optimized and debug libraries set( ${basename}_LIBRARY "" ) foreach( _libname IN LISTS ${basename}_LIBRARY_RELEASE ) list( APPEND ${basename}_LIBRARY optimized "${_libname}" ) endforeach() foreach( _libname IN LISTS ${basename}_LIBRARY_DEBUG ) list( APPEND ${basename}_LIBRARY debug "${_libname}" ) endforeach() elseif( ${basename}_LIBRARY_RELEASE ) set( ${basename}_LIBRARY ${${basename}_LIBRARY_RELEASE} ) elseif( ${basename}_LIBRARY_DEBUG ) set( ${basename}_LIBRARY ${${basename}_LIBRARY_DEBUG} ) else() set( ${basename}_LIBRARY "${basename}_LIBRARY-NOTFOUND") endif() set( ${basename}_LIBRARIES "${${basename}_LIBRARY}" ) if( ${basename}_LIBRARY ) set( ${basename}_FOUND TRUE ) endif() mark_as_advanced( ${basename}_LIBRARY_RELEASE ${basename}_LIBRARY_DEBUG ) endmacro() ================================================ FILE: external/libzip/config.h.in ================================================ #ifndef HAD_CONFIG_H #define HAD_CONFIG_H #ifndef _HAD_ZIPCONF_H #include "zipconf.h" #endif /* BEGIN DEFINES */ #cmakedefine ENABLE_FDOPEN #cmakedefine HAVE___PROGNAME #cmakedefine HAVE__CLOSE #cmakedefine HAVE__DUP #cmakedefine HAVE__FDOPEN #cmakedefine HAVE__FILENO #cmakedefine HAVE__FSEEKI64 #cmakedefine HAVE__FSTAT64 #cmakedefine HAVE__SETMODE #cmakedefine HAVE__SNPRINTF #cmakedefine HAVE__SNPRINTF_S #cmakedefine HAVE__SNWPRINTF_S #cmakedefine HAVE__STAT64 #cmakedefine HAVE__STRDUP #cmakedefine HAVE__STRICMP #cmakedefine HAVE__STRTOI64 #cmakedefine HAVE__STRTOUI64 #cmakedefine HAVE__UNLINK #cmakedefine HAVE_ARC4RANDOM #cmakedefine HAVE_CLONEFILE #cmakedefine HAVE_COMMONCRYPTO #cmakedefine HAVE_CRYPTO #cmakedefine HAVE_FICLONERANGE #cmakedefine HAVE_FILENO #cmakedefine HAVE_FCHMOD #cmakedefine HAVE_FSEEKO #cmakedefine HAVE_FTELLO #cmakedefine HAVE_GETPROGNAME #cmakedefine HAVE_GETSECURITYINFO #cmakedefine HAVE_GNUTLS #cmakedefine HAVE_LIBBZ2 #cmakedefine HAVE_LIBLZMA #cmakedefine HAVE_LIBZSTD #cmakedefine HAVE_LOCALTIME_R #cmakedefine HAVE_LOCALTIME_S #cmakedefine HAVE_MEMCPY_S #cmakedefine HAVE_MBEDTLS #cmakedefine HAVE_MKSTEMP #cmakedefine HAVE_OPENSSL #cmakedefine HAVE_SETMODE #cmakedefine HAVE_SNPRINTF #cmakedefine HAVE_SNPRINTF_S #cmakedefine HAVE_STRCASECMP #cmakedefine HAVE_STRDUP #cmakedefine HAVE_STRERROR_S #cmakedefine HAVE_STRERRORLEN_S #cmakedefine HAVE_STRICMP #cmakedefine HAVE_STRNCPY_S #cmakedefine HAVE_STRTOLL #cmakedefine HAVE_STRTOULL #cmakedefine HAVE_STRUCT_TM_TM_ZONE #cmakedefine HAVE_STDBOOL_H #cmakedefine HAVE_STRINGS_H #cmakedefine HAVE_UNISTD_H #cmakedefine HAVE_WINDOWS_CRYPTO #cmakedefine SIZEOF_OFF_T ${SIZEOF_OFF_T} #cmakedefine SIZEOF_SIZE_T ${SIZEOF_SIZE_T} #cmakedefine HAVE_DIRENT_H #cmakedefine HAVE_FTS_H #cmakedefine HAVE_NDIR_H #cmakedefine HAVE_SYS_DIR_H #cmakedefine HAVE_SYS_NDIR_H #cmakedefine WORDS_BIGENDIAN #cmakedefine HAVE_SHARED /* END DEFINES */ #define PACKAGE "@CMAKE_PROJECT_NAME@" #define VERSION "@CMAKE_PROJECT_VERSION@" #endif /* HAD_CONFIG_H */ ================================================ FILE: external/libzip/examples/CMakeLists.txt ================================================ foreach(PROGRAM add-compressed-data autoclose-archive in-memory) add_executable(${PROGRAM} ${PROGRAM}.c) target_link_libraries(${PROGRAM} zip) target_include_directories(${PROGRAM} PRIVATE BEFORE ${PROJECT_SOURCE_DIR}/lib ${PROJECT_BINARY_DIR}) endforeach() ================================================ FILE: external/libzip/examples/add-compressed-data.c ================================================ /* add-compressed-data.c -- add already compressed file to zip archive Copyright (C) 2022-2023 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* This layered source can be used to add pre-compressed data to a zip archive. The data is taken from the lower layer source. Metadata (uncompressed size, crc, compression method) must be provided by the caller. */ #include #include #include #include struct ctx { zip_uint64_t uncompressed_size; zip_uint32_t crc; zip_uint32_t compression_method; }; zip_int64_t callback(zip_source_t* src, void *ud, void* data, zip_uint64_t length, zip_source_cmd_t command) { struct ctx* ctx = (struct ctx*)ud; switch (command) { case ZIP_SOURCE_FREE: /* Free our context. */ free(ctx); return 0; case ZIP_SOURCE_STAT: { zip_stat_t *st = (zip_stat_t *)data; /* Fix metadata with provided values. */ if (st->valid & ZIP_STAT_SIZE) { st->comp_size = st->size; st->valid |= ZIP_STAT_COMP_SIZE; } st->size = ctx->uncompressed_size; st->crc = ctx->crc; st->comp_method = ctx->compression_method; st->valid |= ZIP_STAT_COMP_METHOD | ZIP_STAT_SIZE | ZIP_STAT_CRC; return 0; } default: /* For all other commands, use default implementation */ return zip_source_pass_to_lower_layer(src, data, length, command); } } zip_source_t* create_layered_compressed_source(zip_source_t* source, zip_uint64_t uncompressed_size, zip_uint32_t crc, zip_uint32_t compression_method, zip_error_t *error) { struct ctx* ctx = (struct ctx*)malloc(sizeof(*ctx)); zip_source_t *compressed_source; /* Allocate context. */ if (ctx == NULL) { zip_error_set(error, ZIP_ER_MEMORY, 0); return NULL; } /* Initialize context */ ctx->compression_method = compression_method; ctx->uncompressed_size = uncompressed_size; ctx->crc = crc; /* Create layered source using our callback and context. */ compressed_source = zip_source_layered_create(source, callback, ctx, error); /* In case of error, free context. */ if (compressed_source == NULL) { free(ctx); } return compressed_source; } /* This is the information needed to add pre-compressed data to a zip archive. data must be compressed in a format compatible with Zip (e.g. no gzip header for deflate). */ zip_uint16_t compression_method = ZIP_CM_DEFLATE; zip_uint64_t uncompressed_size = 60; zip_uint32_t crc = 0xb0354048; zip_uint8_t data[] = { 0x4B, 0x4C, 0x44, 0x06, 0x5C, 0x49, 0x28, 0x80, 0x2B, 0x11, 0x55 ,0x36, 0x19, 0x05, 0x70, 0x01, 0x00 }; int main(int argc, char *argv[]) { const char *archive; zip_source_t *src, *src_comp; zip_t *za; int err; if (argc != 2) { fprintf(stderr, "usage: %s archive\n", argv[0]); return 1; } archive = argv[1]; if ((za = zip_open(archive, ZIP_CREATE, &err)) == NULL) { zip_error_t error; zip_error_init_with_code(&error, err); fprintf(stderr, "%s: cannot open zip archive '%s': %s\n", argv[0], archive, zip_error_strerror(&error)); zip_error_fini(&error); exit(1); } /* The data can come from any source. To keep the example simple, it is provided in a static buffer here. */ if ((src = zip_source_buffer(za, data, sizeof(data), 0)) == NULL) { fprintf(stderr, "%s: cannot create buffer source: %s\n", argv[0], zip_strerror(za)); zip_discard(za); exit(1); } zip_error_t error; if ((src_comp = create_layered_compressed_source(src, uncompressed_size, crc, compression_method, &error)) == NULL) { fprintf(stderr, "%s: cannot create layered source: %s\n", argv[0], zip_error_strerror(&error)); zip_source_free(src); zip_discard(za); exit(1); } if ((zip_file_add(za, "precompressed", src_comp, 0)) < 0) { fprintf(stderr, "%s: cannot add precompressed file: %s\n", argv[0], zip_strerror(za)); zip_source_free(src_comp); zip_discard(za); exit(1); } if ((zip_close(za)) < 0) { fprintf(stderr, "%s: cannot close archive '%s': %s\n", argv[0], archive, zip_strerror(za)); zip_discard(za); exit(1); } exit(0); } ================================================ FILE: external/libzip/examples/autoclose-archive.c ================================================ /* autoclose-archive.c -- automatically close archive when source is closed Copyright (C) 2022-2023 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* This example layered source takes ownership of a zip archive and discards it when the source is freed. It can be used to add files from various zip archives without having to keep track of them yourself. */ #include #include #include #include struct ctx { zip_t* archive; }; zip_int64_t callback(zip_source_t* src, void *ud, void* data, zip_uint64_t length, zip_source_cmd_t command) { struct ctx* ctx = (struct ctx*)ud; switch (command) { case ZIP_SOURCE_FREE: /* Close zip archive we took ownership of */ zip_discard(ctx->archive); /* Free our own context */ free(ctx); return 0; default: /* For all other commands, use default implementation */ return zip_source_pass_to_lower_layer(src, data, length, command); } } zip_source_t* create_layered_autoclose(zip_source_t* source, zip_t *archive, zip_error_t *error) { struct ctx* ctx = (struct ctx*)malloc(sizeof(*ctx)); zip_source_t *autoclose_source; /* Allocate context. */ if (ctx == NULL) { zip_error_set(error, ZIP_ER_MEMORY, 0); return NULL; } /* Initialize context */ ctx->archive = archive; /* Create layered source using our callback and context. */ autoclose_source = zip_source_layered_create(source, callback, ctx, error); /* In case of error, free context. */ if (autoclose_source == NULL) { free(ctx); } return autoclose_source; } int main(int argc, char *argv[]) { const char *destination_archive, *source_archive, *source_file; zip_int64_t index; zip_source_t *src, *src_autoclose; zip_t *z_source, *z_destination; int err; if (argc != 4) { fprintf(stderr, "usage: %s destination-archive source-archive source-file\n", argv[0]); return 1; } destination_archive = argv[1]; source_archive = argv[2]; source_file = argv[3]; if ((z_source = zip_open(source_archive, 0, &err)) == NULL) { zip_error_t error; zip_error_init_with_code(&error, err); fprintf(stderr, "%s: cannot open zip archive '%s': %s\n", argv[0], source_archive, zip_error_strerror(&error)); zip_error_fini(&error); exit(1); } if ((index = zip_name_locate(z_source, source_file, 0)) < 0) { fprintf(stderr, "%s: cannot find file '%s' in '%s': %s\n", argv[0], source_file, source_archive, zip_strerror(z_source)); zip_discard(z_source); exit(1); } if ((src = zip_source_zip_file(z_source, z_source, index, 0, 0, -1, NULL)) == NULL) { fprintf(stderr, "%s: cannot open file '%s' in '%s': %s\n", argv[0], source_file, source_archive, zip_strerror(z_source)); zip_discard(z_source); exit(1); } zip_error_t error; if ((src_autoclose = create_layered_autoclose(src, z_source, &error)) == NULL) { fprintf(stderr, "%s: cannot create layered source: %s\n", argv[0], zip_error_strerror(&error)); zip_source_free(src); zip_discard(z_source); exit(1); } if ((z_destination = zip_open(destination_archive, ZIP_CREATE, &err)) == NULL) { zip_error_init_with_code(&error, err); fprintf(stderr, "%s: cannot open zip archive '%s': %s\n", argv[0], destination_archive, zip_error_strerror(&error)); zip_error_fini(&error); zip_source_free(src_autoclose); /* freeing src_autoclose closes z_source */ exit(1); } if ((zip_file_add(z_destination, source_file, src_autoclose, 0)) < 0) { fprintf(stderr, "%s: cannot add file: %s\n", argv[0], zip_strerror(z_source)); zip_source_free(src_autoclose); zip_discard(z_destination); exit(1); } if ((zip_close(z_destination)) < 0) { fprintf(stderr, "%s: cannot close archive '%s': %s\n", argv[0], destination_archive, zip_strerror(z_source)); zip_discard(z_destination); exit(1); } exit(0); } ================================================ FILE: external/libzip/examples/cmake-project/CMakeLists.txt ================================================ cmake_minimum_required(VERSION 3.5) project(cmake-example VERSION 1.0 LANGUAGES C) find_package(libzip 1.10 REQUIRED) add_executable(cmake-example cmake-example.c) target_link_libraries(cmake-example PRIVATE libzip::zip) ================================================ FILE: external/libzip/examples/cmake-project/cmake-example.c ================================================ /* cmake-example.c -- mininmal code using libzip for CMake example Copyright (C) 2024 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include int main(int argc, char *argv[]) { printf("libzip version is %s\n", zip_libzip_version()); } ================================================ FILE: external/libzip/examples/in-memory.c ================================================ /* in-memory.c -- modify zip file in memory Copyright (C) 2014-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include static int get_data(void **datap, size_t *sizep, const char *archive) { /* example implementation that reads data from file */ struct stat st; FILE *fp; if ((fp = fopen(archive, "rb")) == NULL) { if (errno != ENOENT) { fprintf(stderr, "can't open %s: %s\n", archive, strerror(errno)); return -1; } *datap = NULL; *sizep = 0; return 0; } if (fstat(fileno(fp), &st) < 0) { fprintf(stderr, "can't stat %s: %s\n", archive, strerror(errno)); fclose(fp); return -1; } if ((*datap = malloc((size_t)st.st_size)) == NULL) { fprintf(stderr, "can't allocate buffer\n"); fclose(fp); return -1; } if (fread(*datap, 1, (size_t)st.st_size, fp) < (size_t)st.st_size) { fprintf(stderr, "can't read %s: %s\n", archive, strerror(errno)); free(*datap); fclose(fp); return -1; } fclose(fp); *sizep = (size_t)st.st_size; return 0; } static int modify_archive(zip_t *za) { /* modify the archive */ return 0; } static int use_data(void *data, size_t size, const char *archive) { /* example implementation that writes data to file */ FILE *fp; if (data == NULL) { if (remove(archive) < 0 && errno != ENOENT) { fprintf(stderr, "can't remove %s: %s\n", archive, strerror(errno)); return -1; } return 0; } if ((fp = fopen(archive, "wb")) == NULL) { fprintf(stderr, "can't open %s: %s\n", archive, strerror(errno)); return -1; } if (fwrite(data, 1, size, fp) < size) { fprintf(stderr, "can't write %s: %s\n", archive, strerror(errno)); fclose(fp); return -1; } if (fclose(fp) < 0) { fprintf(stderr, "can't write %s: %s\n", archive, strerror(errno)); return -1; } return 0; } int main(int argc, char *argv[]) { const char *archive; zip_source_t *src; zip_t *za; zip_error_t error; void *data; size_t size; if (argc < 2) { fprintf(stderr, "usage: %s archive\n", argv[0]); return 1; } archive = argv[1]; /* get buffer with zip archive inside */ if (get_data(&data, &size, archive) < 0) { return 1; } zip_error_init(&error); /* create source from buffer */ if ((src = zip_source_buffer_create(data, size, 1, &error)) == NULL) { fprintf(stderr, "can't create source: %s\n", zip_error_strerror(&error)); free(data); zip_error_fini(&error); return 1; } /* open zip archive from source */ if ((za = zip_open_from_source(src, 0, &error)) == NULL) { fprintf(stderr, "can't open zip from source: %s\n", zip_error_strerror(&error)); zip_source_free(src); zip_error_fini(&error); return 1; } zip_error_fini(&error); /* we'll want to read the data back after zip_close */ zip_source_keep(src); /* modify archive */ modify_archive(za); /* close archive */ if (zip_close(za) < 0) { fprintf(stderr, "can't close zip archive '%s': %s\n", archive, zip_strerror(za)); return 1; } /* copy new archive to buffer */ if (zip_source_is_deleted(src)) { /* new archive is empty, thus no data */ data = NULL; } else { zip_stat_t zst; if (zip_source_stat(src, &zst) < 0) { fprintf(stderr, "can't stat source: %s\n", zip_error_strerror(zip_source_error(src))); return 1; } size = zst.size; if (zip_source_open(src) < 0) { fprintf(stderr, "can't open source: %s\n", zip_error_strerror(zip_source_error(src))); return 1; } if ((data = malloc(size)) == NULL) { fprintf(stderr, "malloc failed: %s\n", strerror(errno)); zip_source_close(src); return 1; } if ((zip_uint64_t)zip_source_read(src, data, size) < size) { fprintf(stderr, "can't read data from source: %s\n", zip_error_strerror(zip_source_error(src))); zip_source_close(src); free(data); return 1; } zip_source_close(src); } /* we're done with src */ zip_source_free(src); /* use new data */ use_data(data, size, archive); free(data); return 0; } ================================================ FILE: external/libzip/examples/windows-open.c ================================================ /* windows-open.c -- open zip archive using Windows UTF-16/Unicode file name Copyright (C) 2015-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include zip_t * windows_open(const wchar_t *name, int flags) { zip_source_t *src; zip_t *za; zip_error_t error; zip_error_init(&error); /* create source from buffer */ if ((src = zip_source_win32w_create(name, 0, -1, &error)) == NULL) { fprintf(stderr, "can't create source: %s\n", zip_error_strerror(&error)); zip_error_fini(&error); return NULL; } /* open zip archive from source */ if ((za = zip_open_from_source(src, flags, &error)) == NULL) { fprintf(stderr, "can't open zip from source: %s\n", zip_error_strerror(&error)); zip_source_free(src); zip_error_fini(&error); return NULL; } zip_error_fini(&error); return za; } ================================================ FILE: external/libzip/lib/CMakeLists.txt ================================================ include(CheckFunctionExists) set(CMAKE_C_VISIBILITY_PRESET hidden) add_library(zip zip_add.c zip_add_dir.c zip_add_entry.c zip_algorithm_deflate.c zip_buffer.c zip_close.c zip_delete.c zip_dir_add.c zip_dirent.c zip_discard.c zip_entry.c zip_error.c zip_error_clear.c zip_error_get.c zip_error_get_sys_type.c zip_error_strerror.c zip_error_to_str.c zip_extra_field.c zip_extra_field_api.c zip_fclose.c zip_fdopen.c zip_file_add.c zip_file_error_clear.c zip_file_error_get.c zip_file_get_comment.c zip_file_get_external_attributes.c zip_file_get_offset.c zip_file_rename.c zip_file_replace.c zip_file_set_comment.c zip_file_set_encryption.c zip_file_set_external_attributes.c zip_file_set_mtime.c zip_file_strerror.c zip_fopen.c zip_fopen_encrypted.c zip_fopen_index.c zip_fopen_index_encrypted.c zip_fread.c zip_fseek.c zip_ftell.c zip_get_archive_comment.c zip_get_archive_flag.c zip_get_encryption_implementation.c zip_get_file_comment.c zip_get_name.c zip_get_num_entries.c zip_get_num_files.c zip_hash.c zip_io_util.c zip_libzip_version.c zip_memdup.c zip_name_locate.c zip_new.c zip_open.c zip_pkware.c zip_progress.c zip_realloc.c zip_rename.c zip_replace.c zip_set_archive_comment.c zip_set_archive_flag.c zip_set_default_password.c zip_set_file_comment.c zip_set_file_compression.c zip_set_name.c zip_source_accept_empty.c zip_source_begin_write.c zip_source_begin_write_cloning.c zip_source_buffer.c zip_source_call.c zip_source_close.c zip_source_commit_write.c zip_source_compress.c zip_source_crc.c zip_source_error.c zip_source_file_common.c zip_source_file_stdio.c zip_source_free.c zip_source_function.c zip_source_get_dostime.c zip_source_get_file_attributes.c zip_source_is_deleted.c zip_source_layered.c zip_source_open.c zip_source_pass_to_lower_layer.c zip_source_pkware_decode.c zip_source_pkware_encode.c zip_source_read.c zip_source_remove.c zip_source_rollback_write.c zip_source_seek.c zip_source_seek_write.c zip_source_stat.c zip_source_supports.c zip_source_tell.c zip_source_tell_write.c zip_source_window.c zip_source_write.c zip_source_zip.c zip_source_zip_new.c zip_stat.c zip_stat_index.c zip_stat_init.c zip_strerror.c zip_string.c zip_unchange.c zip_unchange_all.c zip_unchange_archive.c zip_unchange_data.c zip_utf-8.c ${CMAKE_CURRENT_BINARY_DIR}/zip_err_str.c ) add_library(libzip::zip ALIAS zip) if(WIN32) target_compile_definitions(zip PRIVATE WIN32_LEAN_AND_MEAN) target_sources(zip PRIVATE zip_source_file_win32.c zip_source_file_win32_named.c zip_source_file_win32_utf16.c zip_source_file_win32_utf8.c ) if(CMAKE_SYSTEM_NAME MATCHES WindowsPhone OR CMAKE_SYSTEM_NAME MATCHES WindowsStore) target_sources(zip PRIVATE zip_random_uwp.c) else() target_sources(zip PRIVATE zip_source_file_win32_ansi.c zip_random_win32.c) target_link_libraries(zip PRIVATE advapi32) endif() else(WIN32) target_sources(zip PRIVATE zip_source_file_stdio_named.c zip_random_unix.c ) endif(WIN32) if(HAVE_LIBBZ2) target_sources(zip PRIVATE zip_algorithm_bzip2.c) target_link_libraries(zip PRIVATE BZip2::BZip2) endif() if(HAVE_LIBLZMA) target_sources(zip PRIVATE zip_algorithm_xz.c) target_link_libraries(zip PRIVATE LibLZMA::LibLZMA) endif() if(HAVE_LIBZSTD) target_sources(zip PRIVATE zip_algorithm_zstd.c) target_link_libraries(zip PRIVATE ${zstd_TARGET}) endif() if(HAVE_COMMONCRYPTO) target_sources(zip PRIVATE zip_crypto_commoncrypto.c) elseif(HAVE_WINDOWS_CRYPTO) target_sources(zip PRIVATE zip_crypto_win.c) target_link_libraries(zip PRIVATE bcrypt) elseif(HAVE_GNUTLS) target_sources(zip PRIVATE zip_crypto_gnutls.c) target_link_libraries(zip PRIVATE GnuTLS::GnuTLS Nettle::Nettle) elseif(HAVE_OPENSSL) target_sources(zip PRIVATE zip_crypto_openssl.c) target_link_libraries(zip PRIVATE OpenSSL::Crypto) elseif(HAVE_MBEDTLS) target_sources(zip PRIVATE zip_crypto_mbedtls.c) target_link_libraries(zip PRIVATE MbedTLS::MbedTLS) endif() if(HAVE_CRYPTO) target_sources(zip PRIVATE zip_winzip_aes.c zip_source_winzip_aes_decode.c zip_source_winzip_aes_encode.c) endif() if(SHARED_LIB_VERSIONNING) # MACHO_*_VERSION can be removed when SOVERSION gets increased. Cf #405 set_target_properties(zip PROPERTIES VERSION 5.5 SOVERSION 5 MACHO_CURRENT_VERSION 6.5 MACHO_COMPATIBILITY_VERSION 6) endif() target_link_libraries(zip PRIVATE ZLIB::ZLIB) target_include_directories(zip PUBLIC $ $ $ ) if(LIBZIP_DO_INSTALL) install(TARGETS zip EXPORT ${PROJECT_NAME}-targets RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) install(FILES zip.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) endif() # create zip_err_str.c from zip.h and zipint.h add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/zip_err_str.c COMMAND "${CMAKE_COMMAND}" "-DPROJECT_SOURCE_DIR=${PROJECT_SOURCE_DIR}" "-DCMAKE_CURRENT_BINARY_DIR=${CMAKE_CURRENT_BINARY_DIR}" "-P" "${PROJECT_SOURCE_DIR}/cmake/GenerateZipErrorStrings.cmake" DEPENDS ${PROJECT_SOURCE_DIR}/cmake/GenerateZipErrorStrings.cmake ${PROJECT_SOURCE_DIR}/lib/zip.h ${PROJECT_SOURCE_DIR}/lib/zipint.h COMMENT "Generating zip_err_str.c" ) ================================================ FILE: external/libzip/lib/compat.h ================================================ #ifndef _HAD_LIBZIP_COMPAT_H #define _HAD_LIBZIP_COMPAT_H /* compat.h -- compatibility defines. Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "zipconf.h" #include "config.h" /* to have *_MAX definitions for all types when compiling with g++ */ #define __STDC_LIMIT_MACROS /* to have ISO C secure library functions */ #define __STDC_WANT_LIB_EXT1__ 1 #ifdef _WIN32 #ifndef ZIP_EXTERN #ifndef ZIP_STATIC #define ZIP_EXTERN __declspec(dllexport) #endif #endif /* for dup(), close(), etc. */ #include #endif #ifdef HAVE_STDBOOL_H #include #else typedef char bool; #define true 1 #define false 0 #endif #include /* at least MinGW does not provide EOPNOTSUPP, see * http://sourceforge.net/p/mingw/bugs/263/ */ #ifndef EOPNOTSUPP #define EOPNOTSUPP EINVAL #endif /* at least MinGW does not provide EOVERFLOW, see * http://sourceforge.net/p/mingw/bugs/242/ */ #ifndef EOVERFLOW #define EOVERFLOW EFBIG #endif /* not supported on at least Windows */ #ifndef O_CLOEXEC #define O_CLOEXEC 0 #endif #ifdef _WIN32 #if defined(HAVE__CLOSE) #define close _close #endif #if defined(HAVE__DUP) #define dup _dup #endif /* crashes reported when using fdopen instead of _fdopen on Windows/Visual Studio 10/Win64 */ #if defined(HAVE__FDOPEN) #define fdopen _fdopen #endif #if !defined(HAVE_FILENO) && defined(HAVE__FILENO) #define fileno _fileno #endif #if !defined(HAVE_SNPRINTF) && defined(HAVE__SNPRINTF) #define snprintf _snprintf #endif #if !defined(HAVE__SNWPRINTF_S) #define _snwprintf_s(buf, bufsz, len, fmt, ...) (_snwprintf((buf), (len), (fmt), __VA_ARGS__)) #endif #if defined(HAVE__STRDUP) #if !defined(HAVE_STRDUP) || defined(_WIN32) #undef strdup #define strdup _strdup #endif #endif #if !defined(HAVE__SETMODE) && defined(HAVE_SETMODE) #define _setmode setmode #endif #if !defined(HAVE_STRTOLL) && defined(HAVE__STRTOI64) #define strtoll _strtoi64 #endif #if !defined(HAVE_STRTOULL) && defined(HAVE__STRTOUI64) #define strtoull _strtoui64 #endif #if defined(HAVE__UNLINK) #define unlink _unlink #endif #endif #if defined(HAVE__FSEEKI64) && defined(HAVE__FSTAT64) && defined(HAVE__SEEK64) /* Windows API using int64 */ typedef zip_int64_t zip_off_t; typedef struct _stat64 zip_os_stat_t; #define zip_os_stat _stat64 #define zip_os_fstat _fstat64 #define zip_os_seek _fseeki64 #define ZIP_FSEEK_MAX ZIP_INT64_MAX #define ZIP_FSEEK_MIN ZIP_INT64_MIN #else /* Normal API */ #include typedef struct stat zip_os_stat_t; #define zip_os_fstat fstat #define zip_os_stat stat #if defined(HAVE_FTELLO) && defined(HAVE_FSEEKO) /* Using off_t */ typedef off_t zip_off_t; #if SIZEOF_OFF_T == 8 #define ZIP_OFF_MAX ZIP_INT64_MAX #define ZIP_OFF_MIN ZIP_INT64_MIN #elif SIZEOF_OFF_T == 4 #define ZIP_OFF_MAX ZIP_INT32_MAX #define ZIP_OFF_MIN ZIP_INT32_MIN #elif SIZEOF_OFF_T == 2 #define ZIP_OFF_MAX ZIP_INT16_MAX #define ZIP_OFF_MIN ZIP_INT16_MIN #else #error unsupported size of off_t #endif #define ZIP_FSEEK_MAX ZIP_OFF_MAX #define ZIP_FSEEK_MIN ZIP_OFF_MIN #define zip_os_fseek fseeko #define zip_os_ftell ftello #else /* Using long */ typedef long zip_off_t; #include #define ZIP_FSEEK_MAX LONG_MAX #define ZIP_FSEEK_MIN LONG_MIN #define zip_os_fseek fseek #define zip_os_ftell ftell #endif #endif #ifndef HAVE_FTELLO #define ftello(s) ((long)ftell((s))) #endif #ifdef HAVE_LOCALTIME_S #ifdef _WIN32 /* Windows is incompatible to the C11 standard, hurray! */ #define zip_localtime(t, tm) (localtime_s((tm), (t)) == 0 ? tm : NULL) #else #define zip_localtime localtime_s #endif #else #ifdef HAVE_LOCALTIME_R #define zip_localtime localtime_r #else #define zip_localtime(t, tm) (localtime(t)) #endif #endif #ifndef HAVE_MEMCPY_S #define memcpy_s(dest, destsz, src, count) (memcpy((dest), (src), (count)) == NULL) #endif #ifndef HAVE_SNPRINTF_S #ifdef HAVE__SNPRINTF_S #define snprintf_s(buf, bufsz, fmt, ...) (_snprintf_s((buf), (bufsz), (bufsz), (fmt), __VA_ARGS__)) #else #define snprintf_s snprintf #endif #endif #if !defined(HAVE_STRCASECMP) #if defined(HAVE__STRICMP) #define strcasecmp _stricmp #elif defined(HAVE_STRICMP) #define strcasecmp stricmp #endif #endif #ifndef HAVE_STRNCPY_S #define strncpy_s(dest, destsz, src, count) (strncpy((dest), (src), (count)), 0) #endif #ifndef HAVE_STRERROR_S #define strerrorlen_s(errnum) (strlen(strerror(errnum))) #define strerror_s(buf, bufsz, errnum) ((void)strncpy_s((buf), (bufsz), strerror(errnum), (bufsz)), (buf)[(bufsz)-1] = '\0', strerrorlen_s(errnum) >= (bufsz)) #else #ifndef HAVE_STRERRORLEN_S #define strerrorlen_s(errnum) 8192 #endif #endif #ifndef SIZE_MAX #if SIZEOF_SIZE_T == 8 #define SIZE_MAX ZIP_INT64_MAX #elif SIZEOF_SIZE_T == 4 #define SIZE_MAX ZIP_INT32_MAX #elif SIZEOF_SIZE_T == 2 #define SIZE_MAX ZIP_INT16_MAX #else #error unsupported size of size_t #endif #endif #ifndef PRId64 #ifdef _MSC_VER #define PRId64 "I64d" #else #define PRId64 "lld" #endif #endif #ifndef PRIu64 #ifdef _MSC_VER #define PRIu64 "I64u" #else #define PRIu64 "llu" #endif #endif #ifndef S_ISDIR #define S_ISDIR(mode) (((mode)&S_IFMT) == S_IFDIR) #endif #ifndef S_ISREG #define S_ISREG(mode) (((mode)&S_IFMT) == S_IFREG) #endif #endif /* compat.h */ ================================================ FILE: external/libzip/lib/zip.h ================================================ #ifndef _HAD_ZIP_H #define _HAD_ZIP_H /* zip.h -- exported declarations. Copyright (C) 1999-2024 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #if defined(__has_feature) #if !__has_feature(nullability) #define _Nullable #define _Nonnull #endif #else #define _Nullable #define _Nonnull #endif #ifdef __cplusplus extern "C" { #if 0 } /* fix autoindent */ #endif #endif #include #ifndef ZIP_EXTERN #ifndef ZIP_STATIC #ifdef _WIN32 #define ZIP_EXTERN __declspec(dllimport) #elif defined(__GNUC__) && __GNUC__ >= 4 #define ZIP_EXTERN __attribute__((visibility("default"))) #else #define ZIP_EXTERN #endif #else #define ZIP_EXTERN #endif #endif #ifndef ZIP_DEPRECATED #if defined(__GNUC__) || defined(__clang__) #define ZIP_DEPRECATED(x) __attribute__((deprecated(x))) #elif defined(_MSC_VER) #define ZIP_DEPRECATED(x) __declspec(deprecated(x)) #else #define ZIP_DEPRECATED(x) #endif #endif #include #include #include /* flags for zip_open */ #define ZIP_CREATE 1 #define ZIP_EXCL 2 #define ZIP_CHECKCONS 4 #define ZIP_TRUNCATE 8 #define ZIP_RDONLY 16 /* flags for zip_name_locate, zip_fopen, zip_stat, ... */ #define ZIP_FL_NOCASE 1u /* ignore case on name lookup */ #define ZIP_FL_NODIR 2u /* ignore directory component */ #define ZIP_FL_COMPRESSED 4u /* read compressed data */ #define ZIP_FL_UNCHANGED 8u /* use original data, ignoring changes */ /* 16u was ZIP_FL_RECOMPRESS, which is deprecated */ #define ZIP_FL_ENCRYPTED 32u /* read encrypted data (implies ZIP_FL_COMPRESSED) */ #define ZIP_FL_ENC_GUESS 0u /* guess string encoding (is default) */ #define ZIP_FL_ENC_RAW 64u /* get unmodified string */ #define ZIP_FL_ENC_STRICT 128u /* follow specification strictly */ #define ZIP_FL_LOCAL 256u /* in local header */ #define ZIP_FL_CENTRAL 512u /* in central directory */ /* 1024u reserved for internal use */ #define ZIP_FL_ENC_UTF_8 2048u /* string is UTF-8 encoded */ #define ZIP_FL_ENC_CP437 4096u /* string is CP437 encoded */ #define ZIP_FL_OVERWRITE 8192u /* zip_file_add: if file with name exists, overwrite (replace) it */ /* archive global flags flags */ #define ZIP_AFL_RDONLY 2u /* read only -- cannot be cleared */ #define ZIP_AFL_IS_TORRENTZIP 4u /* current archive is torrentzipped */ #define ZIP_AFL_WANT_TORRENTZIP 8u /* write archive in torrentzip format */ #define ZIP_AFL_CREATE_OR_KEEP_FILE_FOR_EMPTY_ARCHIVE 16u /* don't remove file if archive is empty */ /* create a new extra field */ #define ZIP_EXTRA_FIELD_ALL ZIP_UINT16_MAX #define ZIP_EXTRA_FIELD_NEW ZIP_UINT16_MAX /* length parameter to various functions */ #define ZIP_LENGTH_TO_END 0 #define ZIP_LENGTH_UNCHECKED (-2) /* only supported by zip_source_file and its variants */ /* libzip error codes */ #define ZIP_ER_OK 0 /* N No error */ #define ZIP_ER_MULTIDISK 1 /* N Multi-disk zip archives not supported */ #define ZIP_ER_RENAME 2 /* S Renaming temporary file failed */ #define ZIP_ER_CLOSE 3 /* S Closing zip archive failed */ #define ZIP_ER_SEEK 4 /* S Seek error */ #define ZIP_ER_READ 5 /* S Read error */ #define ZIP_ER_WRITE 6 /* S Write error */ #define ZIP_ER_CRC 7 /* N CRC error */ #define ZIP_ER_ZIPCLOSED 8 /* N Containing zip archive was closed */ #define ZIP_ER_NOENT 9 /* N No such file */ #define ZIP_ER_EXISTS 10 /* N File already exists */ #define ZIP_ER_OPEN 11 /* S Can't open file */ #define ZIP_ER_TMPOPEN 12 /* S Failure to create temporary file */ #define ZIP_ER_ZLIB 13 /* Z Zlib error */ #define ZIP_ER_MEMORY 14 /* N Malloc failure */ #define ZIP_ER_CHANGED 15 /* N Entry has been changed */ #define ZIP_ER_COMPNOTSUPP 16 /* N Compression method not supported */ #define ZIP_ER_EOF 17 /* N Premature end of file */ #define ZIP_ER_INVAL 18 /* N Invalid argument */ #define ZIP_ER_NOZIP 19 /* N Not a zip archive */ #define ZIP_ER_INTERNAL 20 /* N Internal error */ #define ZIP_ER_INCONS 21 /* L Zip archive inconsistent */ #define ZIP_ER_REMOVE 22 /* S Can't remove file */ #define ZIP_ER_DELETED 23 /* N Entry has been deleted */ #define ZIP_ER_ENCRNOTSUPP 24 /* N Encryption method not supported */ #define ZIP_ER_RDONLY 25 /* N Read-only archive */ #define ZIP_ER_NOPASSWD 26 /* N No password provided */ #define ZIP_ER_WRONGPASSWD 27 /* N Wrong password provided */ #define ZIP_ER_OPNOTSUPP 28 /* N Operation not supported */ #define ZIP_ER_INUSE 29 /* N Resource still in use */ #define ZIP_ER_TELL 30 /* S Tell error */ #define ZIP_ER_COMPRESSED_DATA 31 /* N Compressed data invalid */ #define ZIP_ER_CANCELLED 32 /* N Operation cancelled */ #define ZIP_ER_DATA_LENGTH 33 /* N Unexpected length of data */ #define ZIP_ER_NOT_ALLOWED 34 /* N Not allowed in torrentzip */ #define ZIP_ER_TRUNCATED_ZIP 35 /* N Possibly truncated or corrupted zip archive */ /* type of system error value */ #define ZIP_ET_NONE 0 /* sys_err unused */ #define ZIP_ET_SYS 1 /* sys_err is errno */ #define ZIP_ET_ZLIB 2 /* sys_err is zlib error code */ #define ZIP_ET_LIBZIP 3 /* sys_err is libzip error code */ /* compression methods */ #define ZIP_CM_DEFAULT -1 /* better of deflate or store */ #define ZIP_CM_STORE 0 /* stored (uncompressed) */ #define ZIP_CM_SHRINK 1 /* shrunk */ #define ZIP_CM_REDUCE_1 2 /* reduced with factor 1 */ #define ZIP_CM_REDUCE_2 3 /* reduced with factor 2 */ #define ZIP_CM_REDUCE_3 4 /* reduced with factor 3 */ #define ZIP_CM_REDUCE_4 5 /* reduced with factor 4 */ #define ZIP_CM_IMPLODE 6 /* imploded */ /* 7 - Reserved for Tokenizing compression algorithm */ #define ZIP_CM_DEFLATE 8 /* deflated */ #define ZIP_CM_DEFLATE64 9 /* deflate64 */ #define ZIP_CM_PKWARE_IMPLODE 10 /* PKWARE imploding */ /* 11 - Reserved by PKWARE */ #define ZIP_CM_BZIP2 12 /* compressed using BZIP2 algorithm */ /* 13 - Reserved by PKWARE */ #define ZIP_CM_LZMA 14 /* LZMA (EFS) */ /* 15-17 - Reserved by PKWARE */ #define ZIP_CM_TERSE 18 /* compressed using IBM TERSE (new) */ #define ZIP_CM_LZ77 19 /* IBM LZ77 z Architecture (PFS) */ /* 20 - old value for Zstandard */ #define ZIP_CM_LZMA2 33 #define ZIP_CM_ZSTD 93 /* Zstandard compressed data */ #define ZIP_CM_XZ 95 /* XZ compressed data */ #define ZIP_CM_JPEG 96 /* Compressed Jpeg data */ #define ZIP_CM_WAVPACK 97 /* WavPack compressed data */ #define ZIP_CM_PPMD 98 /* PPMd version I, Rev 1 */ /* encryption methods */ #define ZIP_EM_NONE 0 /* not encrypted */ #define ZIP_EM_TRAD_PKWARE 1 /* traditional PKWARE encryption */ #if 0 /* Strong Encryption Header not parsed yet */ #define ZIP_EM_DES 0x6601 /* strong encryption: DES */ #define ZIP_EM_RC2_OLD 0x6602 /* strong encryption: RC2, version < 5.2 */ #define ZIP_EM_3DES_168 0x6603 #define ZIP_EM_3DES_112 0x6609 #define ZIP_EM_PKZIP_AES_128 0x660e #define ZIP_EM_PKZIP_AES_192 0x660f #define ZIP_EM_PKZIP_AES_256 0x6610 #define ZIP_EM_RC2 0x6702 /* strong encryption: RC2, version >= 5.2 */ #define ZIP_EM_RC4 0x6801 #endif #define ZIP_EM_AES_128 0x0101 /* Winzip AES encryption */ #define ZIP_EM_AES_192 0x0102 #define ZIP_EM_AES_256 0x0103 #define ZIP_EM_UNKNOWN 0xffff /* unknown algorithm */ #define ZIP_OPSYS_DOS 0x00u #define ZIP_OPSYS_AMIGA 0x01u #define ZIP_OPSYS_OPENVMS 0x02u #define ZIP_OPSYS_UNIX 0x03u #define ZIP_OPSYS_VM_CMS 0x04u #define ZIP_OPSYS_ATARI_ST 0x05u #define ZIP_OPSYS_OS_2 0x06u #define ZIP_OPSYS_MACINTOSH 0x07u #define ZIP_OPSYS_Z_SYSTEM 0x08u #define ZIP_OPSYS_CPM 0x09u #define ZIP_OPSYS_WINDOWS_NTFS 0x0au #define ZIP_OPSYS_MVS 0x0bu #define ZIP_OPSYS_VSE 0x0cu #define ZIP_OPSYS_ACORN_RISC 0x0du #define ZIP_OPSYS_VFAT 0x0eu #define ZIP_OPSYS_ALTERNATE_MVS 0x0fu #define ZIP_OPSYS_BEOS 0x10u #define ZIP_OPSYS_TANDEM 0x11u #define ZIP_OPSYS_OS_400 0x12u #define ZIP_OPSYS_OS_X 0x13u #define ZIP_OPSYS_DEFAULT ZIP_OPSYS_UNIX enum zip_source_cmd { ZIP_SOURCE_OPEN, /* prepare for reading */ ZIP_SOURCE_READ, /* read data */ ZIP_SOURCE_CLOSE, /* reading is done */ ZIP_SOURCE_STAT, /* get meta information */ ZIP_SOURCE_ERROR, /* get error information */ ZIP_SOURCE_FREE, /* cleanup and free resources */ ZIP_SOURCE_SEEK, /* set position for reading */ ZIP_SOURCE_TELL, /* get read position */ ZIP_SOURCE_BEGIN_WRITE, /* prepare for writing */ ZIP_SOURCE_COMMIT_WRITE, /* writing is done */ ZIP_SOURCE_ROLLBACK_WRITE, /* discard written changes */ ZIP_SOURCE_WRITE, /* write data */ ZIP_SOURCE_SEEK_WRITE, /* set position for writing */ ZIP_SOURCE_TELL_WRITE, /* get write position */ ZIP_SOURCE_SUPPORTS, /* check whether source supports command */ ZIP_SOURCE_REMOVE, /* remove file */ ZIP_SOURCE_RESERVED_1, /* previously used internally */ ZIP_SOURCE_BEGIN_WRITE_CLONING, /* like ZIP_SOURCE_BEGIN_WRITE, but keep part of original file */ ZIP_SOURCE_ACCEPT_EMPTY, /* whether empty files are valid archives */ ZIP_SOURCE_GET_FILE_ATTRIBUTES, /* get additional file attributes */ ZIP_SOURCE_SUPPORTS_REOPEN, /* allow reading from changed entry */ ZIP_SOURCE_GET_DOS_TIME /* get last modification time in DOS format */ }; typedef enum zip_source_cmd zip_source_cmd_t; #define ZIP_SOURCE_MAKE_COMMAND_BITMASK(cmd) (((zip_int64_t)1) << (cmd)) #define ZIP_SOURCE_CHECK_SUPPORTED(supported, cmd) (((supported) & ZIP_SOURCE_MAKE_COMMAND_BITMASK(cmd)) != 0) /* clang-format off */ #define ZIP_SOURCE_SUPPORTS_READABLE (ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_OPEN) \ | ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_READ) \ | ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_CLOSE) \ | ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_STAT) \ | ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_ERROR) \ | ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_FREE)) #define ZIP_SOURCE_SUPPORTS_SEEKABLE (ZIP_SOURCE_SUPPORTS_READABLE \ | ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_SEEK) \ | ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_TELL) \ | ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_SUPPORTS)) #define ZIP_SOURCE_SUPPORTS_WRITABLE (ZIP_SOURCE_SUPPORTS_SEEKABLE \ | ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_BEGIN_WRITE) \ | ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_COMMIT_WRITE) \ | ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_ROLLBACK_WRITE) \ | ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_WRITE) \ | ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_SEEK_WRITE) \ | ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_TELL_WRITE) \ | ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_REMOVE)) /* clang-format on */ /* for use by sources */ struct zip_source_args_seek { zip_int64_t offset; int whence; }; typedef struct zip_source_args_seek zip_source_args_seek_t; #define ZIP_SOURCE_GET_ARGS(type, data, len, error) ((len) < sizeof(type) ? zip_error_set((error), ZIP_ER_INVAL, 0), (type *)NULL : (type *)(data)) /* error information */ /* use zip_error_*() to access */ struct zip_error { int zip_err; /* libzip error code (ZIP_ER_*) */ int sys_err; /* copy of errno (E*) or zlib error code */ char *_Nullable str; /* string representation or NULL */ }; #define ZIP_STAT_NAME 0x0001u #define ZIP_STAT_INDEX 0x0002u #define ZIP_STAT_SIZE 0x0004u #define ZIP_STAT_COMP_SIZE 0x0008u #define ZIP_STAT_MTIME 0x0010u #define ZIP_STAT_CRC 0x0020u #define ZIP_STAT_COMP_METHOD 0x0040u #define ZIP_STAT_ENCRYPTION_METHOD 0x0080u #define ZIP_STAT_FLAGS 0x0100u struct zip_stat { zip_uint64_t valid; /* which fields have valid values */ const char *_Nullable name; /* name of the file */ zip_uint64_t index; /* index within archive */ zip_uint64_t size; /* size of file (uncompressed) */ zip_uint64_t comp_size; /* size of file (compressed) */ time_t mtime; /* modification time */ zip_uint32_t crc; /* crc of file data */ zip_uint16_t comp_method; /* compression method used */ zip_uint16_t encryption_method; /* encryption method used */ zip_uint32_t flags; /* reserved for future use */ }; struct zip_buffer_fragment { zip_uint8_t *_Nonnull data; zip_uint64_t length; }; struct zip_file_attributes { zip_uint64_t valid; /* which fields have valid values */ zip_uint8_t version; /* version of this struct, currently 1 */ zip_uint8_t host_system; /* host system on which file was created */ zip_uint8_t ascii; /* flag whether file is ASCII text */ zip_uint8_t version_needed; /* minimum version needed to extract file */ zip_uint32_t external_file_attributes; /* external file attributes (host-system specific) */ zip_uint16_t general_purpose_bit_flags; /* general purpose big flags, only some bits are honored */ zip_uint16_t general_purpose_bit_mask; /* which bits in general_purpose_bit_flags are valid */ }; #define ZIP_FILE_ATTRIBUTES_HOST_SYSTEM 0x0001u #define ZIP_FILE_ATTRIBUTES_ASCII 0x0002u #define ZIP_FILE_ATTRIBUTES_VERSION_NEEDED 0x0004u #define ZIP_FILE_ATTRIBUTES_EXTERNAL_FILE_ATTRIBUTES 0x0008u #define ZIP_FILE_ATTRIBUTES_GENERAL_PURPOSE_BIT_FLAGS 0x0010u struct zip; struct zip_file; struct zip_source; typedef struct zip zip_t; typedef struct zip_error zip_error_t; typedef struct zip_file zip_file_t; typedef struct zip_file_attributes zip_file_attributes_t; typedef struct zip_source zip_source_t; typedef struct zip_stat zip_stat_t; typedef struct zip_buffer_fragment zip_buffer_fragment_t; typedef zip_uint32_t zip_flags_t; typedef zip_int64_t (*zip_source_callback)(void *_Nullable, void *_Nullable, zip_uint64_t, zip_source_cmd_t); typedef zip_int64_t (*zip_source_layered_callback)(zip_source_t *_Nonnull, void *_Nullable, void *_Nullable, zip_uint64_t, enum zip_source_cmd); typedef void (*zip_progress_callback)(zip_t *_Nonnull, double, void *_Nullable); typedef int (*zip_cancel_callback)(zip_t *_Nonnull, void *_Nullable); #ifndef ZIP_DISABLE_DEPRECATED #define ZIP_FL_RECOMPRESS 16u /* force recompression of data */ typedef void (*zip_progress_callback_t)(double); ZIP_DEPRECATED("use 'zip_register_progress_callback_with_state' instead") ZIP_EXTERN void zip_register_progress_callback(zip_t *_Nonnull, zip_progress_callback_t _Nullable); ZIP_DEPRECATED("use 'zip_file_add' instead") ZIP_EXTERN zip_int64_t zip_add(zip_t *_Nonnull, const char *_Nonnull, zip_source_t *_Nonnull); ZIP_DEPRECATED("use 'zip_dir_add' instead") ZIP_EXTERN zip_int64_t zip_add_dir(zip_t *_Nonnull, const char *_Nonnull); ZIP_DEPRECATED("use 'zip_file_get_comment' instead") ZIP_EXTERN const char *_Nullable zip_get_file_comment(zip_t *_Nonnull, zip_uint64_t, int *_Nullable, int); ZIP_DEPRECATED("use 'zip_get_num_entries' instead") ZIP_EXTERN int zip_get_num_files(zip_t *_Nonnull); ZIP_DEPRECATED("use 'zip_file_rename' instead") ZIP_EXTERN int zip_rename(zip_t *_Nonnull, zip_uint64_t, const char *_Nonnull); ZIP_DEPRECATED("use 'zip_file_replace' instead") ZIP_EXTERN int zip_replace(zip_t *_Nonnull, zip_uint64_t, zip_source_t *_Nonnull); ZIP_DEPRECATED("use 'zip_file_set_comment' instead") ZIP_EXTERN int zip_set_file_comment(zip_t *_Nonnull, zip_uint64_t, const char *_Nullable, int); ZIP_DEPRECATED("use 'zip_error_init_with_code' and 'zip_error_system_type' instead") ZIP_EXTERN int zip_error_get_sys_type(int); ZIP_DEPRECATED("use 'zip_get_error' instead") ZIP_EXTERN void zip_error_get(zip_t *_Nonnull, int *_Nullable, int *_Nullable); ZIP_DEPRECATED("use 'zip_error_strerror' instead") ZIP_EXTERN int zip_error_to_str(char *_Nonnull, zip_uint64_t, int, int); ZIP_DEPRECATED("use 'zip_file_get_error' instead") ZIP_EXTERN void zip_file_error_get(zip_file_t *_Nonnull, int *_Nullable, int *_Nullable); ZIP_DEPRECATED("use 'zip_source_zip_file' instead") ZIP_EXTERN zip_source_t *_Nullable zip_source_zip(zip_t *_Nonnull, zip_t *_Nonnull, zip_uint64_t, zip_flags_t, zip_uint64_t, zip_int64_t); ZIP_DEPRECATED("use 'zip_source_zip_file_create' instead") ZIP_EXTERN zip_source_t *_Nullable zip_source_zip_create(zip_t *_Nonnull, zip_uint64_t, zip_flags_t, zip_uint64_t, zip_int64_t, zip_error_t *_Nullable); #endif ZIP_EXTERN int zip_close(zip_t *_Nonnull); ZIP_EXTERN int zip_delete(zip_t *_Nonnull, zip_uint64_t); ZIP_EXTERN zip_int64_t zip_dir_add(zip_t *_Nonnull, const char *_Nonnull, zip_flags_t); ZIP_EXTERN void zip_discard(zip_t *_Nonnull); ZIP_EXTERN zip_error_t *_Nonnull zip_get_error(zip_t *_Nonnull); ZIP_EXTERN void zip_error_clear(zip_t *_Nonnull); ZIP_EXTERN int zip_error_code_zip(const zip_error_t *_Nonnull); ZIP_EXTERN int zip_error_code_system(const zip_error_t *_Nonnull); ZIP_EXTERN void zip_error_fini(zip_error_t *_Nonnull); ZIP_EXTERN void zip_error_init(zip_error_t *_Nonnull); ZIP_EXTERN void zip_error_init_with_code(zip_error_t *_Nonnull, int); ZIP_EXTERN void zip_error_set(zip_error_t *_Nullable, int, int); ZIP_EXTERN void zip_error_set_from_source(zip_error_t *_Nonnull, zip_source_t *_Nullable); ZIP_EXTERN const char *_Nonnull zip_error_strerror(zip_error_t *_Nonnull); ZIP_EXTERN int zip_error_system_type(const zip_error_t *_Nonnull); ZIP_EXTERN zip_int64_t zip_error_to_data(const zip_error_t *_Nonnull, void *_Nonnull, zip_uint64_t); ZIP_EXTERN int zip_fclose(zip_file_t *_Nonnull); ZIP_EXTERN zip_t *_Nullable zip_fdopen(int, int, int *_Nullable); ZIP_EXTERN zip_int64_t zip_file_add(zip_t *_Nonnull, const char *_Nonnull, zip_source_t *_Nonnull, zip_flags_t); ZIP_EXTERN void zip_file_attributes_init(zip_file_attributes_t *_Nonnull); ZIP_EXTERN void zip_file_error_clear(zip_file_t *_Nonnull); ZIP_EXTERN int zip_file_extra_field_delete(zip_t *_Nonnull, zip_uint64_t, zip_uint16_t, zip_flags_t); ZIP_EXTERN int zip_file_extra_field_delete_by_id(zip_t *_Nonnull, zip_uint64_t, zip_uint16_t, zip_uint16_t, zip_flags_t); ZIP_EXTERN int zip_file_extra_field_set(zip_t *_Nonnull, zip_uint64_t, zip_uint16_t, zip_uint16_t, const zip_uint8_t *_Nullable, zip_uint16_t, zip_flags_t); ZIP_EXTERN zip_int16_t zip_file_extra_fields_count(zip_t *_Nonnull, zip_uint64_t, zip_flags_t); ZIP_EXTERN zip_int16_t zip_file_extra_fields_count_by_id(zip_t *_Nonnull, zip_uint64_t, zip_uint16_t, zip_flags_t); ZIP_EXTERN const zip_uint8_t *_Nullable zip_file_extra_field_get(zip_t *_Nonnull, zip_uint64_t, zip_uint16_t, zip_uint16_t *_Nullable, zip_uint16_t *_Nullable, zip_flags_t); ZIP_EXTERN const zip_uint8_t *_Nullable zip_file_extra_field_get_by_id(zip_t *_Nonnull, zip_uint64_t, zip_uint16_t, zip_uint16_t, zip_uint16_t *_Nullable, zip_flags_t); ZIP_EXTERN const char *_Nullable zip_file_get_comment(zip_t *_Nonnull, zip_uint64_t, zip_uint32_t *_Nullable, zip_flags_t); ZIP_EXTERN zip_error_t *_Nonnull zip_file_get_error(zip_file_t *_Nonnull); ZIP_EXTERN int zip_file_get_external_attributes(zip_t *_Nonnull, zip_uint64_t, zip_flags_t, zip_uint8_t *_Nullable, zip_uint32_t *_Nullable); ZIP_EXTERN int zip_file_is_seekable(zip_file_t *_Nonnull); ZIP_EXTERN int zip_file_rename(zip_t *_Nonnull, zip_uint64_t, const char *_Nonnull, zip_flags_t); ZIP_EXTERN int zip_file_replace(zip_t *_Nonnull, zip_uint64_t, zip_source_t *_Nonnull, zip_flags_t); ZIP_EXTERN int zip_file_set_comment(zip_t *_Nonnull, zip_uint64_t, const char *_Nullable, zip_uint16_t, zip_flags_t); ZIP_EXTERN int zip_file_set_dostime(zip_t *_Nonnull, zip_uint64_t, zip_uint16_t, zip_uint16_t, zip_flags_t); ZIP_EXTERN int zip_file_set_encryption(zip_t *_Nonnull, zip_uint64_t, zip_uint16_t, const char *_Nullable); ZIP_EXTERN int zip_file_set_external_attributes(zip_t *_Nonnull, zip_uint64_t, zip_flags_t, zip_uint8_t, zip_uint32_t); ZIP_EXTERN int zip_file_set_mtime(zip_t *_Nonnull, zip_uint64_t, time_t, zip_flags_t); ZIP_EXTERN const char *_Nonnull zip_file_strerror(zip_file_t *_Nonnull); ZIP_EXTERN zip_file_t *_Nullable zip_fopen(zip_t *_Nonnull, const char *_Nonnull, zip_flags_t); ZIP_EXTERN zip_file_t *_Nullable zip_fopen_encrypted(zip_t *_Nonnull, const char *_Nonnull, zip_flags_t, const char *_Nullable); ZIP_EXTERN zip_file_t *_Nullable zip_fopen_index(zip_t *_Nonnull, zip_uint64_t, zip_flags_t); ZIP_EXTERN zip_file_t *_Nullable zip_fopen_index_encrypted(zip_t *_Nonnull, zip_uint64_t, zip_flags_t, const char *_Nullable); ZIP_EXTERN zip_int64_t zip_fread(zip_file_t *_Nonnull, void *_Nonnull, zip_uint64_t); ZIP_EXTERN zip_int8_t zip_fseek(zip_file_t *_Nonnull, zip_int64_t, int); ZIP_EXTERN zip_int64_t zip_ftell(zip_file_t *_Nonnull); ZIP_EXTERN const char *_Nullable zip_get_archive_comment(zip_t *_Nonnull, int *_Nullable, zip_flags_t); ZIP_EXTERN int zip_get_archive_flag(zip_t *_Nonnull, zip_flags_t, zip_flags_t); ZIP_EXTERN const char *_Nullable zip_get_name(zip_t *_Nonnull, zip_uint64_t, zip_flags_t); ZIP_EXTERN zip_int64_t zip_get_num_entries(zip_t *_Nonnull, zip_flags_t); ZIP_EXTERN const char *_Nonnull zip_libzip_version(void); ZIP_EXTERN zip_int64_t zip_name_locate(zip_t *_Nonnull, const char *_Nonnull, zip_flags_t); ZIP_EXTERN zip_t *_Nullable zip_open(const char *_Nonnull, int, int *_Nullable); ZIP_EXTERN zip_t *_Nullable zip_open_from_source(zip_source_t *_Nonnull, int, zip_error_t *_Nullable); ZIP_EXTERN int zip_register_progress_callback_with_state(zip_t *_Nonnull, double, zip_progress_callback _Nullable, void (*_Nullable)(void *_Nullable), void *_Nullable); ZIP_EXTERN int zip_register_cancel_callback_with_state(zip_t *_Nonnull, zip_cancel_callback _Nullable, void (*_Nullable)(void *_Nullable), void *_Nullable); ZIP_EXTERN int zip_set_archive_comment(zip_t *_Nonnull, const char *_Nullable, zip_uint16_t); ZIP_EXTERN int zip_set_archive_flag(zip_t *_Nonnull, zip_flags_t, int); ZIP_EXTERN int zip_set_default_password(zip_t *_Nonnull, const char *_Nullable); ZIP_EXTERN int zip_set_file_compression(zip_t *_Nonnull, zip_uint64_t, zip_int32_t, zip_uint32_t); ZIP_EXTERN int zip_source_begin_write(zip_source_t *_Nonnull); ZIP_EXTERN int zip_source_begin_write_cloning(zip_source_t *_Nonnull, zip_uint64_t); ZIP_EXTERN zip_source_t *_Nullable zip_source_buffer(zip_t *_Nonnull, const void *_Nullable, zip_uint64_t, int); ZIP_EXTERN zip_source_t *_Nullable zip_source_buffer_create(const void *_Nullable, zip_uint64_t, int, zip_error_t *_Nullable); ZIP_EXTERN zip_source_t *_Nullable zip_source_buffer_fragment(zip_t *_Nonnull, const zip_buffer_fragment_t *_Nonnull, zip_uint64_t, int); ZIP_EXTERN zip_source_t *_Nullable zip_source_buffer_fragment_create(const zip_buffer_fragment_t *_Nullable, zip_uint64_t, int, zip_error_t *_Nullable); ZIP_EXTERN int zip_source_close(zip_source_t *_Nonnull); ZIP_EXTERN int zip_source_commit_write(zip_source_t *_Nonnull); ZIP_EXTERN zip_error_t *_Nonnull zip_source_error(zip_source_t *_Nonnull); ZIP_EXTERN zip_source_t *_Nullable zip_source_file(zip_t *_Nonnull, const char *_Nonnull, zip_uint64_t, zip_int64_t); ZIP_EXTERN zip_source_t *_Nullable zip_source_file_create(const char *_Nonnull, zip_uint64_t, zip_int64_t, zip_error_t *_Nullable); ZIP_EXTERN zip_source_t *_Nullable zip_source_filep(zip_t *_Nonnull, FILE *_Nonnull, zip_uint64_t, zip_int64_t); ZIP_EXTERN zip_source_t *_Nullable zip_source_filep_create(FILE *_Nonnull, zip_uint64_t, zip_int64_t, zip_error_t *_Nullable); ZIP_EXTERN void zip_source_free(zip_source_t *_Nullable); ZIP_EXTERN zip_source_t *_Nullable zip_source_function(zip_t *_Nonnull, zip_source_callback _Nonnull, void *_Nullable); ZIP_EXTERN zip_source_t *_Nullable zip_source_function_create(zip_source_callback _Nonnull, void *_Nullable, zip_error_t *_Nullable); ZIP_EXTERN int zip_source_get_file_attributes(zip_source_t *_Nonnull, zip_file_attributes_t *_Nonnull); ZIP_EXTERN int zip_source_is_deleted(zip_source_t *_Nonnull); ZIP_EXTERN int zip_source_is_seekable(zip_source_t *_Nonnull); ZIP_EXTERN void zip_source_keep(zip_source_t *_Nonnull); ZIP_EXTERN zip_source_t *_Nullable zip_source_layered(zip_t *_Nullable, zip_source_t *_Nonnull, zip_source_layered_callback _Nonnull, void *_Nullable); ZIP_EXTERN zip_source_t *_Nullable zip_source_layered_create(zip_source_t *_Nonnull, zip_source_layered_callback _Nonnull, void *_Nullable, zip_error_t *_Nullable); ZIP_EXTERN zip_int64_t zip_source_make_command_bitmap(zip_source_cmd_t, ...); ZIP_EXTERN int zip_source_open(zip_source_t *_Nonnull); ZIP_EXTERN zip_int64_t zip_source_pass_to_lower_layer(zip_source_t *_Nonnull, void *_Nullable, zip_uint64_t, zip_source_cmd_t); ZIP_EXTERN zip_int64_t zip_source_read(zip_source_t *_Nonnull, void *_Nonnull, zip_uint64_t); ZIP_EXTERN void zip_source_rollback_write(zip_source_t *_Nonnull); ZIP_EXTERN int zip_source_seek(zip_source_t *_Nonnull, zip_int64_t, int); ZIP_EXTERN zip_int64_t zip_source_seek_compute_offset(zip_uint64_t, zip_uint64_t, void *_Nonnull, zip_uint64_t, zip_error_t *_Nullable); ZIP_EXTERN int zip_source_seek_write(zip_source_t *_Nonnull, zip_int64_t, int); ZIP_EXTERN int zip_source_stat(zip_source_t *_Nonnull, zip_stat_t *_Nonnull); ZIP_EXTERN zip_int64_t zip_source_tell(zip_source_t *_Nonnull); ZIP_EXTERN zip_int64_t zip_source_tell_write(zip_source_t *_Nonnull); #ifdef _WIN32 ZIP_EXTERN zip_source_t *_Nullable zip_source_win32a(zip_t *_Nonnull, const char *_Nonnull, zip_uint64_t, zip_int64_t); ZIP_EXTERN zip_source_t *_Nullable zip_source_win32a_create(const char *_Nonnull, zip_uint64_t, zip_int64_t, zip_error_t *_Nullable); ZIP_EXTERN zip_source_t *_Nullable zip_source_win32handle(zip_t *_Nonnull, void *_Nonnull, zip_uint64_t, zip_int64_t); ZIP_EXTERN zip_source_t *_Nullable zip_source_win32handle_create(void *_Nonnull, zip_uint64_t, zip_int64_t, zip_error_t *_Nullable); ZIP_EXTERN zip_source_t *_Nullable zip_source_win32w(zip_t *_Nonnull, const wchar_t *_Nonnull, zip_uint64_t, zip_int64_t); ZIP_EXTERN zip_source_t *_Nullable zip_source_win32w_create(const wchar_t *_Nonnull, zip_uint64_t, zip_int64_t, zip_error_t *_Nullable); #endif ZIP_EXTERN zip_source_t *_Nullable zip_source_window_create(zip_source_t *_Nonnull, zip_uint64_t, zip_int64_t, zip_error_t *_Nullable); ZIP_EXTERN zip_int64_t zip_source_write(zip_source_t *_Nonnull, const void *_Nullable, zip_uint64_t); ZIP_EXTERN zip_source_t *_Nullable zip_source_zip_file(zip_t *_Nonnull, zip_t *_Nonnull, zip_uint64_t, zip_flags_t, zip_uint64_t, zip_int64_t, const char *_Nullable); ZIP_EXTERN zip_source_t *_Nullable zip_source_zip_file_create(zip_t *_Nonnull, zip_uint64_t, zip_flags_t, zip_uint64_t, zip_int64_t, const char *_Nullable, zip_error_t *_Nullable); ZIP_EXTERN int zip_stat(zip_t *_Nonnull, const char *_Nonnull, zip_flags_t, zip_stat_t *_Nonnull); ZIP_EXTERN int zip_stat_index(zip_t *_Nonnull, zip_uint64_t, zip_flags_t, zip_stat_t *_Nonnull); ZIP_EXTERN void zip_stat_init(zip_stat_t *_Nonnull); ZIP_EXTERN const char *_Nonnull zip_strerror(zip_t *_Nonnull); ZIP_EXTERN int zip_unchange(zip_t *_Nonnull, zip_uint64_t); ZIP_EXTERN int zip_unchange_all(zip_t *_Nonnull); ZIP_EXTERN int zip_unchange_archive(zip_t *_Nonnull); ZIP_EXTERN int zip_compression_method_supported(zip_int32_t method, int compress); ZIP_EXTERN int zip_encryption_method_supported(zip_uint16_t method, int encode); #ifdef __cplusplus } #endif #endif /* _HAD_ZIP_H */ ================================================ FILE: external/libzip/lib/zip_add.c ================================================ /* zip_add.c -- add file via callback function Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define _ZIP_COMPILING_DEPRECATED #include "zipint.h" /* NOTE: Return type is signed so we can return -1 on error. The index can not be larger than ZIP_INT64_MAX since the size of the central directory cannot be larger than ZIP_UINT64_MAX, and each entry is larger than 2 bytes. */ ZIP_EXTERN zip_int64_t zip_add(zip_t *za, const char *name, zip_source_t *source) { return zip_file_add(za, name, source, 0); } ================================================ FILE: external/libzip/lib/zip_add_dir.c ================================================ /* zip_add_dir.c -- add directory Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define _ZIP_COMPILING_DEPRECATED #include "zipint.h" /* NOTE: Signed due to -1 on error. See zip_add.c for more details. */ ZIP_EXTERN zip_int64_t zip_add_dir(zip_t *za, const char *name) { return zip_dir_add(za, name, 0); } ================================================ FILE: external/libzip/lib/zip_add_entry.c ================================================ /* zip_add_entry.c -- create and init struct zip_entry Copyright (C) 1999-2024 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include "zipint.h" /* NOTE: Signed due to -1 on error. See zip_add.c for more details. */ zip_int64_t _zip_add_entry(zip_t *za) { zip_uint64_t idx; if (za->nentry + 1 >= za->nentry_alloc) { zip_uint64_t additional_entries = 2 * za->nentry_alloc; if (additional_entries < 16) { additional_entries = 16; } else if (additional_entries > 1024) { additional_entries = 1024; } if (!ZIP_REALLOC(za->entry, za->nentry_alloc, additional_entries, &za->error)) { return -1; } } idx = za->nentry++; _zip_entry_init(za->entry + idx); return (zip_int64_t)idx; } ================================================ FILE: external/libzip/lib/zip_algorithm_bzip2.c ================================================ /* zip_algorithm_bzip2.c -- bzip2 (de)compression routines Copyright (C) 2017-2023 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "zipint.h" #include #include #include struct ctx { zip_error_t *error; bool compress; int compression_flags; bool end_of_input; bz_stream zstr; }; static zip_uint64_t maximum_compressed_size(zip_uint64_t uncompressed_size) { zip_uint64_t compressed_size = (zip_uint64_t)((double)uncompressed_size * 1.006); if (compressed_size < uncompressed_size) { return ZIP_UINT64_MAX; } return compressed_size; } static void * allocate(bool compress, zip_uint32_t compression_flags, zip_error_t *error) { struct ctx *ctx; if ((ctx = (struct ctx *)malloc(sizeof(*ctx))) == NULL) { return NULL; } ctx->error = error; ctx->compress = compress; if (compression_flags >= 1 && compression_flags <= 9) { ctx->compression_flags = (int)compression_flags; } else { ctx->compression_flags = 9; } ctx->end_of_input = false; ctx->zstr.bzalloc = NULL; ctx->zstr.bzfree = NULL; ctx->zstr.opaque = NULL; return ctx; } static void * compress_allocate(zip_uint16_t method, zip_uint32_t compression_flags, zip_error_t *error) { (void)method; return allocate(true, compression_flags, error); } static void * decompress_allocate(zip_uint16_t method, zip_uint32_t compression_flags, zip_error_t *error) { (void)method; return allocate(false, compression_flags, error); } static void deallocate(void *ud) { struct ctx *ctx = (struct ctx *)ud; free(ctx); } static zip_uint16_t general_purpose_bit_flags(void *ud) { (void)ud; return 0; } static int map_error(int ret) { switch (ret) { case BZ_FINISH_OK: case BZ_FLUSH_OK: case BZ_OK: case BZ_RUN_OK: case BZ_STREAM_END: return ZIP_ER_OK; case BZ_DATA_ERROR: case BZ_DATA_ERROR_MAGIC: case BZ_UNEXPECTED_EOF: return ZIP_ER_COMPRESSED_DATA; case BZ_MEM_ERROR: return ZIP_ER_MEMORY; case BZ_PARAM_ERROR: return ZIP_ER_INVAL; case BZ_CONFIG_ERROR: /* actually, bzip2 miscompiled */ case BZ_IO_ERROR: case BZ_OUTBUFF_FULL: case BZ_SEQUENCE_ERROR: default: return ZIP_ER_INTERNAL; } } static bool start(void *ud, zip_stat_t *st, zip_file_attributes_t *attributes) { struct ctx *ctx = (struct ctx *)ud; int ret; (void)st; (void)attributes; ctx->zstr.avail_in = 0; ctx->zstr.next_in = NULL; ctx->zstr.avail_out = 0; ctx->zstr.next_out = NULL; if (ctx->compress) { ret = BZ2_bzCompressInit(&ctx->zstr, ctx->compression_flags, 0, 30); } else { ret = BZ2_bzDecompressInit(&ctx->zstr, 0, 0); } if (ret != BZ_OK) { zip_error_set(ctx->error, map_error(ret), 0); return false; } return true; } static bool end(void *ud) { struct ctx *ctx = (struct ctx *)ud; int err; if (ctx->compress) { err = BZ2_bzCompressEnd(&ctx->zstr); } else { err = BZ2_bzDecompressEnd(&ctx->zstr); } if (err != BZ_OK) { zip_error_set(ctx->error, map_error(err), 0); return false; } return true; } static bool input(void *ud, zip_uint8_t *data, zip_uint64_t length) { struct ctx *ctx = (struct ctx *)ud; if (length > UINT_MAX || ctx->zstr.avail_in > 0) { zip_error_set(ctx->error, ZIP_ER_INVAL, 0); return false; } ctx->zstr.avail_in = (unsigned int)length; ctx->zstr.next_in = (char *)data; return true; } static bool end_of_input(void *ud) { struct ctx *ctx = (struct ctx *)ud; ctx->end_of_input = true; return ctx->zstr.avail_in != 0; } static zip_compression_status_t process(void *ud, zip_uint8_t *data, zip_uint64_t *length) { struct ctx *ctx = (struct ctx *)ud; unsigned int avail_out; int ret; if (ctx->zstr.avail_in == 0 && !ctx->end_of_input) { *length = 0; return ZIP_COMPRESSION_NEED_DATA; } avail_out = (unsigned int)ZIP_MIN(UINT_MAX, *length); ctx->zstr.avail_out = avail_out; ctx->zstr.next_out = (char *)data; if (ctx->compress) { ret = BZ2_bzCompress(&ctx->zstr, ctx->end_of_input ? BZ_FINISH : BZ_RUN); } else { ret = BZ2_bzDecompress(&ctx->zstr); } *length = avail_out - ctx->zstr.avail_out; switch (ret) { case BZ_FINISH_OK: /* compression */ return ZIP_COMPRESSION_OK; case BZ_OK: /* decompression */ case BZ_RUN_OK: /* compression */ if (ctx->zstr.avail_in == 0) { return ZIP_COMPRESSION_NEED_DATA; } return ZIP_COMPRESSION_OK; case BZ_STREAM_END: return ZIP_COMPRESSION_END; default: zip_error_set(ctx->error, map_error(ret), 0); return ZIP_COMPRESSION_ERROR; } } /* clang-format off */ zip_compression_algorithm_t zip_algorithm_bzip2_compress = { maximum_compressed_size, compress_allocate, deallocate, general_purpose_bit_flags, 46, start, end, input, end_of_input, process }; zip_compression_algorithm_t zip_algorithm_bzip2_decompress = { maximum_compressed_size, decompress_allocate, deallocate, general_purpose_bit_flags, 46, start, end, input, end_of_input, process }; /* clang-format on */ ================================================ FILE: external/libzip/lib/zip_algorithm_deflate.c ================================================ /* zip_algorithm_deflate.c -- deflate (de)compression routines Copyright (C) 2017-2023 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "zipint.h" #include #include #include struct ctx { zip_error_t *error; bool compress; int level; int mem_level; bool end_of_input; z_stream zstr; }; static zip_uint64_t maximum_compressed_size(zip_uint64_t uncompressed_size) { /* max deflate size increase: size + ceil(size/16k)*5+6 */ zip_uint64_t compressed_size = uncompressed_size + (uncompressed_size + 16383) / 16384 * 5 + 6; if (compressed_size < uncompressed_size) { return ZIP_UINT64_MAX; } return compressed_size; } static void * allocate(bool compress, zip_uint32_t compression_flags, zip_error_t *error) { struct ctx *ctx; if ((ctx = (struct ctx *)malloc(sizeof(*ctx))) == NULL) { zip_error_set(error, ZIP_ET_SYS, errno); return NULL; } ctx->error = error; ctx->compress = compress; if (compression_flags >= 1 && compression_flags <= 9) { ctx->level = (int)compression_flags; } else { ctx->level = Z_BEST_COMPRESSION; } ctx->mem_level = compression_flags == TORRENTZIP_COMPRESSION_FLAGS ? TORRENTZIP_MEM_LEVEL : MAX_MEM_LEVEL; ctx->end_of_input = false; ctx->zstr.zalloc = Z_NULL; ctx->zstr.zfree = Z_NULL; ctx->zstr.opaque = NULL; return ctx; } static void * compress_allocate(zip_uint16_t method, zip_uint32_t compression_flags, zip_error_t *error) { (void)method; return allocate(true, compression_flags, error); } static void * decompress_allocate(zip_uint16_t method, zip_uint32_t compression_flags, zip_error_t *error) { (void)method; return allocate(false, compression_flags, error); } static void deallocate(void *ud) { struct ctx *ctx = (struct ctx *)ud; free(ctx); } static zip_uint16_t general_purpose_bit_flags(void *ud) { struct ctx *ctx = (struct ctx *)ud; if (!ctx->compress) { return 0; } if (ctx->level < 3) { return 2 << 1; } else if (ctx->level > 7) { return 1 << 1; } return 0; } static bool start(void *ud, zip_stat_t *st, zip_file_attributes_t *attributes) { struct ctx *ctx = (struct ctx *)ud; int ret; (void)st; (void)attributes; ctx->zstr.avail_in = 0; ctx->zstr.next_in = NULL; ctx->zstr.avail_out = 0; ctx->zstr.next_out = NULL; if (ctx->compress) { /* negative value to tell zlib not to write a header */ ret = deflateInit2(&ctx->zstr, ctx->level, Z_DEFLATED, -MAX_WBITS, ctx->mem_level, Z_DEFAULT_STRATEGY); } else { ret = inflateInit2(&ctx->zstr, -MAX_WBITS); } if (ret != Z_OK) { zip_error_set(ctx->error, ZIP_ER_ZLIB, ret); return false; } return true; } static bool end(void *ud) { struct ctx *ctx = (struct ctx *)ud; int err; if (ctx->compress) { err = deflateEnd(&ctx->zstr); } else { err = inflateEnd(&ctx->zstr); } if (err != Z_OK) { zip_error_set(ctx->error, ZIP_ER_ZLIB, err); return false; } return true; } static bool input(void *ud, zip_uint8_t *data, zip_uint64_t length) { struct ctx *ctx = (struct ctx *)ud; if (length > UINT_MAX || ctx->zstr.avail_in > 0) { zip_error_set(ctx->error, ZIP_ER_INVAL, 0); return false; } ctx->zstr.avail_in = (uInt)length; ctx->zstr.next_in = (Bytef *)data; return true; } static bool end_of_input(void *ud) { struct ctx *ctx = (struct ctx *)ud; ctx->end_of_input = true; return ctx->zstr.avail_in != 0; } static zip_compression_status_t process(void *ud, zip_uint8_t *data, zip_uint64_t *length) { struct ctx *ctx = (struct ctx *)ud; uInt avail_out; int ret; avail_out = (uInt)ZIP_MIN(UINT_MAX, *length); ctx->zstr.avail_out = avail_out; ctx->zstr.next_out = (Bytef *)data; if (ctx->compress) { ret = deflate(&ctx->zstr, ctx->end_of_input ? Z_FINISH : 0); } else { ret = inflate(&ctx->zstr, Z_SYNC_FLUSH); } *length = avail_out - ctx->zstr.avail_out; switch (ret) { case Z_OK: return ZIP_COMPRESSION_OK; case Z_STREAM_END: return ZIP_COMPRESSION_END; case Z_BUF_ERROR: if (ctx->zstr.avail_in == 0) { return ZIP_COMPRESSION_NEED_DATA; } /* fallthrough */ default: zip_error_set(ctx->error, ZIP_ER_ZLIB, ret); return ZIP_COMPRESSION_ERROR; } } /* clang-format off */ zip_compression_algorithm_t zip_algorithm_deflate_compress = { maximum_compressed_size, compress_allocate, deallocate, general_purpose_bit_flags, 20, start, end, input, end_of_input, process }; zip_compression_algorithm_t zip_algorithm_deflate_decompress = { maximum_compressed_size, decompress_allocate, deallocate, general_purpose_bit_flags, 20, start, end, input, end_of_input, process }; /* clang-format on */ ================================================ FILE: external/libzip/lib/zip_algorithm_xz.c ================================================ /* zip_algorithm_xz.c -- LZMA/XZ (de)compression routines Bazed on zip_algorithm_deflate.c -- deflate (de)compression routines Copyright (C) 2017-2023 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "zipint.h" #include #include #include #include enum header_state { INCOMPLETE, OUTPUT, DONE }; #define HEADER_BYTES_ZIP 9 #define HEADER_MAGIC_LENGTH 4 #define HEADER_MAGIC1_OFFSET 0 #define HEADER_MAGIC2_OFFSET 2 #define HEADER_SIZE_OFFSET 9 #define HEADER_SIZE_LENGTH 8 #define HEADER_PARAMETERS_LENGTH 5 #define HEADER_LZMA_ALONE_LENGTH (HEADER_PARAMETERS_LENGTH + HEADER_SIZE_LENGTH) struct ctx { zip_error_t *error; bool compress; zip_uint32_t compression_flags; bool end_of_input; lzma_stream zstr; zip_uint16_t method; /* header member is used for converting from zip to "lzma alone" * format * * "lzma alone" file format starts with: * 5 bytes lzma parameters * 8 bytes uncompressed size * compressed data * * zip archive on-disk format starts with * 4 bytes magic (first two bytes vary, e.g. 0x0914 or 0x1002, next bytes are 0x0500) * 5 bytes lzma parameters * compressed data * * we read the data into a header of the form * 4 bytes magic * 5 bytes lzma parameters * 8 bytes uncompressed size */ zip_uint8_t header[HEADER_MAGIC_LENGTH + HEADER_LZMA_ALONE_LENGTH]; zip_uint8_t header_bytes_offset; enum header_state header_state; zip_uint64_t uncompresssed_size; }; static zip_uint64_t maximum_compressed_size(zip_uint64_t uncompressed_size) { /* According to https://sourceforge.net/p/sevenzip/discussion/45797/thread/b6bd62f8/ 1) you can use outSize = 1.10 * originalSize + 64 KB. in most cases outSize is less then 1.02 from originalSize. 2) You can try LZMA2, where outSize can be = 1.001 * originalSize + 1 KB. */ /* 13 bytes added for lzma alone header */ zip_uint64_t compressed_size = (zip_uint64_t)((double)uncompressed_size * 1.1) + 64 * 1024 + 13; if (compressed_size < uncompressed_size) { return ZIP_UINT64_MAX; } return compressed_size; } static void * allocate(bool compress, zip_uint32_t compression_flags, zip_error_t *error, zip_uint16_t method) { struct ctx *ctx; if ((ctx = (struct ctx *)malloc(sizeof(*ctx))) == NULL) { zip_error_set(error, ZIP_ER_MEMORY, 0); return NULL; } ctx->error = error; ctx->compress = compress; if (compression_flags <= 9) { ctx->compression_flags = compression_flags; } else { ctx->compression_flags = 6; /* default value */ } ctx->compression_flags |= LZMA_PRESET_EXTREME; ctx->end_of_input = false; memset(ctx->header, 0, sizeof(ctx->header)); ctx->header_bytes_offset = 0; if (method == ZIP_CM_LZMA) { ctx->header_state = INCOMPLETE; } else { ctx->header_state = DONE; } memset(&ctx->zstr, 0, sizeof(ctx->zstr)); ctx->method = method; return ctx; } static void * compress_allocate(zip_uint16_t method, zip_uint32_t compression_flags, zip_error_t *error) { return allocate(true, compression_flags, error, method); } static void * decompress_allocate(zip_uint16_t method, zip_uint32_t compression_flags, zip_error_t *error) { return allocate(false, compression_flags, error, method); } static void deallocate(void *ud) { struct ctx *ctx = (struct ctx *)ud; free(ctx); } static zip_uint16_t general_purpose_bit_flags(void *ud) { struct ctx *ctx = (struct ctx *)ud; if (!ctx->compress) { return 0; } if (ctx->method == ZIP_CM_LZMA) { /* liblzma always returns an EOS/EOPM marker, see * https://sourceforge.net/p/lzmautils/discussion/708858/thread/84c5dbb9/#a5e4/3764 */ return 1 << 1; } return 0; } static int map_error(lzma_ret ret) { switch (ret) { case LZMA_DATA_ERROR: case LZMA_UNSUPPORTED_CHECK: return ZIP_ER_COMPRESSED_DATA; case LZMA_MEM_ERROR: return ZIP_ER_MEMORY; case LZMA_OPTIONS_ERROR: return ZIP_ER_INVAL; default: return ZIP_ER_INTERNAL; } } static bool start(void *ud, zip_stat_t *st, zip_file_attributes_t *attributes) { struct ctx *ctx = (struct ctx *)ud; lzma_ret ret; lzma_options_lzma opt_lzma; lzma_lzma_preset(&opt_lzma, ctx->compression_flags); lzma_filter filters[] = { {.id = (ctx->method == ZIP_CM_LZMA ? LZMA_FILTER_LZMA1 : LZMA_FILTER_LZMA2), .options = &opt_lzma}, {.id = LZMA_VLI_UNKNOWN, .options = NULL}, }; ctx->zstr.avail_in = 0; ctx->zstr.next_in = NULL; ctx->zstr.avail_out = 0; ctx->zstr.next_out = NULL; if (ctx->compress) { if (ctx->method == ZIP_CM_LZMA) ret = lzma_alone_encoder(&ctx->zstr, filters[0].options); else ret = lzma_stream_encoder(&ctx->zstr, filters, LZMA_CHECK_CRC64); } else { if (ctx->method == ZIP_CM_LZMA) ret = lzma_alone_decoder(&ctx->zstr, UINT64_MAX); else ret = lzma_stream_decoder(&ctx->zstr, UINT64_MAX, LZMA_CONCATENATED); } if (ret != LZMA_OK) { zip_error_set(ctx->error, map_error(ret), 0); return false; } /* If general purpose bits 1 & 2 are both zero, write real uncompressed size in header. */ if ((attributes->valid & ZIP_FILE_ATTRIBUTES_GENERAL_PURPOSE_BIT_FLAGS) && (attributes->general_purpose_bit_mask & 0x6) == 0x6 && (attributes->general_purpose_bit_flags & 0x06) == 0 && (st->valid & ZIP_STAT_SIZE)) { ctx->uncompresssed_size = st->size; } else { ctx->uncompresssed_size = ZIP_UINT64_MAX; } return true; } static bool end(void *ud) { struct ctx *ctx = (struct ctx *)ud; lzma_end(&ctx->zstr); return true; } static bool input(void *ud, zip_uint8_t *data, zip_uint64_t length) { struct ctx *ctx = (struct ctx *)ud; if (length > UINT_MAX || ctx->zstr.avail_in > 0) { zip_error_set(ctx->error, ZIP_ER_INVAL, 0); return false; } /* For decompression of LZMA1: Have we read the full "lzma alone" header yet? */ if (ctx->method == ZIP_CM_LZMA && !ctx->compress && ctx->header_state == INCOMPLETE) { /* if not, get more of the data */ zip_uint8_t got = (zip_uint8_t)ZIP_MIN(HEADER_BYTES_ZIP - ctx->header_bytes_offset, length); (void)memcpy_s(ctx->header + ctx->header_bytes_offset, sizeof(ctx->header) - ctx->header_bytes_offset, data, got); ctx->header_bytes_offset += got; length -= got; data += got; /* Do we have a complete header now? */ if (ctx->header_bytes_offset == HEADER_BYTES_ZIP) { Bytef empty_buffer[1]; zip_buffer_t *buffer; /* check magic */ if (ctx->header[HEADER_MAGIC2_OFFSET] != 0x05 || ctx->header[HEADER_MAGIC2_OFFSET + 1] != 0x00) { /* magic does not match */ zip_error_set(ctx->error, ZIP_ER_COMPRESSED_DATA, 0); return false; } /* set size of uncompressed data in "lzma alone" header to "unknown" */ if ((buffer = _zip_buffer_new(ctx->header + HEADER_SIZE_OFFSET, HEADER_SIZE_LENGTH)) == NULL) { zip_error_set(ctx->error, ZIP_ER_MEMORY, 0); return false; } _zip_buffer_put_64(buffer, ctx->uncompresssed_size); _zip_buffer_free(buffer); /* Feed header into "lzma alone" decoder, for * initialization; this should not produce output. */ ctx->zstr.next_in = (void *)(ctx->header + HEADER_MAGIC_LENGTH); ctx->zstr.avail_in = HEADER_LZMA_ALONE_LENGTH; ctx->zstr.total_in = 0; ctx->zstr.next_out = empty_buffer; ctx->zstr.avail_out = sizeof(*empty_buffer); ctx->zstr.total_out = 0; /* this just initializes the decoder and does not produce output, so it consumes the complete header */ if (lzma_code(&ctx->zstr, LZMA_RUN) != LZMA_OK || ctx->zstr.total_out > 0) { zip_error_set(ctx->error, ZIP_ER_COMPRESSED_DATA, 0); return false; } ctx->header_state = DONE; } } ctx->zstr.avail_in = (uInt)length; ctx->zstr.next_in = (Bytef *)data; return true; } static bool end_of_input(void *ud) { struct ctx *ctx = (struct ctx *)ud; ctx->end_of_input = true; return ctx->zstr.avail_in != 0; } static zip_compression_status_t process(void *ud, zip_uint8_t *data, zip_uint64_t *length) { struct ctx *ctx = (struct ctx *)ud; uInt avail_out; lzma_ret ret; /* for compression of LZMA1 */ if (ctx->method == ZIP_CM_LZMA && ctx->compress) { if (ctx->header_state == INCOMPLETE) { /* write magic to output buffer */ ctx->header[0] = 0x09; ctx->header[1] = 0x14; ctx->header[2] = 0x05; ctx->header[3] = 0x00; /* generate lzma parameters into output buffer */ ctx->zstr.avail_out = HEADER_LZMA_ALONE_LENGTH; ctx->zstr.next_out = ctx->header + HEADER_MAGIC_LENGTH; ret = lzma_code(&ctx->zstr, LZMA_RUN); if (ret != LZMA_OK || ctx->zstr.avail_out != 0) { /* assume that the whole header will be provided with the first call to lzma_code */ return ZIP_COMPRESSION_ERROR; } ctx->header_state = OUTPUT; } if (ctx->header_state == OUTPUT) { /* write header */ zip_uint8_t write_len = (zip_uint8_t)ZIP_MIN(HEADER_BYTES_ZIP - ctx->header_bytes_offset, *length); (void)memcpy_s(data, *length, ctx->header + ctx->header_bytes_offset, write_len); ctx->header_bytes_offset += write_len; *length = write_len; if (ctx->header_bytes_offset == HEADER_BYTES_ZIP) { ctx->header_state = DONE; } return ZIP_COMPRESSION_OK; } } avail_out = (uInt)ZIP_MIN(UINT_MAX, *length); ctx->zstr.avail_out = avail_out; ctx->zstr.next_out = (Bytef *)data; ret = lzma_code(&ctx->zstr, ctx->end_of_input ? LZMA_FINISH : LZMA_RUN); *length = avail_out - ctx->zstr.avail_out; switch (ret) { case LZMA_OK: return ZIP_COMPRESSION_OK; case LZMA_STREAM_END: return ZIP_COMPRESSION_END; case LZMA_BUF_ERROR: if (ctx->zstr.avail_in == 0) { return ZIP_COMPRESSION_NEED_DATA; } /* fallthrough */ default: zip_error_set(ctx->error, map_error(ret), 0); return ZIP_COMPRESSION_ERROR; } } /* Version Required should be set to 63 (6.3) because this compression method was only defined in appnote.txt version 6.3.8, but Winzip does not unpack it if the value is not 20. */ /* clang-format off */ zip_compression_algorithm_t zip_algorithm_xz_compress = { maximum_compressed_size, compress_allocate, deallocate, general_purpose_bit_flags, 20, start, end, input, end_of_input, process }; zip_compression_algorithm_t zip_algorithm_xz_decompress = { maximum_compressed_size, decompress_allocate, deallocate, general_purpose_bit_flags, 20, start, end, input, end_of_input, process }; /* clang-format on */ ================================================ FILE: external/libzip/lib/zip_algorithm_zstd.c ================================================ /* zip_algorithm_zstd.c -- zstd (de)compression routines Copyright (C) 2020-2023 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "zipint.h" #include #include #include struct ctx { zip_error_t *error; bool compress; int compression_flags; bool end_of_input; ZSTD_DStream *zdstream; ZSTD_CStream *zcstream; ZSTD_outBuffer out; ZSTD_inBuffer in; }; static zip_uint64_t maximum_compressed_size(zip_uint64_t uncompressed_size) { return ZSTD_compressBound(uncompressed_size); } static void * allocate(bool compress, zip_uint32_t compression_flags, zip_error_t *error) { struct ctx *ctx; if ((ctx = (struct ctx *)malloc(sizeof(*ctx))) == NULL) { return NULL; } ctx->compression_flags = (zip_int32_t)compression_flags; if (ctx->compression_flags < ZSTD_minCLevel() || ctx->compression_flags > ZSTD_maxCLevel()) { ctx->compression_flags = 0; /* let zstd choose */ } ctx->error = error; ctx->compress = compress; ctx->end_of_input = false; ctx->zdstream = NULL; ctx->zcstream = NULL; ctx->in.src = NULL; ctx->in.pos = 0; ctx->in.size = 0; ctx->out.dst = NULL; ctx->out.pos = 0; ctx->out.size = 0; return ctx; } static void * compress_allocate(zip_uint16_t method, zip_uint32_t compression_flags, zip_error_t *error) { (void)method; return allocate(true, compression_flags, error); } static void * decompress_allocate(zip_uint16_t method, zip_uint32_t compression_flags, zip_error_t *error) { (void)method; return allocate(false, compression_flags, error); } static void deallocate(void *ud) { struct ctx *ctx = (struct ctx *)ud; free(ctx); } static zip_uint16_t general_purpose_bit_flags(void *ud) { (void)ud; return 0; } static int map_error(size_t ret) { switch (ret) { case ZSTD_error_no_error: return ZIP_ER_OK; case ZSTD_error_corruption_detected: case ZSTD_error_checksum_wrong: case ZSTD_error_dictionary_corrupted: case ZSTD_error_dictionary_wrong: return ZIP_ER_COMPRESSED_DATA; case ZSTD_error_memory_allocation: return ZIP_ER_MEMORY; case ZSTD_error_parameter_unsupported: case ZSTD_error_parameter_outOfBound: return ZIP_ER_INVAL; default: return ZIP_ER_INTERNAL; } } static bool start(void *ud, zip_stat_t *st, zip_file_attributes_t *attributes) { struct ctx *ctx = (struct ctx *)ud; (void)st; (void)attributes; ctx->in.src = NULL; ctx->in.pos = 0; ctx->in.size = 0; ctx->out.dst = NULL; ctx->out.pos = 0; ctx->out.size = 0; if (ctx->compress) { size_t ret; ctx->zcstream = ZSTD_createCStream(); if (ctx->zcstream == NULL) { zip_error_set(ctx->error, ZIP_ER_MEMORY, 0); return false; } ret = ZSTD_initCStream(ctx->zcstream, ctx->compression_flags); if (ZSTD_isError(ret)) { zip_error_set(ctx->error, ZIP_ER_ZLIB, map_error(ret)); return false; } } else { ctx->zdstream = ZSTD_createDStream(); if (ctx->zdstream == NULL) { zip_error_set(ctx->error, ZIP_ER_MEMORY, 0); return false; } } return true; } static bool end(void *ud) { struct ctx *ctx = (struct ctx *)ud; size_t ret; if (ctx->compress) { ret = ZSTD_freeCStream(ctx->zcstream); ctx->zcstream = NULL; } else { ret = ZSTD_freeDStream(ctx->zdstream); ctx->zdstream = NULL; } if (ZSTD_isError(ret)) { zip_error_set(ctx->error, map_error(ret), 0); return false; } return true; } static bool input(void *ud, zip_uint8_t *data, zip_uint64_t length) { struct ctx *ctx = (struct ctx *)ud; if (length > SIZE_MAX || ctx->in.pos != ctx->in.size) { zip_error_set(ctx->error, ZIP_ER_INVAL, 0); return false; } ctx->in.src = (const void *)data; ctx->in.size = (size_t)length; ctx->in.pos = 0; return true; } static bool end_of_input(void *ud) { struct ctx *ctx = (struct ctx *)ud; ctx->end_of_input = true; return ctx->in.pos != ctx->in.size; } static zip_compression_status_t process(void *ud, zip_uint8_t *data, zip_uint64_t *length) { struct ctx *ctx = (struct ctx *)ud; size_t ret; if (ctx->in.pos == ctx->in.size && !ctx->end_of_input) { *length = 0; return ZIP_COMPRESSION_NEED_DATA; } ctx->out.dst = data; ctx->out.pos = 0; ctx->out.size = ZIP_MIN(SIZE_MAX, *length); if (ctx->compress) { if (ctx->in.pos == ctx->in.size && ctx->end_of_input) { ret = ZSTD_endStream(ctx->zcstream, &ctx->out); if (ret == 0) { *length = ctx->out.pos; return ZIP_COMPRESSION_END; } } else { ret = ZSTD_compressStream(ctx->zcstream, &ctx->out, &ctx->in); } } else { ret = ZSTD_decompressStream(ctx->zdstream, &ctx->out, &ctx->in); } if (ZSTD_isError(ret)) { zip_error_set(ctx->error, map_error(ret), 0); return ZIP_COMPRESSION_ERROR; } *length = ctx->out.pos; if (ctx->in.pos == ctx->in.size) { return ZIP_COMPRESSION_NEED_DATA; } return ZIP_COMPRESSION_OK; } /* Version Required should be set to 63 (6.3) because this compression method was only defined in appnote.txt version 6.3.7, but Winzip does not unpack it if the value is not 20. */ /* clang-format off */ zip_compression_algorithm_t zip_algorithm_zstd_compress = { maximum_compressed_size, compress_allocate, deallocate, general_purpose_bit_flags, 20, start, end, input, end_of_input, process }; zip_compression_algorithm_t zip_algorithm_zstd_decompress = { maximum_compressed_size, decompress_allocate, deallocate, general_purpose_bit_flags, 20, start, end, input, end_of_input, process }; /* clang-format on */ ================================================ FILE: external/libzip/lib/zip_buffer.c ================================================ /* zip_buffer.c -- bounds checked access to memory buffer Copyright (C) 2014-2024 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include "zipint.h" zip_uint8_t * _zip_buffer_data(zip_buffer_t *buffer) { return buffer->data; } void _zip_buffer_free(zip_buffer_t *buffer) { if (buffer == NULL) { return; } if (buffer->free_data) { free(buffer->data); } free(buffer); } bool _zip_buffer_eof(zip_buffer_t *buffer) { return buffer->ok && buffer->offset == buffer->size; } zip_uint8_t * _zip_buffer_get(zip_buffer_t *buffer, zip_uint64_t length) { zip_uint8_t *data; data = _zip_buffer_peek(buffer, length); if (data != NULL) { buffer->offset += length; } return data; } zip_uint16_t _zip_buffer_get_16(zip_buffer_t *buffer) { zip_uint8_t *data = _zip_buffer_get(buffer, 2); if (data == NULL) { return 0; } return (zip_uint16_t)(data[0] + (data[1] << 8)); } zip_uint32_t _zip_buffer_get_32(zip_buffer_t *buffer) { zip_uint8_t *data = _zip_buffer_get(buffer, 4); if (data == NULL) { return 0; } return ((((((zip_uint32_t)data[3] << 8) + data[2]) << 8) + data[1]) << 8) + data[0]; } zip_uint64_t _zip_buffer_get_64(zip_buffer_t *buffer) { zip_uint8_t *data = _zip_buffer_get(buffer, 8); if (data == NULL) { return 0; } return ((zip_uint64_t)data[7] << 56) + ((zip_uint64_t)data[6] << 48) + ((zip_uint64_t)data[5] << 40) + ((zip_uint64_t)data[4] << 32) + ((zip_uint64_t)data[3] << 24) + ((zip_uint64_t)data[2] << 16) + ((zip_uint64_t)data[1] << 8) + (zip_uint64_t)data[0]; } zip_uint8_t _zip_buffer_get_8(zip_buffer_t *buffer) { zip_uint8_t *data = _zip_buffer_get(buffer, 1); if (data == NULL) { return 0; } return data[0]; } zip_uint64_t _zip_buffer_left(zip_buffer_t *buffer) { return buffer->ok ? buffer->size - buffer->offset : 0; } zip_uint64_t _zip_buffer_read(zip_buffer_t *buffer, zip_uint8_t *data, zip_uint64_t length) { zip_uint64_t copied; if (_zip_buffer_left(buffer) < length) { length = _zip_buffer_left(buffer); } copied = 0; while (copied < length) { size_t n = ZIP_MIN(length - copied, SIZE_MAX); (void)memcpy_s(data + copied, n, _zip_buffer_get(buffer, n), n); copied += n; } return copied; } zip_buffer_t * _zip_buffer_new(zip_uint8_t *data, zip_uint64_t size) { bool free_data = (data == NULL); zip_buffer_t *buffer; #if ZIP_UINT64_MAX > SIZE_MAX if (size > SIZE_MAX) { return NULL; } #endif if (data == NULL) { if ((data = (zip_uint8_t *)malloc((size_t)size)) == NULL) { return NULL; } } if ((buffer = (zip_buffer_t *)malloc(sizeof(*buffer))) == NULL) { if (free_data) { free(data); } return NULL; } buffer->ok = true; buffer->data = data; buffer->size = size; buffer->offset = 0; buffer->free_data = free_data; return buffer; } zip_buffer_t * _zip_buffer_new_from_source(zip_source_t *src, zip_uint64_t size, zip_uint8_t *buf, zip_error_t *error) { zip_buffer_t *buffer; if ((buffer = _zip_buffer_new(buf, size)) == NULL) { zip_error_set(error, ZIP_ER_MEMORY, 0); return NULL; } if (_zip_read(src, buffer->data, size, error) < 0) { _zip_buffer_free(buffer); return NULL; } return buffer; } zip_uint64_t _zip_buffer_offset(zip_buffer_t *buffer) { return buffer->ok ? buffer->offset : 0; } bool _zip_buffer_ok(zip_buffer_t *buffer) { return buffer->ok; } zip_uint8_t * _zip_buffer_peek(zip_buffer_t *buffer, zip_uint64_t length) { zip_uint8_t *data; if (!buffer->ok || buffer->offset + length < length || buffer->offset + length > buffer->size) { buffer->ok = false; return NULL; } data = buffer->data + buffer->offset; return data; } int _zip_buffer_put(zip_buffer_t *buffer, const void *src, size_t length) { zip_uint8_t *dst = _zip_buffer_get(buffer, length); if (dst == NULL) { return -1; } (void)memcpy_s(dst, length, src, length); return 0; } int _zip_buffer_put_16(zip_buffer_t *buffer, zip_uint16_t i) { zip_uint8_t *data = _zip_buffer_get(buffer, 2); if (data == NULL) { return -1; } data[0] = (zip_uint8_t)(i & 0xff); data[1] = (zip_uint8_t)((i >> 8) & 0xff); return 0; } int _zip_buffer_put_32(zip_buffer_t *buffer, zip_uint32_t i) { zip_uint8_t *data = _zip_buffer_get(buffer, 4); if (data == NULL) { return -1; } data[0] = (zip_uint8_t)(i & 0xff); data[1] = (zip_uint8_t)((i >> 8) & 0xff); data[2] = (zip_uint8_t)((i >> 16) & 0xff); data[3] = (zip_uint8_t)((i >> 24) & 0xff); return 0; } int _zip_buffer_put_64(zip_buffer_t *buffer, zip_uint64_t i) { zip_uint8_t *data = _zip_buffer_get(buffer, 8); if (data == NULL) { return -1; } data[0] = (zip_uint8_t)(i & 0xff); data[1] = (zip_uint8_t)((i >> 8) & 0xff); data[2] = (zip_uint8_t)((i >> 16) & 0xff); data[3] = (zip_uint8_t)((i >> 24) & 0xff); data[4] = (zip_uint8_t)((i >> 32) & 0xff); data[5] = (zip_uint8_t)((i >> 40) & 0xff); data[6] = (zip_uint8_t)((i >> 48) & 0xff); data[7] = (zip_uint8_t)((i >> 56) & 0xff); return 0; } int _zip_buffer_put_8(zip_buffer_t *buffer, zip_uint8_t i) { zip_uint8_t *data = _zip_buffer_get(buffer, 1); if (data == NULL) { return -1; } data[0] = i; return 0; } int _zip_buffer_set_offset(zip_buffer_t *buffer, zip_uint64_t offset) { if (offset > buffer->size) { buffer->ok = false; return -1; } buffer->ok = true; buffer->offset = offset; return 0; } int _zip_buffer_skip(zip_buffer_t *buffer, zip_uint64_t length) { zip_uint64_t offset = buffer->offset + length; if (offset < buffer->offset) { buffer->ok = false; return -1; } return _zip_buffer_set_offset(buffer, offset); } zip_uint64_t _zip_buffer_size(zip_buffer_t *buffer) { return buffer->size; } ================================================ FILE: external/libzip/lib/zip_close.c ================================================ /* zip_close.c -- close zip archive and update changes Copyright (C) 1999-2024 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "zipint.h" #include #include #ifdef _WIN32 #include #include #endif static int add_data(zip_t *, zip_source_t *, zip_dirent_t *); static int copy_data(zip_t *, zip_uint64_t); static int copy_source(zip_t *, zip_source_t *, zip_source_t *, zip_int64_t); static int torrentzip_compare_names(const void *a, const void *b); static int write_cdir(zip_t *, const zip_filelist_t *, zip_uint64_t); static int write_data_descriptor(zip_t *za, const zip_dirent_t *dirent, int is_zip64); ZIP_EXTERN int zip_close(zip_t *za) { zip_uint64_t i, j, survivors, unchanged_offset; zip_int64_t off; int error; zip_filelist_t *filelist; int changed; if (za == NULL) return -1; changed = _zip_changed(za, &survivors); if (survivors == 0 && !(za->ch_flags & ZIP_AFL_CREATE_OR_KEEP_FILE_FOR_EMPTY_ARCHIVE)) { /* don't create zip files with no entries */ if ((za->open_flags & ZIP_TRUNCATE) || changed) { if (zip_source_remove(za->src) < 0) { if (!((zip_error_code_zip(zip_source_error(za->src)) == ZIP_ER_REMOVE) && (zip_error_code_system(zip_source_error(za->src)) == ENOENT))) { zip_error_set_from_source(&za->error, za->src); return -1; } } } zip_discard(za); return 0; } /* Always write empty archive if we are told to keep it, otherwise it wouldn't be created if the file doesn't already exist. */ if (!changed && survivors > 0) { zip_discard(za); return 0; } if (survivors > za->nentry) { zip_error_set(&za->error, ZIP_ER_INTERNAL, 0); return -1; } if ((filelist = (zip_filelist_t *)malloc(sizeof(filelist[0]) * (size_t)survivors)) == NULL) return -1; unchanged_offset = ZIP_UINT64_MAX; /* create list of files with index into original archive */ for (i = j = 0; i < za->nentry; i++) { if (za->entry[i].orig != NULL && ZIP_ENTRY_HAS_CHANGES(&za->entry[i])) { unchanged_offset = ZIP_MIN(unchanged_offset, za->entry[i].orig->offset); } if (za->entry[i].deleted) { continue; } if (j >= survivors) { free(filelist); zip_error_set(&za->error, ZIP_ER_INTERNAL, 0); return -1; } filelist[j].idx = i; filelist[j].name = zip_get_name(za, i, 0); j++; } if (j < survivors) { free(filelist); zip_error_set(&za->error, ZIP_ER_INTERNAL, 0); return -1; } if (ZIP_WANT_TORRENTZIP(za)) { qsort(filelist, (size_t)survivors, sizeof(filelist[0]), torrentzip_compare_names); } if (ZIP_WANT_TORRENTZIP(za) || (zip_source_supports(za->src) & ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_BEGIN_WRITE_CLONING)) == 0) { unchanged_offset = 0; } else { if (unchanged_offset == ZIP_UINT64_MAX) { /* we're keeping all file data, find the end of the last one */ zip_uint64_t last_index = ZIP_UINT64_MAX; unchanged_offset = 0; for (i = 0; i < za->nentry; i++) { if (za->entry[i].orig != NULL) { if (za->entry[i].orig->offset >= unchanged_offset) { unchanged_offset = za->entry[i].orig->offset; last_index = i; } } } if (last_index != ZIP_UINT64_MAX) { if ((unchanged_offset = _zip_file_get_end(za, last_index, &za->error)) == 0) { free(filelist); return -1; } } } if (unchanged_offset > 0) { if (zip_source_begin_write_cloning(za->src, unchanged_offset) < 0) { /* cloning not supported, need to copy everything */ unchanged_offset = 0; } } } if (unchanged_offset == 0) { if (zip_source_begin_write(za->src) < 0) { zip_error_set_from_source(&za->error, za->src); free(filelist); return -1; } } if (_zip_progress_start(za->progress) != 0) { zip_error_set(&za->error, ZIP_ER_CANCELLED, 0); zip_source_rollback_write(za->src); free(filelist); return -1; } error = 0; for (j = 0; j < survivors; j++) { int new_data; zip_entry_t *entry; zip_dirent_t *de; if (_zip_progress_subrange(za->progress, (double)j / (double)survivors, (double)(j + 1) / (double)survivors) != 0) { zip_error_set(&za->error, ZIP_ER_CANCELLED, 0); error = 1; break; } i = filelist[j].idx; entry = za->entry + i; if (entry->orig != NULL && entry->orig->offset < unchanged_offset) { /* already implicitly copied by cloning */ continue; } new_data = (ZIP_ENTRY_DATA_CHANGED(entry) || ZIP_ENTRY_CHANGED(entry, ZIP_DIRENT_COMP_METHOD) || ZIP_ENTRY_CHANGED(entry, ZIP_DIRENT_ENCRYPTION_METHOD)) || (ZIP_WANT_TORRENTZIP(za) && !ZIP_IS_TORRENTZIP(za)); /* create new local directory entry */ if (entry->changes == NULL) { if ((entry->changes = _zip_dirent_clone(entry->orig)) == NULL) { zip_error_set(&za->error, ZIP_ER_MEMORY, 0); error = 1; break; } } else if (entry->orig != NULL) { if (!_zip_dirent_merge(entry->changes, entry->orig, ZIP_ENTRY_DATA_CHANGED(entry), &za->error)) { error = 1; break; } } de = entry->changes; if (_zip_read_local_ef(za, i) < 0) { error = 1; break; } if (ZIP_WANT_TORRENTZIP(za)) { zip_dirent_torrentzip_normalize(entry->changes); } if ((off = zip_source_tell_write(za->src)) < 0) { zip_error_set_from_source(&za->error, za->src); error = 1; break; } de->offset = (zip_uint64_t)off; if (new_data) { zip_source_t *zs; zs = NULL; if (!ZIP_ENTRY_DATA_CHANGED(entry)) { if ((zs = zip_source_zip_file_create(za, i, ZIP_FL_UNCHANGED, 0, -1, NULL, &za->error)) == NULL) { error = 1; break; } } /* add_data writes dirent */ if (add_data(za, zs ? zs : entry->source, de) < 0) { error = 1; if (zs) zip_source_free(zs); break; } if (zs) zip_source_free(zs); } else { zip_uint64_t offset; if (de->encryption_method != ZIP_EM_TRAD_PKWARE) { /* when copying data, all sizes are known -> no data descriptor needed */ /* except for PKWare encryption, where removing the data descriptor breaks password validation */ de->bitflags &= (zip_uint16_t)~ZIP_GPBF_DATA_DESCRIPTOR; } if (_zip_dirent_write(za, de, ZIP_FL_LOCAL) < 0) { error = 1; break; } if ((offset = _zip_file_get_offset(za, i, &za->error)) == 0) { error = 1; break; } if (zip_source_seek(za->src, (zip_int64_t)offset, SEEK_SET) < 0) { zip_error_set_from_source(&za->error, za->src); error = 1; break; } if (copy_data(za, de->comp_size) < 0) { error = 1; break; } if (de->bitflags & ZIP_GPBF_DATA_DESCRIPTOR) { if (write_data_descriptor(za, de, _zip_dirent_needs_zip64(de, 0)) < 0) { error = 1; break; } } } } if (!error) { if (write_cdir(za, filelist, survivors) < 0) error = 1; } free(filelist); if (!error) { if (zip_source_commit_write(za->src) != 0) { zip_error_set_from_source(&za->error, za->src); error = 1; } _zip_progress_end(za->progress); } if (error) { zip_source_rollback_write(za->src); return -1; } zip_discard(za); return 0; } static int add_data(zip_t *za, zip_source_t *src, zip_dirent_t *de) { zip_int64_t offstart, offdata, offend, data_length; zip_stat_t st; zip_file_attributes_t attributes; zip_source_t *src_final, *src_tmp; int ret; int is_zip64; zip_flags_t flags; bool needs_recompress, needs_decompress, needs_crc, needs_compress, needs_reencrypt, needs_decrypt, needs_encrypt; bool dirent_changed; bool have_dos_time = false; time_t mtime_before_copy; if (zip_source_stat(src, &st) < 0) { zip_error_set_from_source(&za->error, src); return -1; } de->bitflags &= ~ZIP_GPBF_DATA_DESCRIPTOR; if ((st.valid & ZIP_STAT_COMP_METHOD) == 0) { st.valid |= ZIP_STAT_COMP_METHOD; st.comp_method = ZIP_CM_STORE; } if (ZIP_CM_IS_DEFAULT(de->comp_method) && st.comp_method != ZIP_CM_STORE) { de->comp_method = st.comp_method; } else if (de->comp_method == ZIP_CM_STORE && (st.valid & ZIP_STAT_SIZE)) { st.valid |= ZIP_STAT_COMP_SIZE; st.comp_size = st.size; } else { /* we'll recompress */ st.valid &= ~ZIP_STAT_COMP_SIZE; } if ((st.valid & ZIP_STAT_ENCRYPTION_METHOD) == 0) { st.valid |= ZIP_STAT_ENCRYPTION_METHOD; st.encryption_method = ZIP_EM_NONE; } flags = ZIP_EF_LOCAL; if ((st.valid & ZIP_STAT_SIZE) == 0) { /* TODO: not valid for torrentzip */ flags |= ZIP_FL_FORCE_ZIP64; data_length = -1; } else { de->uncomp_size = st.size; /* this is technically incorrect (copy_source counts compressed data), but it's the best we have */ data_length = (zip_int64_t)st.size; if ((st.valid & ZIP_STAT_COMP_SIZE) == 0) { zip_uint64_t max_compressed_size; zip_uint16_t compression_method = ZIP_CM_ACTUAL(de->comp_method); if (compression_method == ZIP_CM_STORE) { max_compressed_size = st.size; } else { zip_compression_algorithm_t *algorithm = _zip_get_compression_algorithm(compression_method, true); if (algorithm == NULL) { max_compressed_size = ZIP_UINT64_MAX; } else { max_compressed_size = algorithm->maximum_compressed_size(st.size); } } if (max_compressed_size > 0xffffffffu) { /* TODO: not valid for torrentzip */ flags |= ZIP_FL_FORCE_ZIP64; } } else { de->comp_size = st.comp_size; data_length = (zip_int64_t)st.comp_size; } } if ((de->changed & ZIP_DIRENT_LAST_MOD) == 0) { int ret2 = zip_source_get_dos_time(src, &de->last_mod); if (ret2 < 0) { zip_error_set_from_source(&za->error, src); return -1; } if (ret2 == 1) { have_dos_time = true; } else { if (st.valid & ZIP_STAT_MTIME) { mtime_before_copy = st.mtime; } else { time(&mtime_before_copy); } if (_zip_u2d_time(mtime_before_copy, &de->last_mod, &za->error) < 0) { return -1; } } } if ((offstart = zip_source_tell_write(za->src)) < 0) { zip_error_set_from_source(&za->error, za->src); return -1; } needs_recompress = ZIP_WANT_TORRENTZIP(za) || st.comp_method != ZIP_CM_ACTUAL(de->comp_method); needs_decompress = needs_recompress && (st.comp_method != ZIP_CM_STORE); /* in these cases we can compute the CRC ourselves, so we do */ needs_crc = (st.comp_method == ZIP_CM_STORE) || needs_decompress; needs_compress = needs_recompress && (de->comp_method != ZIP_CM_STORE); needs_reencrypt = needs_recompress || (de->changed & ZIP_DIRENT_PASSWORD) || (de->encryption_method != st.encryption_method); needs_decrypt = needs_reencrypt && (st.encryption_method != ZIP_EM_NONE); needs_encrypt = needs_reencrypt && (de->encryption_method != ZIP_EM_NONE); src_final = src; zip_source_keep(src_final); if (!needs_decrypt && st.encryption_method == ZIP_EM_TRAD_PKWARE && (de->changed & ZIP_DIRENT_LAST_MOD)) { /* PKWare encryption uses the last modification time for password verification, therefore we can't change it without re-encrypting. Ignoring the requested modification time change seems more sensible than failing to close the archive. */ de->changed &= ~ZIP_DIRENT_LAST_MOD; } if (needs_decrypt) { zip_encryption_implementation impl; if ((impl = _zip_get_encryption_implementation(st.encryption_method, ZIP_CODEC_DECODE)) == NULL) { zip_error_set(&za->error, ZIP_ER_ENCRNOTSUPP, 0); zip_source_free(src_final); return -1; } if ((src_tmp = impl(za, src_final, st.encryption_method, ZIP_CODEC_DECODE, za->default_password)) == NULL) { /* error set by impl */ zip_source_free(src_final); return -1; } src_final = src_tmp; } if (needs_decompress) { if ((src_tmp = zip_source_decompress(za, src_final, st.comp_method)) == NULL) { zip_source_free(src_final); return -1; } src_final = src_tmp; } if (needs_crc) { if ((src_tmp = zip_source_crc_create(src_final, 0, &za->error)) == NULL) { zip_source_free(src_final); return -1; } src_final = src_tmp; } if (needs_compress) { if ((src_tmp = zip_source_compress(za, src_final, de->comp_method, de->compression_level)) == NULL) { zip_source_free(src_final); return -1; } src_final = src_tmp; } if (needs_encrypt) { zip_encryption_implementation impl; const char *password = NULL; if (de->password) { password = de->password; } else if (za->default_password) { password = za->default_password; } if ((impl = _zip_get_encryption_implementation(de->encryption_method, ZIP_CODEC_ENCODE)) == NULL) { zip_error_set(&za->error, ZIP_ER_ENCRNOTSUPP, 0); zip_source_free(src_final); return -1; } if (de->encryption_method == ZIP_EM_TRAD_PKWARE) { de->bitflags |= ZIP_GPBF_DATA_DESCRIPTOR; /* PKWare encryption uses last_mod, make sure it gets the right value. */ if (de->changed & ZIP_DIRENT_LAST_MOD) { if ((src_tmp = _zip_source_window_new(src_final, 0, -1, NULL, 0, NULL, &de->last_mod, NULL, 0, true, &za->error)) == NULL) { zip_source_free(src_final); return -1; } src_final = src_tmp; } } if ((src_tmp = impl(za, src_final, de->encryption_method, ZIP_CODEC_ENCODE, password)) == NULL) { /* error set by impl */ zip_source_free(src_final); return -1; } src_final = src_tmp; } if (!ZIP_WANT_TORRENTZIP(za)) { if (zip_source_get_file_attributes(src_final, &attributes) != 0) { zip_error_set_from_source(&za->error, src_final); zip_source_free(src_final); return -1; } _zip_dirent_apply_attributes(de, &attributes, (flags & ZIP_FL_FORCE_ZIP64) != 0); } /* as long as we don't support non-seekable output, clear data descriptor bit */ if ((is_zip64 = _zip_dirent_write(za, de, flags)) < 0) { zip_source_free(src_final); return -1; } if ((offdata = zip_source_tell_write(za->src)) < 0) { zip_error_set_from_source(&za->error, za->src); zip_source_free(src_final); return -1; } ret = copy_source(za, src_final, src, data_length); if (zip_source_stat(src_final, &st) < 0) { zip_error_set_from_source(&za->error, src_final); ret = -1; } if (!ZIP_WANT_TORRENTZIP(za)) { if (zip_source_get_file_attributes(src_final, &attributes) != 0) { zip_error_set_from_source(&za->error, src_final); ret = -1; } } zip_source_free(src_final); if (ret < 0) { return -1; } if ((offend = zip_source_tell_write(za->src)) < 0) { zip_error_set_from_source(&za->error, za->src); return -1; } if ((st.valid & (ZIP_STAT_COMP_METHOD | ZIP_STAT_CRC | ZIP_STAT_SIZE)) != (ZIP_STAT_COMP_METHOD | ZIP_STAT_CRC | ZIP_STAT_SIZE)) { zip_error_set(&za->error, ZIP_ER_INTERNAL, 0); return -1; } dirent_changed = ZIP_CM_ACTUAL(de->comp_method) != st.comp_method || de->crc != st.crc || de->uncomp_size != st.size || de->comp_size != (zip_uint64_t)(offend - offdata); de->comp_method = st.comp_method; de->crc = st.crc; de->uncomp_size = st.size; de->comp_size = (zip_uint64_t)(offend - offdata); if (!ZIP_WANT_TORRENTZIP(za)) { dirent_changed |= _zip_dirent_apply_attributes(de, &attributes, (flags & ZIP_FL_FORCE_ZIP64) != 0); if ((de->changed & ZIP_DIRENT_LAST_MOD) == 0 && !have_dos_time) { if (st.valid & ZIP_STAT_MTIME) { if (st.mtime != mtime_before_copy) { if (_zip_u2d_time(st.mtime, &de->last_mod, &za->error) < 0) { return -1; } dirent_changed = true; } } } } if (dirent_changed) { if (zip_source_seek_write(za->src, offstart, SEEK_SET) < 0) { zip_error_set_from_source(&za->error, za->src); return -1; } if ((ret = _zip_dirent_write(za, de, flags)) < 0) return -1; if (is_zip64 != ret) { /* Zip64 mismatch between preliminary file header written before data and final file header written afterwards */ zip_error_set(&za->error, ZIP_ER_INTERNAL, 0); return -1; } if (zip_source_seek_write(za->src, offend, SEEK_SET) < 0) { zip_error_set_from_source(&za->error, za->src); return -1; } } if (de->bitflags & ZIP_GPBF_DATA_DESCRIPTOR) { if (write_data_descriptor(za, de, is_zip64) < 0) { return -1; } } return 0; } static int copy_data(zip_t *za, zip_uint64_t len) { DEFINE_BYTE_ARRAY(buf, BUFSIZE); double total = (double)len; if (!byte_array_init(buf, BUFSIZE)) { zip_error_set(&za->error, ZIP_ER_MEMORY, 0); return -1; } while (len > 0) { zip_uint64_t n = ZIP_MIN(len, BUFSIZE); if (_zip_read(za->src, buf, n, &za->error) < 0) { byte_array_fini(buf); return -1; } if (_zip_write(za, buf, n) < 0) { byte_array_fini(buf); return -1; } len -= n; if (_zip_progress_update(za->progress, (total - (double)len) / total) != 0) { zip_error_set(&za->error, ZIP_ER_CANCELLED, 0); return -1; } } byte_array_fini(buf); return 0; } static int copy_source(zip_t *za, zip_source_t *src, zip_source_t *src_for_length, zip_int64_t data_length) { DEFINE_BYTE_ARRAY(buf, BUFSIZE); zip_int64_t n, current; int ret; if (zip_source_open(src) < 0) { zip_error_set_from_source(&za->error, src); return -1; } if (!byte_array_init(buf, BUFSIZE)) { zip_error_set(&za->error, ZIP_ER_MEMORY, 0); return -1; } ret = 0; current = 0; while ((n = zip_source_read(src, buf, BUFSIZE)) > 0) { if (_zip_write(za, buf, (zip_uint64_t)n) < 0) { ret = -1; break; } if (n == BUFSIZE && za->progress && data_length > 0) { zip_int64_t t; t = zip_source_tell(src_for_length); if (t >= 0) { current = t; } else { current += n; } if (_zip_progress_update(za->progress, (double)current / (double)data_length) != 0) { zip_error_set(&za->error, ZIP_ER_CANCELLED, 0); ret = -1; break; } } } if (n < 0) { zip_error_set_from_source(&za->error, src); ret = -1; } byte_array_fini(buf); zip_source_close(src); return ret; } static int write_cdir(zip_t *za, const zip_filelist_t *filelist, zip_uint64_t survivors) { if (zip_source_tell_write(za->src) < 0) { return -1; } if (_zip_cdir_write(za, filelist, survivors) < 0) { return -1; } if (zip_source_tell_write(za->src) < 0) { return -1; } return 0; } int _zip_changed(const zip_t *za, zip_uint64_t *survivorsp) { int changed; zip_uint64_t i, survivors; changed = 0; survivors = 0; if (za->comment_changed || (ZIP_WANT_TORRENTZIP(za) && !ZIP_IS_TORRENTZIP(za))) { changed = 1; } for (i = 0; i < za->nentry; i++) { if (ZIP_ENTRY_HAS_CHANGES(&za->entry[i])) { changed = 1; } if (!za->entry[i].deleted) { survivors++; } } if (survivorsp) { *survivorsp = survivors; } return changed; } static int write_data_descriptor(zip_t *za, const zip_dirent_t *de, int is_zip64) { zip_buffer_t *buffer = _zip_buffer_new(NULL, MAX_DATA_DESCRIPTOR_LENGTH); int ret = 0; if (buffer == NULL) { zip_error_set(&za->error, ZIP_ER_MEMORY, 0); return -1; } _zip_buffer_put(buffer, DATADES_MAGIC, 4); _zip_buffer_put_32(buffer, de->crc); if (is_zip64) { _zip_buffer_put_64(buffer, de->comp_size); _zip_buffer_put_64(buffer, de->uncomp_size); } else { _zip_buffer_put_32(buffer, (zip_uint32_t)de->comp_size); _zip_buffer_put_32(buffer, (zip_uint32_t)de->uncomp_size); } if (!_zip_buffer_ok(buffer)) { zip_error_set(&za->error, ZIP_ER_INTERNAL, 0); ret = -1; } else { ret = _zip_write(za, _zip_buffer_data(buffer), _zip_buffer_offset(buffer)); } _zip_buffer_free(buffer); return ret; } static int torrentzip_compare_names(const void *a, const void *b) { const char *aname = ((const zip_filelist_t *)a)->name; const char *bname = ((const zip_filelist_t *)b)->name; if (aname == NULL) { return (bname != NULL) * -1; } else if (bname == NULL) { return 1; } return strcasecmp(aname, bname); } ================================================ FILE: external/libzip/lib/zip_crypto.h ================================================ /* zip_crypto.h -- crypto definitions Copyright (C) 2017-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef HAD_ZIP_CRYPTO_H #define HAD_ZIP_CRYPTO_H #define ZIP_CRYPTO_SHA1_LENGTH 20 #define ZIP_CRYPTO_AES_BLOCK_LENGTH 16 #if defined(HAVE_WINDOWS_CRYPTO) #include "zip_crypto_win.h" #elif defined(HAVE_COMMONCRYPTO) #include "zip_crypto_commoncrypto.h" #elif defined(HAVE_GNUTLS) #include "zip_crypto_gnutls.h" #elif defined(HAVE_OPENSSL) #include "zip_crypto_openssl.h" #elif defined(HAVE_MBEDTLS) #include "zip_crypto_mbedtls.h" #else #error "no crypto backend found" #endif #endif /* HAD_ZIP_CRYPTO_H */ ================================================ FILE: external/libzip/lib/zip_crypto_commoncrypto.c ================================================ /* zip_crypto_commoncrypto.c -- CommonCrypto wrapper. Copyright (C) 2018-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include "zipint.h" #include "zip_crypto.h" #include #include void _zip_crypto_aes_free(_zip_crypto_aes_t *aes) { if (aes == NULL) { return; } CCCryptorRelease(aes); } bool _zip_crypto_aes_encrypt_block(_zip_crypto_aes_t *aes, const zip_uint8_t *in, zip_uint8_t *out) { size_t len; CCCryptorUpdate(aes, in, ZIP_CRYPTO_AES_BLOCK_LENGTH, out, ZIP_CRYPTO_AES_BLOCK_LENGTH, &len); return true; } _zip_crypto_aes_t * _zip_crypto_aes_new(const zip_uint8_t *key, zip_uint16_t key_size, zip_error_t *error) { _zip_crypto_aes_t *aes; CCCryptorStatus ret; ret = CCCryptorCreate(kCCEncrypt, kCCAlgorithmAES, kCCOptionECBMode, key, key_size / 8, NULL, &aes); switch (ret) { case kCCSuccess: return aes; case kCCMemoryFailure: zip_error_set(error, ZIP_ER_MEMORY, 0); return NULL; case kCCParamError: zip_error_set(error, ZIP_ER_INVAL, 0); return NULL; default: zip_error_set(error, ZIP_ER_INTERNAL, 0); return NULL; } } void _zip_crypto_hmac_free(_zip_crypto_hmac_t *hmac) { if (hmac == NULL) { return; } _zip_crypto_clear(hmac, sizeof(*hmac)); free(hmac); } _zip_crypto_hmac_t * _zip_crypto_hmac_new(const zip_uint8_t *secret, zip_uint64_t secret_length, zip_error_t *error) { _zip_crypto_hmac_t *hmac; if ((hmac = (_zip_crypto_hmac_t *)malloc(sizeof(*hmac))) == NULL) { zip_error_set(error, ZIP_ER_MEMORY, 0); return NULL; } CCHmacInit(hmac, kCCHmacAlgSHA1, secret, secret_length); return hmac; } ================================================ FILE: external/libzip/lib/zip_crypto_commoncrypto.h ================================================ /* zip_crypto_commoncrypto.h -- definitions for CommonCrypto wrapper. Copyright (C) 2018-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef HAD_ZIP_CRYPTO_COMMONCRYPTO_H #define HAD_ZIP_CRYPTO_COMMONCRYPTO_H #include #define _zip_crypto_aes_t struct _CCCryptor #define _zip_crypto_hmac_t CCHmacContext void _zip_crypto_aes_free(_zip_crypto_aes_t *aes); bool _zip_crypto_aes_encrypt_block(_zip_crypto_aes_t *aes, const zip_uint8_t *in, zip_uint8_t *out); _zip_crypto_aes_t *_zip_crypto_aes_new(const zip_uint8_t *key, zip_uint16_t key_size, zip_error_t *error); #define _zip_crypto_hmac(hmac, data, length) (CCHmacUpdate((hmac), (data), (length)), true) void _zip_crypto_hmac_free(_zip_crypto_hmac_t *hmac); _zip_crypto_hmac_t *_zip_crypto_hmac_new(const zip_uint8_t *secret, zip_uint64_t secret_length, zip_error_t *error); #define _zip_crypto_hmac_output(hmac, data) (CCHmacFinal((hmac), (data)), true) #define _zip_crypto_pbkdf2(key, key_length, salt, salt_length, iterations, output, output_length) (CCKeyDerivationPBKDF(kCCPBKDF2, (const char *)(key), (key_length), (salt), (salt_length), kCCPRFHmacAlgSHA1, (iterations), (output), (output_length)) == kCCSuccess) #endif /* HAD_ZIP_CRYPTO_COMMONCRYPTO_H */ ================================================ FILE: external/libzip/lib/zip_crypto_gnutls.c ================================================ /* zip_crypto_gnutls.c -- GnuTLS wrapper. Copyright (C) 2018-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include "zipint.h" #include "zip_crypto.h" _zip_crypto_aes_t * _zip_crypto_aes_new(const zip_uint8_t *key, zip_uint16_t key_size, zip_error_t *error) { _zip_crypto_aes_t *aes; if ((aes = (_zip_crypto_aes_t *)malloc(sizeof(*aes))) == NULL) { zip_error_set(error, ZIP_ER_MEMORY, 0); return NULL; } aes->key_size = key_size; switch (aes->key_size) { case 128: nettle_aes128_set_encrypt_key(&aes->ctx.ctx_128, key); break; case 192: nettle_aes192_set_encrypt_key(&aes->ctx.ctx_192, key); break; case 256: nettle_aes256_set_encrypt_key(&aes->ctx.ctx_256, key); break; default: zip_error_set(error, ZIP_ER_INVAL, 0); free(aes); return NULL; } return aes; } bool _zip_crypto_aes_encrypt_block(_zip_crypto_aes_t *aes, const zip_uint8_t *in, zip_uint8_t *out) { switch (aes->key_size) { case 128: nettle_aes128_encrypt(&aes->ctx.ctx_128, ZIP_CRYPTO_AES_BLOCK_LENGTH, out, in); break; case 192: nettle_aes192_encrypt(&aes->ctx.ctx_192, ZIP_CRYPTO_AES_BLOCK_LENGTH, out, in); break; case 256: nettle_aes256_encrypt(&aes->ctx.ctx_256, ZIP_CRYPTO_AES_BLOCK_LENGTH, out, in); break; } return true; } void _zip_crypto_aes_free(_zip_crypto_aes_t *aes) { if (aes == NULL) { return; } _zip_crypto_clear(aes, sizeof(*aes)); free(aes); } _zip_crypto_hmac_t * _zip_crypto_hmac_new(const zip_uint8_t *secret, zip_uint64_t secret_length, zip_error_t *error) { _zip_crypto_hmac_t *hmac; if ((hmac = (_zip_crypto_hmac_t *)malloc(sizeof(*hmac))) == NULL) { zip_error_set(error, ZIP_ER_MEMORY, 0); return NULL; } if (gnutls_hmac_init(hmac, GNUTLS_MAC_SHA1, secret, secret_length) < 0) { zip_error_set(error, ZIP_ER_INTERNAL, 0); free(hmac); return NULL; } return hmac; } void _zip_crypto_hmac_free(_zip_crypto_hmac_t *hmac) { zip_uint8_t buf[ZIP_CRYPTO_SHA1_LENGTH]; if (hmac == NULL) { return; } gnutls_hmac_deinit(*hmac, buf); _zip_crypto_clear(hmac, sizeof(*hmac)); free(hmac); } ZIP_EXTERN bool zip_secure_random(zip_uint8_t *buffer, zip_uint16_t length) { return gnutls_rnd(GNUTLS_RND_KEY, buffer, length) == 0; } ================================================ FILE: external/libzip/lib/zip_crypto_gnutls.h ================================================ /* zip_crypto_gnutls.h -- definitions for GnuTLS wrapper. Copyright (C) 2018-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef HAD_ZIP_CRYPTO_GNUTLS_H #define HAD_ZIP_CRYPTO_GNUTLS_H #define HAVE_SECURE_RANDOM #include #include #include #include typedef struct { union { struct aes128_ctx ctx_128; struct aes192_ctx ctx_192; struct aes256_ctx ctx_256; } ctx; zip_uint16_t key_size; } _zip_crypto_aes_t; #define _zip_crypto_hmac_t gnutls_hmac_hd_t void _zip_crypto_aes_free(_zip_crypto_aes_t *aes); bool _zip_crypto_aes_encrypt_block(_zip_crypto_aes_t *aes, const zip_uint8_t *in, zip_uint8_t *out); _zip_crypto_aes_t *_zip_crypto_aes_new(const zip_uint8_t *key, zip_uint16_t key_size, zip_error_t *error); #define _zip_crypto_hmac(hmac, data, length) (gnutls_hmac(*(hmac), (data), (length)) == 0) void _zip_crypto_hmac_free(_zip_crypto_hmac_t *hmac); _zip_crypto_hmac_t *_zip_crypto_hmac_new(const zip_uint8_t *secret, zip_uint64_t secret_length, zip_error_t *error); #define _zip_crypto_hmac_output(hmac, data) (gnutls_hmac_output(*(hmac), (data)), true) #define _zip_crypto_pbkdf2(key, key_length, salt, salt_length, iterations, output, output_length) (pbkdf2_hmac_sha1((key_length), (key), (iterations), (salt_length), (salt), (output_length), (output)), true) #endif /* HAD_ZIP_CRYPTO_GNUTLS_H */ ================================================ FILE: external/libzip/lib/zip_crypto_mbedtls.c ================================================ /* zip_crypto_mbedtls.c -- mbed TLS wrapper Copyright (C) 2018-2023 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include "zipint.h" #include "zip_crypto.h" #include #include #include #include _zip_crypto_aes_t * _zip_crypto_aes_new(const zip_uint8_t *key, zip_uint16_t key_size, zip_error_t *error) { _zip_crypto_aes_t *aes; if ((aes = (_zip_crypto_aes_t *)malloc(sizeof(*aes))) == NULL) { zip_error_set(error, ZIP_ER_MEMORY, 0); return NULL; } mbedtls_aes_init(aes); mbedtls_aes_setkey_enc(aes, (const unsigned char *)key, (unsigned int)key_size); return aes; } void _zip_crypto_aes_free(_zip_crypto_aes_t *aes) { if (aes == NULL) { return; } mbedtls_aes_free(aes); free(aes); } _zip_crypto_hmac_t * _zip_crypto_hmac_new(const zip_uint8_t *secret, zip_uint64_t secret_length, zip_error_t *error) { _zip_crypto_hmac_t *hmac; if (secret_length > INT_MAX) { zip_error_set(error, ZIP_ER_INVAL, 0); return NULL; } if ((hmac = (_zip_crypto_hmac_t *)malloc(sizeof(*hmac))) == NULL) { zip_error_set(error, ZIP_ER_MEMORY, 0); return NULL; } mbedtls_md_init(hmac); if (mbedtls_md_setup(hmac, mbedtls_md_info_from_type(MBEDTLS_MD_SHA1), 1) != 0) { zip_error_set(error, ZIP_ER_INTERNAL, 0); free(hmac); return NULL; } if (mbedtls_md_hmac_starts(hmac, (const unsigned char *)secret, (size_t)secret_length) != 0) { zip_error_set(error, ZIP_ER_INTERNAL, 0); free(hmac); return NULL; } return hmac; } void _zip_crypto_hmac_free(_zip_crypto_hmac_t *hmac) { if (hmac == NULL) { return; } mbedtls_md_free(hmac); free(hmac); } bool _zip_crypto_pbkdf2(const zip_uint8_t *key, zip_uint64_t key_length, const zip_uint8_t *salt, zip_uint16_t salt_length, int iterations, zip_uint8_t *output, zip_uint64_t output_length) { mbedtls_md_context_t sha1_ctx; bool ok = true; #if MBEDTLS_VERSION_NUMBER < 0x03030000 mbedtls_md_init(&sha1_ctx); if (mbedtls_md_setup(&sha1_ctx, mbedtls_md_info_from_type(MBEDTLS_MD_SHA1), 1) != 0) { ok = false; } if (ok && mbedtls_pkcs5_pbkdf2_hmac(&sha1_ctx, (const unsigned char *)key, (size_t)key_length, (const unsigned char *)salt, (size_t)salt_length, (unsigned int)iterations, (uint32_t)output_length, (unsigned char *)output) != 0) { ok = false; } mbedtls_md_free(&sha1_ctx); #else ok = mbedtls_pkcs5_pbkdf2_hmac_ext(MBEDTLS_MD_SHA1, (const unsigned char *)key, (size_t)key_length, (const unsigned char *)salt, (size_t)salt_length, (unsigned int)iterations, (uint32_t)output_length, (unsigned char *)output) == 0; #endif // !defined(MBEDTLS_DEPRECATED_REMOVED) || MBEDTLS_VERSION_NUMBER < 0x03030000 return ok; } typedef struct { mbedtls_entropy_context entropy; mbedtls_ctr_drbg_context ctr_drbg; } zip_random_context_t; ZIP_EXTERN bool zip_secure_random(zip_uint8_t *buffer, zip_uint16_t length) { static zip_random_context_t *ctx = NULL; const unsigned char *pers = "zip_crypto_mbedtls"; if (!ctx) { ctx = (zip_random_context_t *)malloc(sizeof(zip_random_context_t)); if (!ctx) { return false; } mbedtls_entropy_init(&ctx->entropy); mbedtls_ctr_drbg_init(&ctx->ctr_drbg); if (mbedtls_ctr_drbg_seed(&ctx->ctr_drbg, mbedtls_entropy_func, &ctx->entropy, pers, strlen(pers)) != 0) { mbedtls_ctr_drbg_free(&ctx->ctr_drbg); mbedtls_entropy_free(&ctx->entropy); free(ctx); ctx = NULL; return false; } } return mbedtls_ctr_drbg_random(&ctx->ctr_drbg, (unsigned char *)buffer, (size_t)length) == 0; } ================================================ FILE: external/libzip/lib/zip_crypto_mbedtls.h ================================================ /* zip_crypto_mbedtls.h -- definitions for mbedtls wrapper Copyright (C) 2018-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef HAD_ZIP_CRYPTO_MBEDTLS_H #define HAD_ZIP_CRYPTO_MBEDTLS_H #define HAVE_SECURE_RANDOM #include #include #define _zip_crypto_aes_t mbedtls_aes_context #define _zip_crypto_hmac_t mbedtls_md_context_t _zip_crypto_aes_t *_zip_crypto_aes_new(const zip_uint8_t *key, zip_uint16_t key_size, zip_error_t *error); #define _zip_crypto_aes_encrypt_block(aes, in, out) (mbedtls_aes_crypt_ecb((aes), MBEDTLS_AES_ENCRYPT, (in), (out)) == 0) void _zip_crypto_aes_free(_zip_crypto_aes_t *aes); _zip_crypto_hmac_t *_zip_crypto_hmac_new(const zip_uint8_t *secret, zip_uint64_t secret_length, zip_error_t *error); #define _zip_crypto_hmac(hmac, data, length) (mbedtls_md_hmac_update((hmac), (data), (length)) == 0) #define _zip_crypto_hmac_output(hmac, data) (mbedtls_md_hmac_finish((hmac), (data)) == 0) void _zip_crypto_hmac_free(_zip_crypto_hmac_t *hmac); bool _zip_crypto_pbkdf2(const zip_uint8_t *key, zip_uint64_t key_length, const zip_uint8_t *salt, zip_uint16_t salt_length, int iterations, zip_uint8_t *output, zip_uint64_t output_length); #endif /* HAD_ZIP_CRYPTO_MBEDTLS_H */ ================================================ FILE: external/libzip/lib/zip_crypto_openssl.c ================================================ /* zip_crypto_openssl.c -- OpenSSL wrapper. Copyright (C) 2018-2023 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include "zipint.h" #include "zip_crypto.h" #include #include #ifdef USE_OPENSSL_3_API static _zip_crypto_hmac_t* hmac_new() { _zip_crypto_hmac_t *hmac = (_zip_crypto_hmac_t*)malloc(sizeof(*hmac)); if (hmac != NULL) { hmac->mac = NULL; hmac->ctx = NULL; } return hmac; } static void hmac_free(_zip_crypto_hmac_t* hmac) { if (hmac != NULL) { if (hmac->ctx != NULL) { EVP_MAC_CTX_free(hmac->ctx); } if (hmac->mac != NULL) { EVP_MAC_free(hmac->mac); } free(hmac); } } #endif _zip_crypto_aes_t * _zip_crypto_aes_new(const zip_uint8_t *key, zip_uint16_t key_size, zip_error_t *error) { _zip_crypto_aes_t *aes; const EVP_CIPHER* cipher_type; switch (key_size) { case 128: cipher_type = EVP_aes_128_ecb(); break; case 192: cipher_type = EVP_aes_192_ecb(); break; case 256: cipher_type = EVP_aes_256_ecb(); break; default: zip_error_set(error, ZIP_ER_INTERNAL, 0); return NULL; } #ifdef USE_OPENSSL_1_0_API if ((aes = (_zip_crypto_aes_t *)malloc(sizeof(*aes))) == NULL) { zip_error_set(error, ZIP_ER_MEMORY, 0); return NULL; } memset(aes, 0, sizeof(*aes)); #else if ((aes = EVP_CIPHER_CTX_new()) == NULL) { zip_error_set(error, ZIP_ER_MEMORY, 0); return NULL; } #endif if (EVP_EncryptInit_ex(aes, cipher_type, NULL, key, NULL) != 1) { #ifdef USE_OPENSSL_1_0_API free(aes); #else EVP_CIPHER_CTX_free(aes); #endif zip_error_set(error, ZIP_ER_INTERNAL, 0); return NULL; } return aes; } void _zip_crypto_aes_free(_zip_crypto_aes_t *aes) { if (aes == NULL) { return; } #ifdef USE_OPENSSL_1_0_API EVP_CIPHER_CTX_cleanup(aes); _zip_crypto_clear(aes, sizeof(*aes)); free(aes); #else EVP_CIPHER_CTX_free(aes); #endif } bool _zip_crypto_aes_encrypt_block(_zip_crypto_aes_t *aes, const zip_uint8_t *in, zip_uint8_t *out) { int len = 0; if (EVP_EncryptUpdate(aes, out, &len, in, ZIP_CRYPTO_AES_BLOCK_LENGTH) != 1 || len != ZIP_CRYPTO_AES_BLOCK_LENGTH) { return false; } return true; } _zip_crypto_hmac_t * _zip_crypto_hmac_new(const zip_uint8_t *secret, zip_uint64_t secret_length, zip_error_t *error) { _zip_crypto_hmac_t *hmac; if (secret_length > INT_MAX) { zip_error_set(error, ZIP_ER_INVAL, 0); return NULL; } #ifdef USE_OPENSSL_3_API if ((hmac = hmac_new()) == NULL || (hmac->mac = EVP_MAC_fetch(NULL, "HMAC", "provider=default")) == NULL || (hmac->ctx = EVP_MAC_CTX_new(hmac->mac)) == NULL) { hmac_free(hmac); zip_error_set(error, ZIP_ER_MEMORY, 0); return NULL; } { OSSL_PARAM params[2]; params[0] = OSSL_PARAM_construct_utf8_string("digest", "SHA1", 0); params[1] = OSSL_PARAM_construct_end(); if (!EVP_MAC_init(hmac->ctx, (const unsigned char *)secret, secret_length, params)) { zip_error_set(error, ZIP_ER_INTERNAL, 0); hmac_free(hmac); return NULL; } } #else #ifdef USE_OPENSSL_1_0_API if ((hmac = (_zip_crypto_hmac_t *)malloc(sizeof(*hmac))) == NULL) { zip_error_set(error, ZIP_ER_MEMORY, 0); return NULL; } HMAC_CTX_init(hmac); #else if ((hmac = HMAC_CTX_new()) == NULL) { zip_error_set(error, ZIP_ER_MEMORY, 0); return NULL; } #endif if (HMAC_Init_ex(hmac, secret, (int)secret_length, EVP_sha1(), NULL) != 1) { zip_error_set(error, ZIP_ER_INTERNAL, 0); #ifdef USE_OPENSSL_1_0_API free(hmac); #else HMAC_CTX_free(hmac); #endif return NULL; } #endif return hmac; } void _zip_crypto_hmac_free(_zip_crypto_hmac_t *hmac) { if (hmac == NULL) { return; } #if defined(USE_OPENSSL_3_API) hmac_free(hmac); #elif defined(USE_OPENSSL_1_0_API) HMAC_CTX_cleanup(hmac); _zip_crypto_clear(hmac, sizeof(*hmac)); free(hmac); #else HMAC_CTX_free(hmac); #endif } bool _zip_crypto_hmac_output(_zip_crypto_hmac_t *hmac, zip_uint8_t *data) { #ifdef USE_OPENSSL_3_API size_t length = 0; return EVP_MAC_final(hmac->ctx, data, &length, ZIP_CRYPTO_SHA1_LENGTH) == 1 && length == ZIP_CRYPTO_SHA1_LENGTH; #else unsigned int length = 0; return HMAC_Final(hmac, data, &length) == 1 && length == ZIP_CRYPTO_SHA1_LENGTH; #endif } ZIP_EXTERN bool zip_secure_random(zip_uint8_t *buffer, zip_uint16_t length) { return RAND_bytes(buffer, length) == 1; } ================================================ FILE: external/libzip/lib/zip_crypto_openssl.h ================================================ /* zip_crypto_openssl.h -- definitions for OpenSSL wrapper. Copyright (C) 2018-2023 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef HAD_ZIP_CRYPTO_OPENSSL_H #define HAD_ZIP_CRYPTO_OPENSSL_H #define HAVE_SECURE_RANDOM #include #include #if OPENSSL_VERSION_NUMBER < 0x1010000fL || (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x02070000fL) #define USE_OPENSSL_1_0_API #elif OPENSSL_VERSION_NUMBER < 0x3000000fL #define USE_OPENSSL_1_1_API #else #define USE_OPENSSL_3_API #endif #define _zip_crypto_aes_t EVP_CIPHER_CTX #ifdef USE_OPENSSL_3_API struct _zip_crypto_hmac_t { EVP_MAC *mac; EVP_MAC_CTX *ctx; }; typedef struct _zip_crypto_hmac_t _zip_crypto_hmac_t; #define _zip_crypto_hmac(hmac, data, length) (EVP_MAC_update((hmac->ctx), (data), (length)) == 1) #else #define _zip_crypto_hmac_t HMAC_CTX #define _zip_crypto_hmac(hmac, data, length) (HMAC_Update((hmac), (data), (length)) == 1) #endif void _zip_crypto_aes_free(_zip_crypto_aes_t *aes); bool _zip_crypto_aes_encrypt_block(_zip_crypto_aes_t *aes, const zip_uint8_t *in, zip_uint8_t *out); _zip_crypto_aes_t *_zip_crypto_aes_new(const zip_uint8_t *key, zip_uint16_t key_size, zip_error_t *error); void _zip_crypto_hmac_free(_zip_crypto_hmac_t *hmac); _zip_crypto_hmac_t *_zip_crypto_hmac_new(const zip_uint8_t *secret, zip_uint64_t secret_length, zip_error_t *error); bool _zip_crypto_hmac_output(_zip_crypto_hmac_t *hmac, zip_uint8_t *data); #define _zip_crypto_pbkdf2(key, key_length, salt, salt_length, iterations, output, output_length) (PKCS5_PBKDF2_HMAC_SHA1((const char *)(key), (key_length), (salt), (salt_length), (iterations), (output_length), (output))) #endif /* HAD_ZIP_CRYPTO_OPENSSL_H */ ================================================ FILE: external/libzip/lib/zip_crypto_win.c ================================================ /* zip_crypto_win.c -- Windows Crypto API wrapper. Copyright (C) 2018-2023 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include "zipint.h" #include "zip_crypto.h" #include #include #pragma comment(lib, "bcrypt.lib") /* This code is using the Cryptography API: Next Generation (CNG) https://docs.microsoft.com/en-us/windows/desktop/seccng/cng-portal This API is supported on - Windows Vista or later (client OS) - Windows Server 2008 (server OS) - Windows Embedded Compact 2013 (don't know about Windows Embedded Compact 7) The code was developed for Windows Embedded Compact 2013 (WEC2013), but should be working for all of the above mentioned OSes. There are 2 restrictions for WEC2013, Windows Vista and Windows Server 2008: 1.) The function "BCryptDeriveKeyPBKDF2" is not available I found some code which is implementing this function using the deprecated Crypto API here: https://www.idrix.fr/Root/content/view/37/54/ I took this code and converted it to the newer CNG API. The original code was more flexible, but this is not needed here so i refactored it a bit and just kept what is needed. The define "HAS_BCRYPTDERIVEKEYPBKDF2" controls whether "BCryptDeriveKeyPBKDF2" of the CNG API is used or not. This define must not be set if you are compiling for WEC2013 or Windows Vista. 2.) "BCryptCreateHash" can't manage the memory needed for the hash object internally On Windows 7 or later it is possible to pass NULL for the hash object buffer. This is not supported on WEC2013, so we have to handle the memory allocation/deallocation ourselves. There is no #ifdef to control that, because this is working for all supported OSes. */ #if !defined(WINCE) && !defined(__MINGW32__) #define HAS_BCRYPTDERIVEKEYPBKDF2 #endif #ifdef HAS_BCRYPTDERIVEKEYPBKDF2 bool _zip_crypto_pbkdf2(const zip_uint8_t *key, zip_uint64_t key_length, const zip_uint8_t *salt, zip_uint16_t salt_length, zip_uint16_t iterations, zip_uint8_t *output, zip_uint16_t output_length) { BCRYPT_ALG_HANDLE hAlgorithm = NULL; bool result; if (!BCRYPT_SUCCESS(BCryptOpenAlgorithmProvider(&hAlgorithm, BCRYPT_SHA1_ALGORITHM, NULL, BCRYPT_ALG_HANDLE_HMAC_FLAG))) { return false; } result = BCRYPT_SUCCESS(BCryptDeriveKeyPBKDF2(hAlgorithm, (PUCHAR)key, (ULONG)key_length, (PUCHAR)salt, salt_length, iterations, output, output_length, 0)); BCryptCloseAlgorithmProvider(hAlgorithm, 0); return result; } #else #include #define DIGEST_SIZE 20 #define BLOCK_SIZE 64 typedef struct { BCRYPT_ALG_HANDLE hAlgorithm; BCRYPT_HASH_HANDLE hInnerHash; BCRYPT_HASH_HANDLE hOuterHash; ULONG cbHashObject; PUCHAR pbInnerHash; PUCHAR pbOuterHash; } PRF_CTX; static void hmacFree(PRF_CTX *pContext) { if (pContext->hOuterHash) BCryptDestroyHash(pContext->hOuterHash); if (pContext->hInnerHash) BCryptDestroyHash(pContext->hInnerHash); free(pContext->pbOuterHash); free(pContext->pbInnerHash); if (pContext->hAlgorithm) BCryptCloseAlgorithmProvider(pContext->hAlgorithm, 0); } static BOOL hmacPrecomputeDigest(BCRYPT_HASH_HANDLE hHash, PUCHAR pbPassword, DWORD cbPassword, BYTE mask) { BYTE buffer[BLOCK_SIZE]; DWORD i; if (cbPassword > BLOCK_SIZE) { return FALSE; } memset(buffer, mask, sizeof(buffer)); for (i = 0; i < cbPassword; ++i) { buffer[i] = (char)(pbPassword[i] ^ mask); } return BCRYPT_SUCCESS(BCryptHashData(hHash, buffer, sizeof(buffer), 0)); } static BOOL hmacInit(PRF_CTX *pContext, PUCHAR pbPassword, DWORD cbPassword) { BOOL bStatus = FALSE; ULONG cbResult; BYTE key[DIGEST_SIZE]; if (!BCRYPT_SUCCESS(BCryptOpenAlgorithmProvider(&pContext->hAlgorithm, BCRYPT_SHA1_ALGORITHM, NULL, 0)) || !BCRYPT_SUCCESS(BCryptGetProperty(pContext->hAlgorithm, BCRYPT_OBJECT_LENGTH, (PUCHAR)&pContext->cbHashObject, sizeof(pContext->cbHashObject), &cbResult, 0)) || ((pContext->pbInnerHash = malloc(pContext->cbHashObject)) == NULL) || ((pContext->pbOuterHash = malloc(pContext->cbHashObject)) == NULL) || !BCRYPT_SUCCESS(BCryptCreateHash(pContext->hAlgorithm, &pContext->hInnerHash, pContext->pbInnerHash, pContext->cbHashObject, NULL, 0, 0)) || !BCRYPT_SUCCESS(BCryptCreateHash(pContext->hAlgorithm, &pContext->hOuterHash, pContext->pbOuterHash, pContext->cbHashObject, NULL, 0, 0))) { goto hmacInit_end; } if (cbPassword > BLOCK_SIZE) { BCRYPT_HASH_HANDLE hHash = NULL; PUCHAR pbHashObject = malloc(pContext->cbHashObject); if (pbHashObject == NULL) { goto hmacInit_end; } bStatus = BCRYPT_SUCCESS(BCryptCreateHash(pContext->hAlgorithm, &hHash, pbHashObject, pContext->cbHashObject, NULL, 0, 0)) && BCRYPT_SUCCESS(BCryptHashData(hHash, pbPassword, cbPassword, 0)) && BCRYPT_SUCCESS(BCryptGetProperty(hHash, BCRYPT_HASH_LENGTH, (PUCHAR)&cbPassword, sizeof(cbPassword), &cbResult, 0)) && BCRYPT_SUCCESS(BCryptFinishHash(hHash, key, cbPassword, 0)); if (hHash) BCryptDestroyHash(hHash); free(pbHashObject); if (!bStatus) { goto hmacInit_end; } pbPassword = key; } bStatus = hmacPrecomputeDigest(pContext->hInnerHash, pbPassword, cbPassword, 0x36) && hmacPrecomputeDigest(pContext->hOuterHash, pbPassword, cbPassword, 0x5C); hmacInit_end: if (bStatus == FALSE) hmacFree(pContext); return bStatus; } static BOOL hmacCalculateInternal(BCRYPT_HASH_HANDLE hHashTemplate, PUCHAR pbData, DWORD cbData, PUCHAR pbOutput, DWORD cbOutput, DWORD cbHashObject) { BOOL success = FALSE; BCRYPT_HASH_HANDLE hHash = NULL; PUCHAR pbHashObject = malloc(cbHashObject); if (pbHashObject == NULL) { return FALSE; } if (BCRYPT_SUCCESS(BCryptDuplicateHash(hHashTemplate, &hHash, pbHashObject, cbHashObject, 0))) { success = BCRYPT_SUCCESS(BCryptHashData(hHash, pbData, cbData, 0)) && BCRYPT_SUCCESS(BCryptFinishHash(hHash, pbOutput, cbOutput, 0)); BCryptDestroyHash(hHash); } free(pbHashObject); return success; } static BOOL hmacCalculate(PRF_CTX *pContext, PUCHAR pbData, DWORD cbData, PUCHAR pbDigest) { DWORD cbResult; DWORD cbHashObject; return BCRYPT_SUCCESS(BCryptGetProperty(pContext->hAlgorithm, BCRYPT_OBJECT_LENGTH, (PUCHAR)&cbHashObject, sizeof(cbHashObject), &cbResult, 0)) && hmacCalculateInternal(pContext->hInnerHash, pbData, cbData, pbDigest, DIGEST_SIZE, cbHashObject) && hmacCalculateInternal(pContext->hOuterHash, pbDigest, DIGEST_SIZE, pbDigest, DIGEST_SIZE, cbHashObject); } static void myxor(LPBYTE ptr1, LPBYTE ptr2, DWORD dwLen) { while (dwLen--) *ptr1++ ^= *ptr2++; } BOOL pbkdf2(PUCHAR pbPassword, ULONG cbPassword, PUCHAR pbSalt, ULONG cbSalt, DWORD cIterations, PUCHAR pbDerivedKey, ULONG cbDerivedKey) { BOOL bStatus = FALSE; DWORD l, r, dwULen, i, j; BYTE Ti[DIGEST_SIZE]; BYTE V[DIGEST_SIZE]; LPBYTE U = malloc(max((cbSalt + 4), DIGEST_SIZE)); PRF_CTX prfCtx = {0}; if (U == NULL) { return FALSE; } if (pbPassword == NULL || cbPassword == 0 || pbSalt == NULL || cbSalt == 0 || cIterations == 0 || pbDerivedKey == NULL || cbDerivedKey == 0) { free(U); return FALSE; } if (!hmacInit(&prfCtx, pbPassword, cbPassword)) { goto PBKDF2_end; } l = (DWORD)ceil((double)cbDerivedKey / (double)DIGEST_SIZE); r = cbDerivedKey - (l - 1) * DIGEST_SIZE; for (i = 1; i <= l; i++) { ZeroMemory(Ti, DIGEST_SIZE); for (j = 0; j < cIterations; j++) { if (j == 0) { /* construct first input for PRF */ (void)memcpy_s(U, cbSalt, pbSalt, cbSalt); U[cbSalt] = (BYTE)((i & 0xFF000000) >> 24); U[cbSalt + 1] = (BYTE)((i & 0x00FF0000) >> 16); U[cbSalt + 2] = (BYTE)((i & 0x0000FF00) >> 8); U[cbSalt + 3] = (BYTE)((i & 0x000000FF)); dwULen = cbSalt + 4; } else { (void)memcpy_s(U, DIGEST_SIZE, V, DIGEST_SIZE); dwULen = DIGEST_SIZE; } if (!hmacCalculate(&prfCtx, U, dwULen, V)) { goto PBKDF2_end; } myxor(Ti, V, DIGEST_SIZE); } if (i != l) { (void)memcpy_s(&pbDerivedKey[(i - 1) * DIGEST_SIZE], cbDerivedKey - (i - 1) * DIGEST_SIZE, Ti, DIGEST_SIZE); } else { /* Take only the first r bytes */ (void)memcpy_s(&pbDerivedKey[(i - 1) * DIGEST_SIZE], cbDerivedKey - (i - 1) * DIGEST_SIZE, Ti, r); } } bStatus = TRUE; PBKDF2_end: hmacFree(&prfCtx); free(U); return bStatus; } bool _zip_crypto_pbkdf2(const zip_uint8_t *key, zip_uint64_t key_length, const zip_uint8_t *salt, zip_uint16_t salt_length, zip_uint16_t iterations, zip_uint8_t *output, zip_uint16_t output_length) { return (key_length <= ZIP_UINT32_MAX) && pbkdf2((PUCHAR)key, (ULONG)key_length, (PUCHAR)salt, salt_length, iterations, output, output_length); } #endif struct _zip_crypto_aes_s { BCRYPT_ALG_HANDLE hAlgorithm; BCRYPT_KEY_HANDLE hKey; ULONG cbKeyObject; PUCHAR pbKeyObject; }; _zip_crypto_aes_t * _zip_crypto_aes_new(const zip_uint8_t *key, zip_uint16_t key_size, zip_error_t *error) { _zip_crypto_aes_t *aes = (_zip_crypto_aes_t *)calloc(1, sizeof(*aes)); ULONG cbResult; ULONG key_length = key_size / 8; if (aes == NULL) { zip_error_set(error, ZIP_ER_MEMORY, 0); return NULL; } if (!BCRYPT_SUCCESS(BCryptOpenAlgorithmProvider(&aes->hAlgorithm, BCRYPT_AES_ALGORITHM, NULL, 0))) { _zip_crypto_aes_free(aes); return NULL; } if (!BCRYPT_SUCCESS(BCryptSetProperty(aes->hAlgorithm, BCRYPT_CHAINING_MODE, (PUCHAR)BCRYPT_CHAIN_MODE_ECB, sizeof(BCRYPT_CHAIN_MODE_ECB), 0))) { _zip_crypto_aes_free(aes); return NULL; } if (!BCRYPT_SUCCESS(BCryptGetProperty(aes->hAlgorithm, BCRYPT_OBJECT_LENGTH, (PUCHAR)&aes->cbKeyObject, sizeof(aes->cbKeyObject), &cbResult, 0))) { _zip_crypto_aes_free(aes); return NULL; } aes->pbKeyObject = malloc(aes->cbKeyObject); if (aes->pbKeyObject == NULL) { _zip_crypto_aes_free(aes); zip_error_set(error, ZIP_ER_MEMORY, 0); return NULL; } if (!BCRYPT_SUCCESS(BCryptGenerateSymmetricKey(aes->hAlgorithm, &aes->hKey, aes->pbKeyObject, aes->cbKeyObject, (PUCHAR)key, key_length, 0))) { _zip_crypto_aes_free(aes); return NULL; } return aes; } void _zip_crypto_aes_free(_zip_crypto_aes_t *aes) { if (aes == NULL) { return; } if (aes->hKey != NULL) { BCryptDestroyKey(aes->hKey); } if (aes->pbKeyObject != NULL) { free(aes->pbKeyObject); } if (aes->hAlgorithm != NULL) { BCryptCloseAlgorithmProvider(aes->hAlgorithm, 0); } free(aes); } bool _zip_crypto_aes_encrypt_block(_zip_crypto_aes_t *aes, const zip_uint8_t *in, zip_uint8_t *out) { ULONG cbResult; NTSTATUS status = BCryptEncrypt(aes->hKey, (PUCHAR)in, ZIP_CRYPTO_AES_BLOCK_LENGTH, NULL, NULL, 0, (PUCHAR)out, ZIP_CRYPTO_AES_BLOCK_LENGTH, &cbResult, 0); return BCRYPT_SUCCESS(status); } struct _zip_crypto_hmac_s { BCRYPT_ALG_HANDLE hAlgorithm; BCRYPT_HASH_HANDLE hHash; DWORD cbHashObject; PUCHAR pbHashObject; DWORD cbHash; PUCHAR pbHash; }; /* https://code.msdn.microsoft.com/windowsdesktop/Hmac-Computation-Sample-11fe8ec1/sourcecode?fileId=42820&pathId=283874677 */ _zip_crypto_hmac_t * _zip_crypto_hmac_new(const zip_uint8_t *secret, zip_uint64_t secret_length, zip_error_t *error) { NTSTATUS status; ULONG cbResult; _zip_crypto_hmac_t *hmac; if (secret_length > INT_MAX) { zip_error_set(error, ZIP_ER_INVAL, 0); return NULL; } hmac = (_zip_crypto_hmac_t *)calloc(1, sizeof(*hmac)); if (hmac == NULL) { zip_error_set(error, ZIP_ER_MEMORY, 0); return NULL; } status = BCryptOpenAlgorithmProvider(&hmac->hAlgorithm, BCRYPT_SHA1_ALGORITHM, NULL, BCRYPT_ALG_HANDLE_HMAC_FLAG); if (!BCRYPT_SUCCESS(status)) { _zip_crypto_hmac_free(hmac); return NULL; } status = BCryptGetProperty(hmac->hAlgorithm, BCRYPT_OBJECT_LENGTH, (PUCHAR)&hmac->cbHashObject, sizeof(hmac->cbHashObject), &cbResult, 0); if (!BCRYPT_SUCCESS(status)) { _zip_crypto_hmac_free(hmac); return NULL; } hmac->pbHashObject = malloc(hmac->cbHashObject); if (hmac->pbHashObject == NULL) { _zip_crypto_hmac_free(hmac); zip_error_set(error, ZIP_ER_MEMORY, 0); return NULL; } status = BCryptGetProperty(hmac->hAlgorithm, BCRYPT_HASH_LENGTH, (PUCHAR)&hmac->cbHash, sizeof(hmac->cbHash), &cbResult, 0); if (!BCRYPT_SUCCESS(status)) { _zip_crypto_hmac_free(hmac); return NULL; } hmac->pbHash = malloc(hmac->cbHash); if (hmac->pbHash == NULL) { _zip_crypto_hmac_free(hmac); zip_error_set(error, ZIP_ER_MEMORY, 0); return NULL; } status = BCryptCreateHash(hmac->hAlgorithm, &hmac->hHash, hmac->pbHashObject, hmac->cbHashObject, (PUCHAR)secret, (ULONG)secret_length, 0); if (!BCRYPT_SUCCESS(status)) { _zip_crypto_hmac_free(hmac); return NULL; } return hmac; } void _zip_crypto_hmac_free(_zip_crypto_hmac_t *hmac) { if (hmac == NULL) { return; } if (hmac->hHash != NULL) { BCryptDestroyHash(hmac->hHash); } if (hmac->pbHash != NULL) { free(hmac->pbHash); } if (hmac->pbHashObject != NULL) { free(hmac->pbHashObject); } if (hmac->hAlgorithm) { BCryptCloseAlgorithmProvider(hmac->hAlgorithm, 0); } free(hmac); } bool _zip_crypto_hmac(_zip_crypto_hmac_t *hmac, zip_uint8_t *data, zip_uint64_t length) { if (hmac == NULL || length > ULONG_MAX) { return false; } return BCRYPT_SUCCESS(BCryptHashData(hmac->hHash, data, (ULONG)length, 0)); } bool _zip_crypto_hmac_output(_zip_crypto_hmac_t *hmac, zip_uint8_t *data) { if (hmac == NULL) { return false; } return BCRYPT_SUCCESS(BCryptFinishHash(hmac->hHash, data, hmac->cbHash, 0)); } ZIP_EXTERN bool zip_secure_random(zip_uint8_t *buffer, zip_uint16_t length) { return BCRYPT_SUCCESS(BCryptGenRandom(NULL, buffer, length, BCRYPT_USE_SYSTEM_PREFERRED_RNG)); } ================================================ FILE: external/libzip/lib/zip_crypto_win.h ================================================ /* zip_crypto_win.h -- Windows Crypto API wrapper. Copyright (C) 2018-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef HAD_ZIP_CRYPTO_WIN_H #define HAD_ZIP_CRYPTO_WIN_H #define HAVE_SECURE_RANDOM typedef struct _zip_crypto_aes_s _zip_crypto_aes_t; typedef struct _zip_crypto_hmac_s _zip_crypto_hmac_t; void _zip_crypto_aes_free(_zip_crypto_aes_t *aes); _zip_crypto_aes_t *_zip_crypto_aes_new(const zip_uint8_t *key, zip_uint16_t key_size, zip_error_t *error); bool _zip_crypto_aes_encrypt_block(_zip_crypto_aes_t *aes, const zip_uint8_t *in, zip_uint8_t *out); bool _zip_crypto_pbkdf2(const zip_uint8_t *key, zip_uint64_t key_length, const zip_uint8_t *salt, zip_uint16_t salt_length, zip_uint16_t iterations, zip_uint8_t *output, zip_uint16_t output_length); _zip_crypto_hmac_t *_zip_crypto_hmac_new(const zip_uint8_t *secret, zip_uint64_t secret_length, zip_error_t *error); void _zip_crypto_hmac_free(_zip_crypto_hmac_t *hmac); bool _zip_crypto_hmac(_zip_crypto_hmac_t *hmac, zip_uint8_t *data, zip_uint64_t length); bool _zip_crypto_hmac_output(_zip_crypto_hmac_t *hmac, zip_uint8_t *data); #endif /* HAD_ZIP_CRYPTO_WIN_H */ ================================================ FILE: external/libzip/lib/zip_delete.c ================================================ /* zip_delete.c -- delete file from zip archive Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "zipint.h" ZIP_EXTERN int zip_delete(zip_t *za, zip_uint64_t idx) { const char *name; if (idx >= za->nentry) { zip_error_set(&za->error, ZIP_ER_INVAL, 0); return -1; } if (ZIP_IS_RDONLY(za)) { zip_error_set(&za->error, ZIP_ER_RDONLY, 0); return -1; } if ((name = _zip_get_name(za, idx, 0, &za->error)) == NULL) { return -1; } if (!_zip_hash_delete(za->names, (const zip_uint8_t *)name, &za->error)) { return -1; } /* allow duplicate file names, because the file will * be removed directly afterwards */ if (_zip_unchange(za, idx, 1) != 0) return -1; za->entry[idx].deleted = 1; return 0; } ================================================ FILE: external/libzip/lib/zip_dir_add.c ================================================ /* zip_dir_add.c -- add directory Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include "zipint.h" /* NOTE: Signed due to -1 on error. See zip_add.c for more details. */ ZIP_EXTERN zip_int64_t zip_dir_add(zip_t *za, const char *name, zip_flags_t flags) { size_t len; zip_int64_t idx; char *s; zip_source_t *source; if (ZIP_IS_RDONLY(za)) { zip_error_set(&za->error, ZIP_ER_RDONLY, 0); return -1; } if (name == NULL) { zip_error_set(&za->error, ZIP_ER_INVAL, 0); return -1; } s = NULL; len = strlen(name); if (name[len - 1] != '/') { if (len > SIZE_MAX - 2 || (s = (char *)malloc(len + 2)) == NULL) { zip_error_set(&za->error, ZIP_ER_MEMORY, 0); return -1; } (void)strncpy_s(s, len + 2, name, len); s[len] = '/'; s[len + 1] = '\0'; } if ((source = zip_source_buffer(za, NULL, 0, 0)) == NULL) { free(s); return -1; } idx = _zip_file_replace(za, ZIP_UINT64_MAX, s ? s : name, source, flags); free(s); if (idx < 0) zip_source_free(source); else { if (zip_file_set_external_attributes(za, (zip_uint64_t)idx, 0, ZIP_OPSYS_DEFAULT, ZIP_EXT_ATTRIB_DEFAULT_DIR) < 0) { zip_delete(za, (zip_uint64_t)idx); return -1; } } return idx; } ================================================ FILE: external/libzip/lib/zip_dirent.c ================================================ /* zip_dirent.c -- read directory entry (local or central), clean dirent Copyright (C) 1999-2024 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include "zipint.h" static zip_string_t *_zip_dirent_process_ef_utf_8(const zip_dirent_t *de, zip_uint16_t id, zip_string_t *str, bool check_consistency); static zip_extra_field_t *_zip_ef_utf8(zip_uint16_t, zip_string_t *, zip_error_t *); static bool _zip_dirent_process_winzip_aes(zip_dirent_t *de, zip_error_t *error); void _zip_cdir_free(zip_cdir_t *cd) { zip_uint64_t i; if (cd == NULL) { return; } for (i = 0; i < cd->nentry; i++) _zip_entry_finalize(cd->entry + i); free(cd->entry); _zip_string_free(cd->comment); free(cd); } zip_cdir_t * _zip_cdir_new(zip_error_t *error) { zip_cdir_t *cd; if ((cd = (zip_cdir_t *)malloc(sizeof(*cd))) == NULL) { zip_error_set(error, ZIP_ER_MEMORY, 0); return NULL; } cd->entry = NULL; cd->nentry = cd->nentry_alloc = 0; cd->size = cd->offset = 0; cd->comment = NULL; cd->is_zip64 = false; return cd; } bool _zip_cdir_grow(zip_cdir_t *cd, zip_uint64_t additional_entries, zip_error_t *error) { zip_uint64_t i; if (additional_entries == 0) { return true; } if (!ZIP_REALLOC(cd->entry, cd->nentry_alloc, additional_entries, error)) { return false; } for (i = cd->nentry; i < cd->nentry_alloc; i++) { _zip_entry_init(cd->entry + i); } cd->nentry = cd->nentry_alloc; return true; } zip_int64_t _zip_cdir_write(zip_t *za, const zip_filelist_t *filelist, zip_uint64_t survivors) { zip_uint64_t offset, size; zip_string_t *comment; zip_uint8_t buf[EOCDLEN + EOCD64LEN + EOCD64LOCLEN]; zip_buffer_t *buffer; zip_int64_t off; zip_uint64_t i; zip_uint32_t cdir_crc; if ((off = zip_source_tell_write(za->src)) < 0) { zip_error_set_from_source(&za->error, za->src); return -1; } offset = (zip_uint64_t)off; if (ZIP_WANT_TORRENTZIP(za)) { cdir_crc = (zip_uint32_t)crc32(0, NULL, 0); za->write_crc = &cdir_crc; } for (i = 0; i < survivors; i++) { zip_entry_t *entry = za->entry + filelist[i].idx; if (_zip_dirent_write(za, entry->changes ? entry->changes : entry->orig, ZIP_FL_CENTRAL) < 0) { za->write_crc = NULL; return -1; } } za->write_crc = NULL; if ((off = zip_source_tell_write(za->src)) < 0) { zip_error_set_from_source(&za->error, za->src); return -1; } size = (zip_uint64_t)off - offset; if ((buffer = _zip_buffer_new(buf, sizeof(buf))) == NULL) { zip_error_set(&za->error, ZIP_ER_MEMORY, 0); return -1; } if (survivors > ZIP_UINT16_MAX || offset > ZIP_UINT32_MAX || size > ZIP_UINT32_MAX) { _zip_buffer_put(buffer, EOCD64_MAGIC, 4); _zip_buffer_put_64(buffer, EOCD64LEN - 12); _zip_buffer_put_16(buffer, 45); _zip_buffer_put_16(buffer, 45); _zip_buffer_put_32(buffer, 0); _zip_buffer_put_32(buffer, 0); _zip_buffer_put_64(buffer, survivors); _zip_buffer_put_64(buffer, survivors); _zip_buffer_put_64(buffer, size); _zip_buffer_put_64(buffer, offset); _zip_buffer_put(buffer, EOCD64LOC_MAGIC, 4); _zip_buffer_put_32(buffer, 0); _zip_buffer_put_64(buffer, offset + size); _zip_buffer_put_32(buffer, 1); } _zip_buffer_put(buffer, EOCD_MAGIC, 4); _zip_buffer_put_32(buffer, 0); _zip_buffer_put_16(buffer, (zip_uint16_t)(survivors >= ZIP_UINT16_MAX ? ZIP_UINT16_MAX : survivors)); _zip_buffer_put_16(buffer, (zip_uint16_t)(survivors >= ZIP_UINT16_MAX ? ZIP_UINT16_MAX : survivors)); _zip_buffer_put_32(buffer, size >= ZIP_UINT32_MAX ? ZIP_UINT32_MAX : (zip_uint32_t)size); _zip_buffer_put_32(buffer, offset >= ZIP_UINT32_MAX ? ZIP_UINT32_MAX : (zip_uint32_t)offset); comment = za->comment_changed ? za->comment_changes : za->comment_orig; if (ZIP_WANT_TORRENTZIP(za)) { _zip_buffer_put_16(buffer, TORRENTZIP_SIGNATURE_LENGTH + TORRENTZIP_CRC_LENGTH); } else { _zip_buffer_put_16(buffer, (zip_uint16_t)(comment ? comment->length : 0)); } if (!_zip_buffer_ok(buffer)) { zip_error_set(&za->error, ZIP_ER_INTERNAL, 0); _zip_buffer_free(buffer); return -1; } if (_zip_write(za, _zip_buffer_data(buffer), _zip_buffer_offset(buffer)) < 0) { _zip_buffer_free(buffer); return -1; } _zip_buffer_free(buffer); if (ZIP_WANT_TORRENTZIP(za)) { char torrentzip_comment[TORRENTZIP_SIGNATURE_LENGTH + TORRENTZIP_CRC_LENGTH + 1]; snprintf(torrentzip_comment, sizeof(torrentzip_comment), TORRENTZIP_SIGNATURE "%08X", cdir_crc); if (_zip_write(za, torrentzip_comment, strlen(torrentzip_comment)) < 0) { return -1; } } else if (comment != NULL) { if (_zip_write(za, comment->raw, comment->length) < 0) { return -1; } } return (zip_int64_t)size; } zip_dirent_t * _zip_dirent_clone(const zip_dirent_t *sde) { zip_dirent_t *tde; if ((tde = (zip_dirent_t *)malloc(sizeof(*tde))) == NULL) return NULL; if (sde) (void)memcpy_s(tde, sizeof(*tde), sde, sizeof(*sde)); else _zip_dirent_init(tde); tde->changed = 0; tde->cloned = 1; return tde; } void _zip_dirent_finalize(zip_dirent_t *zde) { if (!zde->cloned || zde->changed & ZIP_DIRENT_FILENAME) { _zip_string_free(zde->filename); zde->filename = NULL; } if (!zde->cloned || zde->changed & ZIP_DIRENT_EXTRA_FIELD) { _zip_ef_free(zde->extra_fields); zde->extra_fields = NULL; } if (!zde->cloned || zde->changed & ZIP_DIRENT_COMMENT) { _zip_string_free(zde->comment); zde->comment = NULL; } if (!zde->cloned || zde->changed & ZIP_DIRENT_PASSWORD) { if (zde->password) { _zip_crypto_clear(zde->password, strlen(zde->password)); } free(zde->password); zde->password = NULL; } } void _zip_dirent_free(zip_dirent_t *zde) { if (zde == NULL) return; _zip_dirent_finalize(zde); free(zde); } bool _zip_dirent_merge(zip_dirent_t *de, zip_dirent_t *de_orig, bool replacing_data, zip_error_t *error) { if (!de->cloned) { zip_error_set(error, ZIP_ER_INTERNAL, 0); return false; } if (!(de->changed & ZIP_DIRENT_ATTRIBUTES)) { de->ext_attrib = de_orig->ext_attrib; de->int_attrib = de_orig->int_attrib; } if (!(de->changed & ZIP_DIRENT_COMMENT)) { de->comment = de_orig->comment; } if (!(de->changed & ZIP_DIRENT_COMP_METHOD)) { if (replacing_data) { de->comp_method = ZIP_CM_DEFAULT; de->compression_level = 0; } else { de->comp_method = de_orig->comp_method; de->compression_level = de_orig->compression_level; } } if (!(de->changed & ZIP_DIRENT_ENCRYPTION_METHOD)) { if (replacing_data) { de->encryption_method = ZIP_EM_NONE; } else { de->encryption_method = de_orig->encryption_method; } } if (!(de->changed & ZIP_DIRENT_EXTRA_FIELD)) { de->extra_fields = de_orig->extra_fields; } if (!(de->changed & ZIP_DIRENT_FILENAME)) { de->filename = de_orig->filename; } if (!(de->changed & ZIP_DIRENT_LAST_MOD)) { de->last_mod = de_orig->last_mod; } if (!(de->changed & ZIP_DIRENT_PASSWORD)) { de->password = de_orig->password; } return true; } void _zip_dirent_init(zip_dirent_t *de) { de->changed = 0; de->local_extra_fields_read = 0; de->cloned = 0; de->crc_valid = true; de->last_mod_mtime_valid = false; de->version_madeby = 63 | (ZIP_OPSYS_DEFAULT << 8); de->version_needed = 10; /* 1.0 */ de->bitflags = 0; de->comp_method = ZIP_CM_DEFAULT; de->last_mod.date = 0; de->last_mod.time = 0; de->crc = 0; de->comp_size = 0; de->uncomp_size = 0; de->filename = NULL; de->extra_fields = NULL; de->comment = NULL; de->disk_number = 0; de->int_attrib = 0; de->ext_attrib = ZIP_EXT_ATTRIB_DEFAULT; de->offset = 0; de->compression_level = 0; de->encryption_method = ZIP_EM_NONE; de->password = NULL; } bool _zip_dirent_needs_zip64(const zip_dirent_t *de, zip_flags_t flags) { if (de->uncomp_size >= ZIP_UINT32_MAX || de->comp_size >= ZIP_UINT32_MAX || ((flags & ZIP_FL_CENTRAL) && de->offset >= ZIP_UINT32_MAX)) return true; return false; } zip_dirent_t * _zip_dirent_new(void) { zip_dirent_t *de; if ((de = (zip_dirent_t *)malloc(sizeof(*de))) == NULL) return NULL; _zip_dirent_init(de); return de; } /* Fills the zip directory entry zde. If buffer is non-NULL, data is taken from there; otherwise data is read from fp as needed. If local is true, it reads a local header instead of a central directory entry. Returns size of dirent read if successful. On error, error is filled in and -1 is returned. */ zip_int64_t _zip_dirent_read(zip_dirent_t *zde, zip_source_t *src, zip_buffer_t *buffer, bool local, zip_uint64_t central_compressed_size, bool check_consistency, zip_error_t *error) { zip_uint8_t buf[CDENTRYSIZE]; zip_uint32_t size, variable_size; zip_uint16_t filename_len, comment_len, ef_len; zip_string_t *utf8_string; bool is_zip64 = false; bool from_buffer = (buffer != NULL); size = local ? LENTRYSIZE : CDENTRYSIZE; if (buffer) { if (_zip_buffer_left(buffer) < size) { zip_error_set(error, ZIP_ER_NOZIP, 0); return -1; } } else { if ((buffer = _zip_buffer_new_from_source(src, size, buf, error)) == NULL) { return -1; } } if (memcmp(_zip_buffer_get(buffer, 4), (local ? LOCAL_MAGIC : CENTRAL_MAGIC), 4) != 0) { zip_error_set(error, ZIP_ER_NOZIP, 0); if (!from_buffer) { _zip_buffer_free(buffer); } return -1; } /* convert buffercontents to zip_dirent */ _zip_dirent_init(zde); if (!local) zde->version_madeby = _zip_buffer_get_16(buffer); else zde->version_madeby = 0; zde->version_needed = _zip_buffer_get_16(buffer); zde->bitflags = _zip_buffer_get_16(buffer); zde->comp_method = _zip_buffer_get_16(buffer); /* convert to time_t */ zde->last_mod.time = _zip_buffer_get_16(buffer); zde->last_mod.date = _zip_buffer_get_16(buffer); zde->crc = _zip_buffer_get_32(buffer); zde->comp_size = _zip_buffer_get_32(buffer); zde->uncomp_size = _zip_buffer_get_32(buffer); filename_len = _zip_buffer_get_16(buffer); ef_len = _zip_buffer_get_16(buffer); if (local) { comment_len = 0; zde->disk_number = 0; zde->int_attrib = 0; zde->ext_attrib = 0; zde->offset = 0; } else { comment_len = _zip_buffer_get_16(buffer); zde->disk_number = _zip_buffer_get_16(buffer); zde->int_attrib = _zip_buffer_get_16(buffer); zde->ext_attrib = _zip_buffer_get_32(buffer); zde->offset = _zip_buffer_get_32(buffer); } if (!_zip_buffer_ok(buffer)) { zip_error_set(error, ZIP_ER_INTERNAL, 0); if (!from_buffer) { _zip_buffer_free(buffer); } return -1; } if (zde->bitflags & ZIP_GPBF_ENCRYPTED) { if (zde->bitflags & ZIP_GPBF_STRONG_ENCRYPTION) { /* TODO */ zde->encryption_method = ZIP_EM_UNKNOWN; } else { zde->encryption_method = ZIP_EM_TRAD_PKWARE; } } else { zde->encryption_method = ZIP_EM_NONE; } zde->filename = NULL; zde->extra_fields = NULL; zde->comment = NULL; variable_size = (zip_uint32_t)filename_len + (zip_uint32_t)ef_len + (zip_uint32_t)comment_len; if (from_buffer) { if (_zip_buffer_left(buffer) < variable_size) { zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_VARIABLE_SIZE_OVERFLOW); return -1; } } else { _zip_buffer_free(buffer); if ((buffer = _zip_buffer_new_from_source(src, variable_size, NULL, error)) == NULL) { return -1; } } if (filename_len) { zde->filename = _zip_read_string(buffer, src, filename_len, 1, error); if (zde->filename == NULL) { if (zip_error_code_zip(error) == ZIP_ER_EOF) { zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_VARIABLE_SIZE_OVERFLOW); } if (!from_buffer) { _zip_buffer_free(buffer); } return -1; } if (zde->bitflags & ZIP_GPBF_ENCODING_UTF_8) { if (_zip_guess_encoding(zde->filename, ZIP_ENCODING_UTF8_KNOWN) == ZIP_ENCODING_ERROR) { zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_INVALID_UTF8_IN_FILENAME); if (!from_buffer) { _zip_buffer_free(buffer); } return -1; } } } if (ef_len) { zip_uint8_t *ef = _zip_read_data(buffer, src, ef_len, 0, error); if (ef == NULL) { if (!from_buffer) { _zip_buffer_free(buffer); } return -1; } if (!_zip_ef_parse(ef, ef_len, local ? ZIP_EF_LOCAL : ZIP_EF_CENTRAL, &zde->extra_fields, error)) { free(ef); if (!from_buffer) { _zip_buffer_free(buffer); } return -1; } free(ef); if (local) zde->local_extra_fields_read = 1; } if (comment_len) { zde->comment = _zip_read_string(buffer, src, comment_len, 0, error); if (zde->comment == NULL) { if (!from_buffer) { _zip_buffer_free(buffer); } return -1; } if (zde->bitflags & ZIP_GPBF_ENCODING_UTF_8) { if (_zip_guess_encoding(zde->comment, ZIP_ENCODING_UTF8_KNOWN) == ZIP_ENCODING_ERROR) { zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_INVALID_UTF8_IN_COMMENT); if (!from_buffer) { _zip_buffer_free(buffer); } return -1; } } } if ((utf8_string = _zip_dirent_process_ef_utf_8(zde, ZIP_EF_UTF_8_NAME, zde->filename, check_consistency)) == NULL && zde->filename != NULL) { zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_UTF8_FILENAME_MISMATCH); if (!from_buffer) { _zip_buffer_free(buffer); } return -1; } zde->filename = utf8_string; if (!local) { if ((utf8_string = _zip_dirent_process_ef_utf_8(zde, ZIP_EF_UTF_8_COMMENT, zde->comment, check_consistency)) == NULL && zde->comment != NULL) { zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_UTF8_COMMENT_MISMATCH); if (!from_buffer) { _zip_buffer_free(buffer); } return -1; } zde->comment = utf8_string; } /* Zip64 */ if (zde->uncomp_size == ZIP_UINT32_MAX || zde->comp_size == ZIP_UINT32_MAX || zde->offset == ZIP_UINT32_MAX) { zip_uint16_t got_len; const zip_uint8_t *ef = _zip_ef_get_by_id(zde->extra_fields, &got_len, ZIP_EF_ZIP64, 0, local ? ZIP_EF_LOCAL : ZIP_EF_CENTRAL, error); if (ef != NULL) { if (!zip_dirent_process_ef_zip64(zde, ef, got_len, local, error)) { if (!from_buffer) { _zip_buffer_free(buffer); } return -1; } } is_zip64 = true; } if (!_zip_buffer_ok(buffer)) { zip_error_set(error, ZIP_ER_INTERNAL, 0); if (!from_buffer) { _zip_buffer_free(buffer); } return -1; } if (!from_buffer) { _zip_buffer_free(buffer); } if (local && zde->bitflags & ZIP_GPBF_DATA_DESCRIPTOR) { zip_uint32_t df_crc; zip_uint64_t df_comp_size, df_uncomp_size; if (zip_source_seek(src, central_compressed_size, SEEK_CUR) != 0 || (buffer = _zip_buffer_new_from_source(src, MAX_DATA_DESCRIPTOR_LENGTH, buf, error)) == NULL) { return -1; } if (memcmp(_zip_buffer_peek(buffer, MAGIC_LEN), DATADES_MAGIC, MAGIC_LEN) == 0) { _zip_buffer_skip(buffer, MAGIC_LEN); } df_crc = _zip_buffer_get_32(buffer); df_comp_size = is_zip64 ? _zip_buffer_get_64(buffer) : _zip_buffer_get_32(buffer); df_uncomp_size = is_zip64 ? _zip_buffer_get_64(buffer) : _zip_buffer_get_32(buffer); if (!_zip_buffer_ok(buffer)) { zip_error_set(error, ZIP_ER_INTERNAL, 0); _zip_buffer_free(buffer); return -1; } _zip_buffer_free(buffer); if ((zde->crc != 0 && zde->crc != df_crc) || (zde->comp_size != 0 && zde->comp_size != df_comp_size) || (zde->uncomp_size != 0 && zde->uncomp_size != df_uncomp_size)) { zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_DATA_DESCRIPTOR_MISMATCH); return -1; } zde->crc = df_crc; zde->comp_size = df_comp_size; zde->uncomp_size = df_uncomp_size; } /* zip_source_seek / zip_source_tell don't support values > ZIP_INT64_MAX */ if (zde->offset > ZIP_INT64_MAX) { zip_error_set(error, ZIP_ER_SEEK, EFBIG); return -1; } if (!_zip_dirent_process_winzip_aes(zde, error)) { return -1; } zde->extra_fields = _zip_ef_remove_internal(zde->extra_fields); return (zip_int64_t)size + (zip_int64_t)variable_size; } bool zip_dirent_process_ef_zip64(zip_dirent_t *zde, const zip_uint8_t *ef, zip_uint64_t got_len, bool local, zip_error_t *error) { zip_buffer_t *ef_buffer; if ((ef_buffer = _zip_buffer_new((zip_uint8_t *)ef, got_len)) == NULL) { zip_error_set(error, ZIP_ER_MEMORY, 0); return false; } if (zde->uncomp_size == ZIP_UINT32_MAX) { zde->uncomp_size = _zip_buffer_get_64(ef_buffer); } else if (local) { /* From appnote.txt: This entry in the Local header MUST include BOTH original and compressed file size fields. */ (void)_zip_buffer_skip(ef_buffer, 8); /* error is caught by _zip_buffer_eof() call */ } if (zde->comp_size == ZIP_UINT32_MAX) { zde->comp_size = _zip_buffer_get_64(ef_buffer); } if (!local) { if (zde->offset == ZIP_UINT32_MAX) { zde->offset = _zip_buffer_get_64(ef_buffer); } if (zde->disk_number == ZIP_UINT16_MAX) { zde->disk_number = _zip_buffer_get_32(ef_buffer); } } if (!_zip_buffer_eof(ef_buffer)) { /* accept additional fields if values match */ bool ok = true; switch (got_len) { case 28: _zip_buffer_set_offset(ef_buffer, 24); if (zde->disk_number != _zip_buffer_get_32(ef_buffer)) { ok = false; } /* fallthrough */ case 24: _zip_buffer_set_offset(ef_buffer, 0); if ((zde->uncomp_size != _zip_buffer_get_64(ef_buffer)) || (zde->comp_size != _zip_buffer_get_64(ef_buffer)) || (zde->offset != _zip_buffer_get_64(ef_buffer))) { ok = false; } break; default: ok = false; } if (!ok) { zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_INVALID_ZIP64_EF); _zip_buffer_free(ef_buffer); return false; } } _zip_buffer_free(ef_buffer); return true; } static zip_string_t * _zip_dirent_process_ef_utf_8(const zip_dirent_t *de, zip_uint16_t id, zip_string_t *str, bool check_consistency) { zip_uint16_t ef_len; zip_uint32_t ef_crc; zip_buffer_t *buffer; const zip_uint8_t *ef = _zip_ef_get_by_id(de->extra_fields, &ef_len, id, 0, ZIP_EF_BOTH, NULL); if (ef == NULL || ef_len < 5 || ef[0] != 1) { return str; } if ((buffer = _zip_buffer_new((zip_uint8_t *)ef, ef_len)) == NULL) { return str; } _zip_buffer_get_8(buffer); ef_crc = _zip_buffer_get_32(buffer); if (_zip_string_crc32(str) == ef_crc) { zip_uint16_t len = (zip_uint16_t)_zip_buffer_left(buffer); zip_string_t *ef_str = _zip_string_new(_zip_buffer_get(buffer, len), len, ZIP_FL_ENC_UTF_8, NULL); if (ef_str != NULL) { if (check_consistency) { if (!_zip_string_equal(str, ef_str) && _zip_string_is_ascii(ef_str)) { _zip_string_free(ef_str); _zip_buffer_free(buffer); return NULL; } } _zip_string_free(str); str = ef_str; } } _zip_buffer_free(buffer); return str; } static bool _zip_dirent_process_winzip_aes(zip_dirent_t *de, zip_error_t *error) { zip_uint16_t ef_len; zip_buffer_t *buffer; const zip_uint8_t *ef; bool crc_valid; zip_uint16_t enc_method; if (de->comp_method != ZIP_CM_WINZIP_AES) { return true; } ef = _zip_ef_get_by_id(de->extra_fields, &ef_len, ZIP_EF_WINZIP_AES, 0, ZIP_EF_BOTH, NULL); if (ef == NULL || ef_len < 7) { zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_INVALID_WINZIPAES_EF); return false; } if ((buffer = _zip_buffer_new((zip_uint8_t *)ef, ef_len)) == NULL) { zip_error_set(error, ZIP_ER_INTERNAL, 0); return false; } /* version */ crc_valid = true; switch (_zip_buffer_get_16(buffer)) { case 1: break; case 2: crc_valid = false; /* TODO: When checking consistency, check that crc is 0. */ break; default: zip_error_set(error, ZIP_ER_ENCRNOTSUPP, 0); _zip_buffer_free(buffer); return false; } /* vendor */ if (memcmp(_zip_buffer_get(buffer, 2), "AE", 2) != 0) { zip_error_set(error, ZIP_ER_ENCRNOTSUPP, 0); _zip_buffer_free(buffer); return false; } /* mode */ switch (_zip_buffer_get_8(buffer)) { case 1: enc_method = ZIP_EM_AES_128; break; case 2: enc_method = ZIP_EM_AES_192; break; case 3: enc_method = ZIP_EM_AES_256; break; default: zip_error_set(error, ZIP_ER_ENCRNOTSUPP, 0); _zip_buffer_free(buffer); return false; } if (ef_len != 7) { zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_INVALID_WINZIPAES_EF); _zip_buffer_free(buffer); return false; } de->crc_valid = crc_valid; de->encryption_method = enc_method; de->comp_method = _zip_buffer_get_16(buffer); _zip_buffer_free(buffer); return true; } zip_int32_t _zip_dirent_size(zip_source_t *src, zip_uint16_t flags, zip_error_t *error) { zip_int32_t size; bool local = (flags & ZIP_EF_LOCAL) != 0; int i; zip_uint8_t b[6]; zip_buffer_t *buffer; size = local ? LENTRYSIZE : CDENTRYSIZE; if (zip_source_seek(src, local ? 26 : 28, SEEK_CUR) < 0) { zip_error_set_from_source(error, src); return -1; } if ((buffer = _zip_buffer_new_from_source(src, local ? 4 : 6, b, error)) == NULL) { return -1; } for (i = 0; i < (local ? 2 : 3); i++) { size += _zip_buffer_get_16(buffer); } if (!_zip_buffer_eof(buffer)) { zip_error_set(error, ZIP_ER_INTERNAL, 0); _zip_buffer_free(buffer); return -1; } _zip_buffer_free(buffer); return size; } /* _zip_dirent_write Writes zip directory entry. If flags & ZIP_EF_LOCAL, it writes a local header instead of a central directory entry. If flags & ZIP_EF_FORCE_ZIP64, a ZIP64 extra field is written, even if not needed. Returns 0 if successful, 1 if successful and wrote ZIP64 extra field. On error, error is filled in and -1 is returned. */ int _zip_dirent_write(zip_t *za, zip_dirent_t *de, zip_flags_t flags) { zip_dostime_t dostime; zip_encoding_type_t com_enc, name_enc; zip_extra_field_t *ef; zip_extra_field_t *ef64; zip_uint32_t ef_total_size; bool is_zip64; bool is_really_zip64; bool is_winzip_aes; zip_uint8_t buf[CDENTRYSIZE]; zip_buffer_t *buffer; ef = NULL; name_enc = _zip_guess_encoding(de->filename, ZIP_ENCODING_UNKNOWN); com_enc = _zip_guess_encoding(de->comment, ZIP_ENCODING_UNKNOWN); if ((name_enc == ZIP_ENCODING_UTF8_KNOWN && com_enc == ZIP_ENCODING_ASCII) || (name_enc == ZIP_ENCODING_ASCII && com_enc == ZIP_ENCODING_UTF8_KNOWN) || (name_enc == ZIP_ENCODING_UTF8_KNOWN && com_enc == ZIP_ENCODING_UTF8_KNOWN)) de->bitflags |= ZIP_GPBF_ENCODING_UTF_8; else { de->bitflags &= (zip_uint16_t)~ZIP_GPBF_ENCODING_UTF_8; if (name_enc == ZIP_ENCODING_UTF8_KNOWN) { ef = _zip_ef_utf8(ZIP_EF_UTF_8_NAME, de->filename, &za->error); if (ef == NULL) return -1; } if ((flags & ZIP_FL_LOCAL) == 0 && com_enc == ZIP_ENCODING_UTF8_KNOWN) { zip_extra_field_t *ef2 = _zip_ef_utf8(ZIP_EF_UTF_8_COMMENT, de->comment, &za->error); if (ef2 == NULL) { _zip_ef_free(ef); return -1; } ef2->next = ef; ef = ef2; } } if (de->encryption_method == ZIP_EM_NONE) { de->bitflags &= (zip_uint16_t)~ZIP_GPBF_ENCRYPTED; } else { de->bitflags |= (zip_uint16_t)ZIP_GPBF_ENCRYPTED; } is_really_zip64 = _zip_dirent_needs_zip64(de, flags); is_zip64 = (flags & (ZIP_FL_LOCAL | ZIP_FL_FORCE_ZIP64)) == (ZIP_FL_LOCAL | ZIP_FL_FORCE_ZIP64) || is_really_zip64; is_winzip_aes = de->encryption_method == ZIP_EM_AES_128 || de->encryption_method == ZIP_EM_AES_192 || de->encryption_method == ZIP_EM_AES_256; if (is_zip64) { zip_uint8_t ef_zip64[EFZIP64SIZE]; zip_buffer_t *ef_buffer = _zip_buffer_new(ef_zip64, sizeof(ef_zip64)); if (ef_buffer == NULL) { zip_error_set(&za->error, ZIP_ER_MEMORY, 0); _zip_ef_free(ef); return -1; } if (flags & ZIP_FL_LOCAL) { if ((flags & ZIP_FL_FORCE_ZIP64) || de->comp_size > ZIP_UINT32_MAX || de->uncomp_size > ZIP_UINT32_MAX) { _zip_buffer_put_64(ef_buffer, de->uncomp_size); _zip_buffer_put_64(ef_buffer, de->comp_size); } } else { if ((flags & ZIP_FL_FORCE_ZIP64) || de->comp_size > ZIP_UINT32_MAX || de->uncomp_size > ZIP_UINT32_MAX || de->offset > ZIP_UINT32_MAX) { if (de->uncomp_size >= ZIP_UINT32_MAX) { _zip_buffer_put_64(ef_buffer, de->uncomp_size); } if (de->comp_size >= ZIP_UINT32_MAX) { _zip_buffer_put_64(ef_buffer, de->comp_size); } if (de->offset >= ZIP_UINT32_MAX) { _zip_buffer_put_64(ef_buffer, de->offset); } } } if (!_zip_buffer_ok(ef_buffer)) { zip_error_set(&za->error, ZIP_ER_INTERNAL, 0); _zip_buffer_free(ef_buffer); _zip_ef_free(ef); return -1; } ef64 = _zip_ef_new(ZIP_EF_ZIP64, (zip_uint16_t)(_zip_buffer_offset(ef_buffer)), ef_zip64, ZIP_EF_BOTH); _zip_buffer_free(ef_buffer); ef64->next = ef; ef = ef64; } if (is_winzip_aes) { zip_uint8_t data[EF_WINZIP_AES_SIZE]; zip_buffer_t *ef_buffer = _zip_buffer_new(data, sizeof(data)); zip_extra_field_t *ef_winzip; if (ef_buffer == NULL) { zip_error_set(&za->error, ZIP_ER_MEMORY, 0); _zip_ef_free(ef); return -1; } _zip_buffer_put_16(ef_buffer, 2); _zip_buffer_put(ef_buffer, "AE", 2); _zip_buffer_put_8(ef_buffer, (zip_uint8_t)(de->encryption_method & 0xff)); _zip_buffer_put_16(ef_buffer, (zip_uint16_t)de->comp_method); if (!_zip_buffer_ok(ef_buffer)) { zip_error_set(&za->error, ZIP_ER_INTERNAL, 0); _zip_buffer_free(ef_buffer); _zip_ef_free(ef); return -1; } ef_winzip = _zip_ef_new(ZIP_EF_WINZIP_AES, EF_WINZIP_AES_SIZE, data, ZIP_EF_BOTH); _zip_buffer_free(ef_buffer); ef_winzip->next = ef; ef = ef_winzip; } if ((buffer = _zip_buffer_new(buf, sizeof(buf))) == NULL) { zip_error_set(&za->error, ZIP_ER_MEMORY, 0); _zip_ef_free(ef); return -1; } _zip_buffer_put(buffer, (flags & ZIP_FL_LOCAL) ? LOCAL_MAGIC : CENTRAL_MAGIC, 4); if ((flags & ZIP_FL_LOCAL) == 0) { _zip_buffer_put_16(buffer, de->version_madeby); } _zip_buffer_put_16(buffer, ZIP_MAX(is_really_zip64 ? 45 : 0, de->version_needed)); _zip_buffer_put_16(buffer, de->bitflags); if (is_winzip_aes) { _zip_buffer_put_16(buffer, ZIP_CM_WINZIP_AES); } else { _zip_buffer_put_16(buffer, (zip_uint16_t)ZIP_CM_ACTUAL(de->comp_method)); } if (ZIP_WANT_TORRENTZIP(za)) { dostime.time = 0xbc00; dostime.date = 0x2198; } else { dostime = de->last_mod; } _zip_buffer_put_16(buffer, dostime.time); _zip_buffer_put_16(buffer, dostime.date); if (is_winzip_aes && de->uncomp_size < 20) { _zip_buffer_put_32(buffer, 0); } else { _zip_buffer_put_32(buffer, de->crc); } if (((flags & ZIP_FL_LOCAL) == ZIP_FL_LOCAL) && ((de->comp_size >= ZIP_UINT32_MAX) || (de->uncomp_size >= ZIP_UINT32_MAX))) { /* In local headers, if a ZIP64 EF is written, it MUST contain * both compressed and uncompressed sizes (even if one of the * two is smaller than 0xFFFFFFFF); on the other hand, those * may only appear when the corresponding standard entry is * 0xFFFFFFFF. (appnote.txt 4.5.3) */ _zip_buffer_put_32(buffer, ZIP_UINT32_MAX); _zip_buffer_put_32(buffer, ZIP_UINT32_MAX); } else { if (de->comp_size < ZIP_UINT32_MAX) { _zip_buffer_put_32(buffer, (zip_uint32_t)de->comp_size); } else { _zip_buffer_put_32(buffer, ZIP_UINT32_MAX); } if (de->uncomp_size < ZIP_UINT32_MAX) { _zip_buffer_put_32(buffer, (zip_uint32_t)de->uncomp_size); } else { _zip_buffer_put_32(buffer, ZIP_UINT32_MAX); } } _zip_buffer_put_16(buffer, _zip_string_length(de->filename)); ef_total_size = (zip_uint32_t)_zip_ef_size(ef, ZIP_EF_BOTH); if (!ZIP_WANT_TORRENTZIP(za)) { /* TODO: check for overflow */ ef_total_size += (zip_uint32_t)_zip_ef_size(de->extra_fields, flags); } _zip_buffer_put_16(buffer, (zip_uint16_t)ef_total_size); if ((flags & ZIP_FL_LOCAL) == 0) { _zip_buffer_put_16(buffer, ZIP_WANT_TORRENTZIP(za) ? 0 : _zip_string_length(de->comment)); _zip_buffer_put_16(buffer, (zip_uint16_t)de->disk_number); _zip_buffer_put_16(buffer, de->int_attrib); _zip_buffer_put_32(buffer, de->ext_attrib); if (de->offset < ZIP_UINT32_MAX) _zip_buffer_put_32(buffer, (zip_uint32_t)de->offset); else _zip_buffer_put_32(buffer, ZIP_UINT32_MAX); } if (!_zip_buffer_ok(buffer)) { zip_error_set(&za->error, ZIP_ER_INTERNAL, 0); _zip_buffer_free(buffer); _zip_ef_free(ef); return -1; } if (_zip_write(za, buf, _zip_buffer_offset(buffer)) < 0) { _zip_buffer_free(buffer); _zip_ef_free(ef); return -1; } _zip_buffer_free(buffer); if (de->filename) { if (_zip_string_write(za, de->filename) < 0) { _zip_ef_free(ef); return -1; } } if (ef) { if (_zip_ef_write(za, ef, ZIP_EF_BOTH) < 0) { _zip_ef_free(ef); return -1; } } _zip_ef_free(ef); if (de->extra_fields && !ZIP_WANT_TORRENTZIP(za)) { if (_zip_ef_write(za, de->extra_fields, flags) < 0) { return -1; } } if ((flags & ZIP_FL_LOCAL) == 0 && !ZIP_WANT_TORRENTZIP(za)) { if (de->comment) { if (_zip_string_write(za, de->comment) < 0) { return -1; } } } return is_zip64; } time_t _zip_d2u_time(const zip_dostime_t *dtime) { struct tm tm; memset(&tm, 0, sizeof(tm)); /* let mktime decide if DST is in effect */ tm.tm_isdst = -1; tm.tm_year = ((dtime->date >> 9) & 127) + 1980 - 1900; tm.tm_mon = ((dtime->date >> 5) & 15) - 1; tm.tm_mday = dtime->date & 31; tm.tm_hour = (dtime->time >> 11) & 31; tm.tm_min = (dtime->time >> 5) & 63; tm.tm_sec = (dtime->time << 1) & 62; return mktime(&tm); } static zip_extra_field_t * _zip_ef_utf8(zip_uint16_t id, zip_string_t *str, zip_error_t *error) { const zip_uint8_t *raw; zip_uint32_t len; zip_buffer_t *buffer; zip_extra_field_t *ef; if ((raw = _zip_string_get(str, &len, ZIP_FL_ENC_RAW, NULL)) == NULL) { /* error already set */ return NULL; } if (len + 5 > ZIP_UINT16_MAX) { zip_error_set(error, ZIP_ER_INVAL, 0); /* TODO: better error code? */ return NULL; } if ((buffer = _zip_buffer_new(NULL, len + 5)) == NULL) { zip_error_set(error, ZIP_ER_MEMORY, 0); return NULL; } _zip_buffer_put_8(buffer, 1); _zip_buffer_put_32(buffer, _zip_string_crc32(str)); _zip_buffer_put(buffer, raw, len); if (!_zip_buffer_ok(buffer)) { zip_error_set(error, ZIP_ER_INTERNAL, 0); _zip_buffer_free(buffer); return NULL; } ef = _zip_ef_new(id, (zip_uint16_t)(_zip_buffer_offset(buffer)), _zip_buffer_data(buffer), ZIP_EF_BOTH); _zip_buffer_free(buffer); return ef; } zip_dirent_t * _zip_get_dirent(zip_t *za, zip_uint64_t idx, zip_flags_t flags, zip_error_t *error) { if (error == NULL) error = &za->error; if (idx >= za->nentry) { zip_error_set(error, ZIP_ER_INVAL, 0); return NULL; } if ((flags & ZIP_FL_UNCHANGED) || za->entry[idx].changes == NULL) { if (za->entry[idx].orig == NULL) { zip_error_set(error, ZIP_ER_INVAL, 0); return NULL; } if (za->entry[idx].deleted && (flags & ZIP_FL_UNCHANGED) == 0) { zip_error_set(error, ZIP_ER_DELETED, 0); return NULL; } return za->entry[idx].orig; } else return za->entry[idx].changes; } int _zip_u2d_time(time_t intime, zip_dostime_t *dtime, zip_error_t *ze) { struct tm *tpm; struct tm tm; tpm = zip_localtime(&intime, &tm); if (tpm == NULL) { /* if localtime fails, return an arbitrary date (1980-01-01 00:00:00) */ dtime->date = (1 << 5) + 1; dtime->time = 0; if (ze) { zip_error_set(ze, ZIP_ER_INVAL, errno); } return -1; } if (tpm->tm_year < 80) { tpm->tm_year = 80; } dtime->date = (zip_uint16_t)(((tpm->tm_year + 1900 - 1980) << 9) + ((tpm->tm_mon + 1) << 5) + tpm->tm_mday); dtime->time = (zip_uint16_t)(((tpm->tm_hour) << 11) + ((tpm->tm_min) << 5) + ((tpm->tm_sec) >> 1)); return 0; } bool _zip_dirent_apply_attributes(zip_dirent_t *de, zip_file_attributes_t *attributes, bool force_zip64) { zip_uint16_t length; bool has_changed = false; if (attributes->valid & ZIP_FILE_ATTRIBUTES_GENERAL_PURPOSE_BIT_FLAGS) { zip_uint16_t mask = attributes->general_purpose_bit_mask & ZIP_FILE_ATTRIBUTES_GENERAL_PURPOSE_BIT_FLAGS_ALLOWED_MASK; zip_uint16_t bitflags = (de->bitflags & ~mask) | (attributes->general_purpose_bit_flags & mask); if (de->bitflags != bitflags) { de->bitflags = bitflags; has_changed = true; } } if (attributes->valid & ZIP_FILE_ATTRIBUTES_ASCII) { zip_uint16_t int_attrib = (de->int_attrib & ~0x1) | (attributes->ascii ? 1 : 0); if (de->int_attrib != int_attrib) { de->int_attrib = int_attrib; has_changed = true; } } /* manually set attributes are preferred over attributes provided by source */ if ((de->changed & ZIP_DIRENT_ATTRIBUTES) == 0 && (attributes->valid & ZIP_FILE_ATTRIBUTES_EXTERNAL_FILE_ATTRIBUTES)) { if (de->ext_attrib != attributes->external_file_attributes) { de->ext_attrib = attributes->external_file_attributes; has_changed = true; } } zip_uint16_t version_needed; if (de->comp_method == ZIP_CM_LZMA) { version_needed = 63; } else if (de->encryption_method == ZIP_EM_AES_128 || de->encryption_method == ZIP_EM_AES_192 || de->encryption_method == ZIP_EM_AES_256) { version_needed = 51; } else if (de->comp_method == ZIP_CM_BZIP2) { version_needed = 46; } else if (force_zip64 || _zip_dirent_needs_zip64(de, 0)) { version_needed = 45; } else if (de->comp_method == ZIP_CM_DEFLATE || de->encryption_method == ZIP_EM_TRAD_PKWARE) { version_needed = 20; } else if ((length = _zip_string_length(de->filename)) > 0 && de->filename->raw[length - 1] == '/') { version_needed = 20; } else { version_needed = 10; } if (attributes->valid & ZIP_FILE_ATTRIBUTES_VERSION_NEEDED) { version_needed = ZIP_MAX(version_needed, attributes->version_needed); } if (de->version_needed != version_needed) { de->version_needed = version_needed; has_changed = true; } zip_int16_t version_madeby = 63 | (de->version_madeby & 0xff00); if ((de->changed & ZIP_DIRENT_ATTRIBUTES) == 0 && (attributes->valid & ZIP_FILE_ATTRIBUTES_HOST_SYSTEM)) { version_madeby = (version_madeby & 0xff) | (zip_uint16_t)(attributes->host_system << 8); } if (de->version_madeby != version_madeby) { de->version_madeby = version_madeby; has_changed = true; } return has_changed; } /* _zip_dirent_torrent_normalize(de); Set values suitable for torrentzip. */ void zip_dirent_torrentzip_normalize(zip_dirent_t *de) { de->version_madeby = 0; de->version_needed = 20; /* 2.0 */ de->bitflags = 2; /* maximum compression */ de->comp_method = ZIP_CM_DEFLATE; de->compression_level = TORRENTZIP_COMPRESSION_FLAGS; de->disk_number = 0; de->int_attrib = 0; de->ext_attrib = 0; /* last_mod, extra_fields, and comment are normalized in zip_dirent_write() directly */ } int zip_dirent_check_consistency(zip_dirent_t *dirent) { if (dirent->comp_method == ZIP_CM_STORE) { zip_uint64_t header_size = 0; switch (dirent->encryption_method) { case ZIP_EM_NONE: break; case ZIP_EM_TRAD_PKWARE: header_size = 12; break; case ZIP_EM_AES_128: header_size = 20; break; case ZIP_EM_AES_192: header_size = 24; break; case ZIP_EM_AES_256: header_size = 28; break; default: return 0; } if (dirent->uncomp_size + header_size < dirent->uncomp_size || dirent->comp_size != dirent->uncomp_size + header_size) { return ZIP_ER_DETAIL_STORED_SIZE_MISMATCH; } } return 0; } time_t zip_dirent_get_last_mod_mtime(zip_dirent_t *de) { if (!de->last_mod_mtime_valid) { de->last_mod_mtime = _zip_d2u_time(&de->last_mod); de->last_mod_mtime_valid = true; } return de->last_mod_mtime; } ================================================ FILE: external/libzip/lib/zip_discard.c ================================================ /* zip_discard.c -- discard and free struct zip Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include "zipint.h" /* zip_discard: frees the space allocated to a zipfile struct, and closes the corresponding file. */ void zip_discard(zip_t *za) { zip_uint64_t i; if (za == NULL) return; if (za->src) { zip_source_close(za->src); zip_source_free(za->src); } free(za->default_password); _zip_string_free(za->comment_orig); _zip_string_free(za->comment_changes); _zip_hash_free(za->names); if (za->entry) { for (i = 0; i < za->nentry; i++) _zip_entry_finalize(za->entry + i); free(za->entry); } for (i = 0; i < za->nopen_source; i++) { _zip_source_invalidate(za->open_source[i]); } free(za->open_source); _zip_progress_free(za->progress); zip_error_fini(&za->error); free(za); return; } ================================================ FILE: external/libzip/lib/zip_entry.c ================================================ /* zip_entry.c -- struct zip_entry helper functions Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "zipint.h" void _zip_entry_finalize(zip_entry_t *e) { _zip_unchange_data(e); _zip_dirent_free(e->orig); _zip_dirent_free(e->changes); } void _zip_entry_init(zip_entry_t *e) { e->orig = NULL; e->changes = NULL; e->source = NULL; e->deleted = 0; } ================================================ FILE: external/libzip/lib/zip_error.c ================================================ /* zip_error.c -- zip_error_t helper functions Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include "zipint.h" ZIP_EXTERN int zip_error_code_system(const zip_error_t *error) { return error->sys_err; } ZIP_EXTERN int zip_error_code_zip(const zip_error_t *error) { return error->zip_err; } ZIP_EXTERN void zip_error_fini(zip_error_t *err) { free(err->str); err->str = NULL; } ZIP_EXTERN void zip_error_init(zip_error_t *err) { err->zip_err = ZIP_ER_OK; err->sys_err = 0; err->str = NULL; } ZIP_EXTERN void zip_error_init_with_code(zip_error_t *error, int ze) { zip_error_init(error); error->zip_err = ze; switch (zip_error_system_type(error)) { case ZIP_ET_SYS: case ZIP_ET_LIBZIP: error->sys_err = errno; break; default: error->sys_err = 0; break; } } ZIP_EXTERN int zip_error_system_type(const zip_error_t *error) { if (error->zip_err < 0 || error->zip_err >= _zip_err_str_count) return ZIP_ET_NONE; return _zip_err_str[error->zip_err].type; } void _zip_error_clear(zip_error_t *err) { if (err == NULL) return; err->zip_err = ZIP_ER_OK; err->sys_err = 0; } void _zip_error_copy(zip_error_t *dst, const zip_error_t *src) { if (dst == NULL) { return; } dst->zip_err = src->zip_err; dst->sys_err = src->sys_err; } void _zip_error_get(const zip_error_t *err, int *zep, int *sep) { if (zep) *zep = err->zip_err; if (sep) { if (zip_error_system_type(err) != ZIP_ET_NONE) *sep = err->sys_err; else *sep = 0; } } void zip_error_set(zip_error_t *err, int ze, int se) { if (err) { err->zip_err = ze; err->sys_err = se; } } void zip_error_set_from_source(zip_error_t *err, zip_source_t *src) { if (src == NULL) { zip_error_set(err, ZIP_ER_INVAL, 0); return; } _zip_error_copy(err, zip_source_error(src)); } zip_int64_t zip_error_to_data(const zip_error_t *error, void *data, zip_uint64_t length) { int *e = (int *)data; if (length < sizeof(int) * 2) { return -1; } e[0] = zip_error_code_zip(error); e[1] = zip_error_code_system(error); return sizeof(int) * 2; } ================================================ FILE: external/libzip/lib/zip_error_clear.c ================================================ /* zip_error_clear.c -- clear zip error Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "zipint.h" ZIP_EXTERN void zip_error_clear(zip_t *za) { if (za == NULL) return; _zip_error_clear(&za->error); } ================================================ FILE: external/libzip/lib/zip_error_get.c ================================================ /* zip_error_get.c -- get zip error Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define _ZIP_COMPILING_DEPRECATED #include "zipint.h" ZIP_EXTERN void zip_error_get(zip_t *za, int *zep, int *sep) { _zip_error_get(&za->error, zep, sep); } ZIP_EXTERN zip_error_t * zip_get_error(zip_t *za) { return &za->error; } ZIP_EXTERN zip_error_t * zip_file_get_error(zip_file_t *f) { return &f->error; } ================================================ FILE: external/libzip/lib/zip_error_get_sys_type.c ================================================ /* zip_error_get_sys_type.c -- return type of system error code Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define _ZIP_COMPILING_DEPRECATED #include "zipint.h" ZIP_EXTERN int zip_error_get_sys_type(int ze) { if (ze < 0 || ze >= _zip_err_str_count) { return 0; } return _zip_err_str[ze].type; } ================================================ FILE: external/libzip/lib/zip_error_strerror.c ================================================ /* zip_error_sterror.c -- get string representation of struct zip_error Copyright (C) 1999-2023 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include "zipint.h" ZIP_EXTERN const char * zip_error_strerror(zip_error_t *err) { const char *zip_error_string, *system_error_string; char *s; char *system_error_buffer = NULL; zip_error_fini(err); if (err->zip_err < 0 || err->zip_err >= _zip_err_str_count) { system_error_buffer = (char *)malloc(128); if (system_error_buffer == NULL) { return _zip_err_str[ZIP_ER_MEMORY].description; } snprintf_s(system_error_buffer, 128, "Unknown error %d", err->zip_err); system_error_buffer[128 - 1] = '\0'; /* make sure string is NUL-terminated */ zip_error_string = NULL; system_error_string = system_error_buffer; } else { zip_error_string = _zip_err_str[err->zip_err].description; switch (_zip_err_str[err->zip_err].type) { case ZIP_ET_SYS: { size_t len = strerrorlen_s(err->sys_err) + 1; system_error_buffer = malloc(len); if (system_error_buffer == NULL) { return _zip_err_str[ZIP_ER_MEMORY].description; } strerror_s(system_error_buffer, len, err->sys_err); system_error_string = system_error_buffer; break; } case ZIP_ET_ZLIB: system_error_string = zError(err->sys_err); break; case ZIP_ET_LIBZIP: { zip_uint8_t error = GET_ERROR_FROM_DETAIL(err->sys_err); int index = GET_INDEX_FROM_DETAIL(err->sys_err); if (error == 0) { system_error_string = NULL; } else if (error >= _zip_err_details_count) { system_error_buffer = (char *)malloc(128); if (system_error_buffer == NULL) { return _zip_err_str[ZIP_ER_MEMORY].description; } snprintf_s(system_error_buffer, 128, "invalid detail error %u", error); system_error_buffer[128 - 1] = '\0'; /* make sure string is NUL-terminated */ system_error_string = system_error_buffer; } else if (_zip_err_details[error].type == ZIP_DETAIL_ET_ENTRY && index < MAX_DETAIL_INDEX) { system_error_buffer = (char *)malloc(128); if (system_error_buffer == NULL) { return _zip_err_str[ZIP_ER_MEMORY].description; } snprintf_s(system_error_buffer, 128, "entry %d: %s", index, _zip_err_details[error].description); system_error_buffer[128 - 1] = '\0'; /* make sure string is NUL-terminated */ system_error_string = system_error_buffer; } else { system_error_string = _zip_err_details[error].description; } break; } default: system_error_string = NULL; } } if (system_error_string == NULL) { free(system_error_buffer); return zip_error_string; } else { size_t length = strlen(system_error_string); if (zip_error_string) { size_t length_error = strlen(zip_error_string); if (length + length_error + 2 < length) { free(system_error_buffer); return _zip_err_str[ZIP_ER_MEMORY].description; } length += length_error + 2; } if (length == SIZE_MAX || (s = (char *)malloc(length + 1)) == NULL) { free(system_error_buffer); return _zip_err_str[ZIP_ER_MEMORY].description; } snprintf_s(s, length + 1, "%s%s%s", (zip_error_string ? zip_error_string : ""), (zip_error_string ? ": " : ""), system_error_string); err->str = s; free(system_error_buffer); return s; } } ================================================ FILE: external/libzip/lib/zip_error_to_str.c ================================================ /* zip_error_to_str.c -- get string representation of zip error code Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #define _ZIP_COMPILING_DEPRECATED #include "zipint.h" ZIP_EXTERN int zip_error_to_str(char *buf, zip_uint64_t len, int ze, int se) { zip_error_t error; const char *error_string; int ret; zip_error_init(&error); zip_error_set(&error, ze, se); error_string = zip_error_strerror(&error); ret = snprintf_s(buf, ZIP_MIN(len, SIZE_MAX), error_string, strlen(error_string)); zip_error_fini(&error); return ret; } ================================================ FILE: external/libzip/lib/zip_extra_field.c ================================================ /* zip_extra_field.c -- manipulate extra fields Copyright (C) 2012-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include "zipint.h" zip_extra_field_t * _zip_ef_clone(const zip_extra_field_t *ef, zip_error_t *error) { zip_extra_field_t *head, *prev, *def; head = prev = NULL; while (ef) { if ((def = _zip_ef_new(ef->id, ef->size, ef->data, ef->flags)) == NULL) { zip_error_set(error, ZIP_ER_MEMORY, 0); _zip_ef_free(head); return NULL; } if (head == NULL) head = def; if (prev) prev->next = def; prev = def; ef = ef->next; } return head; } zip_extra_field_t * _zip_ef_delete_by_id(zip_extra_field_t *ef, zip_uint16_t id, zip_uint16_t id_idx, zip_flags_t flags) { zip_extra_field_t *head, *prev; int i; i = 0; head = ef; prev = NULL; for (; ef; ef = (prev ? prev->next : head)) { if ((ef->flags & flags & ZIP_EF_BOTH) && ((ef->id == id) || (id == ZIP_EXTRA_FIELD_ALL))) { if (id_idx == ZIP_EXTRA_FIELD_ALL || i == id_idx) { ef->flags &= ~(flags & ZIP_EF_BOTH); if ((ef->flags & ZIP_EF_BOTH) == 0) { if (prev) prev->next = ef->next; else head = ef->next; ef->next = NULL; _zip_ef_free(ef); if (id_idx == ZIP_EXTRA_FIELD_ALL) continue; } } i++; if (i > id_idx) break; } prev = ef; } return head; } void _zip_ef_free(zip_extra_field_t *ef) { zip_extra_field_t *ef2; while (ef) { ef2 = ef->next; free(ef->data); free(ef); ef = ef2; } } const zip_uint8_t * _zip_ef_get_by_id(const zip_extra_field_t *ef, zip_uint16_t *lenp, zip_uint16_t id, zip_uint16_t id_idx, zip_flags_t flags, zip_error_t *error) { static const zip_uint8_t empty[1] = {'\0'}; int i; i = 0; for (; ef; ef = ef->next) { if (ef->id == id && (ef->flags & flags & ZIP_EF_BOTH)) { if (i < id_idx) { i++; continue; } if (lenp) *lenp = ef->size; if (ef->size > 0) return ef->data; else return empty; } } zip_error_set(error, ZIP_ER_NOENT, 0); return NULL; } zip_extra_field_t * _zip_ef_merge(zip_extra_field_t *to, zip_extra_field_t *from) { zip_extra_field_t *ef2, *tt, *tail; int duplicate; if (to == NULL) return from; for (tail = to; tail->next; tail = tail->next) ; for (; from; from = ef2) { ef2 = from->next; duplicate = 0; for (tt = to; tt; tt = tt->next) { if (tt->id == from->id && tt->size == from->size && (tt->size == 0 || memcmp(tt->data, from->data, tt->size) == 0)) { tt->flags |= (from->flags & ZIP_EF_BOTH); duplicate = 1; break; } } from->next = NULL; if (duplicate) _zip_ef_free(from); else tail = tail->next = from; } return to; } zip_extra_field_t * _zip_ef_new(zip_uint16_t id, zip_uint16_t size, const zip_uint8_t *data, zip_flags_t flags) { zip_extra_field_t *ef; if ((ef = (zip_extra_field_t *)malloc(sizeof(*ef))) == NULL) return NULL; ef->next = NULL; ef->flags = flags; ef->id = id; ef->size = size; if (size > 0) { if ((ef->data = (zip_uint8_t *)_zip_memdup(data, size, NULL)) == NULL) { free(ef); return NULL; } } else ef->data = NULL; return ef; } bool _zip_ef_parse(const zip_uint8_t *data, zip_uint16_t len, zip_flags_t flags, zip_extra_field_t **ef_head_p, zip_error_t *error) { zip_buffer_t *buffer; zip_extra_field_t *ef, *ef2, *ef_head; if ((buffer = _zip_buffer_new((zip_uint8_t *)data, len)) == NULL) { zip_error_set(error, ZIP_ER_MEMORY, 0); return false; } ef_head = ef = NULL; while (_zip_buffer_ok(buffer) && _zip_buffer_left(buffer) >= 4) { zip_uint16_t fid, flen; zip_uint8_t *ef_data; fid = _zip_buffer_get_16(buffer); flen = _zip_buffer_get_16(buffer); ef_data = _zip_buffer_get(buffer, flen); if (ef_data == NULL) { zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_INVALID_EF_LENGTH); _zip_buffer_free(buffer); _zip_ef_free(ef_head); return false; } if ((ef2 = _zip_ef_new(fid, flen, ef_data, flags)) == NULL) { zip_error_set(error, ZIP_ER_MEMORY, 0); _zip_buffer_free(buffer); _zip_ef_free(ef_head); return false; } if (ef_head) { ef->next = ef2; ef = ef2; } else ef_head = ef = ef2; } if (!_zip_buffer_eof(buffer)) { /* Android APK files align stored file data with padding in extra fields; ignore. */ /* see https://android.googlesource.com/platform/build/+/master/tools/zipalign/ZipAlign.cpp */ /* buffer is at most 64k long, so this can't overflow. */ size_t glen = _zip_buffer_left(buffer); zip_uint8_t *garbage; garbage = _zip_buffer_get(buffer, glen); if (glen >= 4 || garbage == NULL || memcmp(garbage, "\0\0\0", (size_t)glen) != 0) { zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_EF_TRAILING_GARBAGE); _zip_buffer_free(buffer); _zip_ef_free(ef_head); return false; } } _zip_buffer_free(buffer); if (ef_head_p) { *ef_head_p = ef_head; } else { _zip_ef_free(ef_head); } return true; } zip_extra_field_t * _zip_ef_remove_internal(zip_extra_field_t *ef) { zip_extra_field_t *ef_head; zip_extra_field_t *prev, *next; ef_head = ef; prev = NULL; while (ef) { if (ZIP_EF_IS_INTERNAL(ef->id)) { next = ef->next; if (ef_head == ef) ef_head = next; ef->next = NULL; _zip_ef_free(ef); if (prev) prev->next = next; ef = next; } else { prev = ef; ef = ef->next; } } return ef_head; } zip_uint16_t _zip_ef_size(const zip_extra_field_t *ef, zip_flags_t flags) { zip_uint16_t size; size = 0; for (; ef; ef = ef->next) { if (ef->flags & flags & ZIP_EF_BOTH) size = (zip_uint16_t)(size + 4 + ef->size); } return size; } int _zip_ef_write(zip_t *za, const zip_extra_field_t *ef, zip_flags_t flags) { zip_uint8_t b[4]; zip_buffer_t *buffer = _zip_buffer_new(b, sizeof(b)); if (buffer == NULL) { return -1; } for (; ef; ef = ef->next) { if (ef->flags & flags & ZIP_EF_BOTH) { _zip_buffer_set_offset(buffer, 0); _zip_buffer_put_16(buffer, ef->id); _zip_buffer_put_16(buffer, ef->size); if (!_zip_buffer_ok(buffer)) { zip_error_set(&za->error, ZIP_ER_INTERNAL, 0); _zip_buffer_free(buffer); return -1; } if (_zip_write(za, b, 4) < 0) { _zip_buffer_free(buffer); return -1; } if (ef->size > 0) { if (_zip_write(za, ef->data, ef->size) < 0) { _zip_buffer_free(buffer); return -1; } } } } _zip_buffer_free(buffer); return 0; } int _zip_read_local_ef(zip_t *za, zip_uint64_t idx) { zip_entry_t *e; unsigned char b[4]; zip_buffer_t *buffer; zip_uint16_t fname_len, ef_len; if (idx >= za->nentry) { zip_error_set(&za->error, ZIP_ER_INVAL, 0); return -1; } e = za->entry + idx; if (e->orig == NULL || e->orig->local_extra_fields_read) return 0; if (e->orig->offset + 26 > ZIP_INT64_MAX) { zip_error_set(&za->error, ZIP_ER_SEEK, EFBIG); return -1; } if (zip_source_seek(za->src, (zip_int64_t)(e->orig->offset + 26), SEEK_SET) < 0) { zip_error_set_from_source(&za->error, za->src); return -1; } if ((buffer = _zip_buffer_new_from_source(za->src, sizeof(b), b, &za->error)) == NULL) { return -1; } fname_len = _zip_buffer_get_16(buffer); ef_len = _zip_buffer_get_16(buffer); if (!_zip_buffer_eof(buffer)) { _zip_buffer_free(buffer); zip_error_set(&za->error, ZIP_ER_INTERNAL, 0); return -1; } _zip_buffer_free(buffer); if (ef_len > 0) { zip_extra_field_t *ef; zip_uint8_t *ef_raw; if (zip_source_seek(za->src, fname_len, SEEK_CUR) < 0) { zip_error_set(&za->error, ZIP_ER_SEEK, errno); return -1; } ef_raw = _zip_read_data(NULL, za->src, ef_len, 0, &za->error); if (ef_raw == NULL) return -1; if (!_zip_ef_parse(ef_raw, ef_len, ZIP_EF_LOCAL, &ef, &za->error)) { free(ef_raw); return -1; } free(ef_raw); if (ef) { ef = _zip_ef_remove_internal(ef); e->orig->extra_fields = _zip_ef_merge(e->orig->extra_fields, ef); } } e->orig->local_extra_fields_read = 1; if (e->changes && e->changes->local_extra_fields_read == 0) { e->changes->extra_fields = e->orig->extra_fields; e->changes->local_extra_fields_read = 1; } return 0; } ================================================ FILE: external/libzip/lib/zip_extra_field_api.c ================================================ /* zip_extra_field_api.c -- public extra fields API functions Copyright (C) 2012-2024 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "zipint.h" ZIP_EXTERN int zip_file_extra_field_delete(zip_t *za, zip_uint64_t idx, zip_uint16_t ef_idx, zip_flags_t flags) { zip_dirent_t *de; if ((flags & ZIP_EF_BOTH) == 0) { zip_error_set(&za->error, ZIP_ER_INVAL, 0); return -1; } if (((flags & ZIP_EF_BOTH) == ZIP_EF_BOTH) && (ef_idx != ZIP_EXTRA_FIELD_ALL)) { zip_error_set(&za->error, ZIP_ER_INVAL, 0); return -1; } if (_zip_get_dirent(za, idx, 0, NULL) == NULL) return -1; if (ZIP_IS_RDONLY(za)) { zip_error_set(&za->error, ZIP_ER_RDONLY, 0); return -1; } if (_zip_file_extra_field_prepare_for_change(za, idx) < 0) return -1; de = za->entry[idx].changes; de->extra_fields = _zip_ef_delete_by_id(de->extra_fields, ZIP_EXTRA_FIELD_ALL, ef_idx, flags); return 0; } ZIP_EXTERN int zip_file_extra_field_delete_by_id(zip_t *za, zip_uint64_t idx, zip_uint16_t ef_id, zip_uint16_t ef_idx, zip_flags_t flags) { zip_dirent_t *de; if ((flags & ZIP_EF_BOTH) == 0) { zip_error_set(&za->error, ZIP_ER_INVAL, 0); return -1; } if (((flags & ZIP_EF_BOTH) == ZIP_EF_BOTH) && (ef_idx != ZIP_EXTRA_FIELD_ALL)) { zip_error_set(&za->error, ZIP_ER_INVAL, 0); return -1; } if (_zip_get_dirent(za, idx, 0, NULL) == NULL) return -1; if (ZIP_IS_RDONLY(za)) { zip_error_set(&za->error, ZIP_ER_RDONLY, 0); return -1; } if (ZIP_WANT_TORRENTZIP(za)) { zip_error_set(&za->error, ZIP_ER_NOT_ALLOWED, 0); return -1; } if (_zip_file_extra_field_prepare_for_change(za, idx) < 0) return -1; de = za->entry[idx].changes; de->extra_fields = _zip_ef_delete_by_id(de->extra_fields, ef_id, ef_idx, flags); return 0; } ZIP_EXTERN const zip_uint8_t * zip_file_extra_field_get(zip_t *za, zip_uint64_t idx, zip_uint16_t ef_idx, zip_uint16_t *idp, zip_uint16_t *lenp, zip_flags_t flags) { static const zip_uint8_t empty[1] = {'\0'}; zip_dirent_t *de; zip_extra_field_t *ef; int i; if ((flags & ZIP_EF_BOTH) == 0) { zip_error_set(&za->error, ZIP_ER_INVAL, 0); return NULL; } if ((de = _zip_get_dirent(za, idx, flags, &za->error)) == NULL) return NULL; if (flags & ZIP_FL_LOCAL) if (_zip_read_local_ef(za, idx) < 0) return NULL; i = 0; for (ef = de->extra_fields; ef; ef = ef->next) { if (ef->flags & flags & ZIP_EF_BOTH) { if (i < ef_idx) { i++; continue; } if (idp) *idp = ef->id; if (lenp) *lenp = ef->size; if (ef->size > 0) return ef->data; else return empty; } } zip_error_set(&za->error, ZIP_ER_NOENT, 0); return NULL; } ZIP_EXTERN const zip_uint8_t * zip_file_extra_field_get_by_id(zip_t *za, zip_uint64_t idx, zip_uint16_t ef_id, zip_uint16_t ef_idx, zip_uint16_t *lenp, zip_flags_t flags) { zip_dirent_t *de; if ((flags & ZIP_EF_BOTH) == 0) { zip_error_set(&za->error, ZIP_ER_INVAL, 0); return NULL; } if ((de = _zip_get_dirent(za, idx, flags, &za->error)) == NULL) return NULL; if (flags & ZIP_FL_LOCAL) if (_zip_read_local_ef(za, idx) < 0) return NULL; return _zip_ef_get_by_id(de->extra_fields, lenp, ef_id, ef_idx, flags, &za->error); } ZIP_EXTERN zip_int16_t zip_file_extra_fields_count(zip_t *za, zip_uint64_t idx, zip_flags_t flags) { zip_dirent_t *de; zip_extra_field_t *ef; zip_uint16_t n; if ((flags & ZIP_EF_BOTH) == 0) { zip_error_set(&za->error, ZIP_ER_INVAL, 0); return -1; } if ((de = _zip_get_dirent(za, idx, flags, &za->error)) == NULL) return -1; if (flags & ZIP_FL_LOCAL) if (_zip_read_local_ef(za, idx) < 0) return -1; n = 0; for (ef = de->extra_fields; ef; ef = ef->next) if (ef->flags & flags & ZIP_EF_BOTH) n++; return (zip_int16_t)n; } ZIP_EXTERN zip_int16_t zip_file_extra_fields_count_by_id(zip_t *za, zip_uint64_t idx, zip_uint16_t ef_id, zip_flags_t flags) { zip_dirent_t *de; zip_extra_field_t *ef; zip_uint16_t n; if ((flags & ZIP_EF_BOTH) == 0) { zip_error_set(&za->error, ZIP_ER_INVAL, 0); return -1; } if ((de = _zip_get_dirent(za, idx, flags, &za->error)) == NULL) return -1; if (flags & ZIP_FL_LOCAL) if (_zip_read_local_ef(za, idx) < 0) return -1; n = 0; for (ef = de->extra_fields; ef; ef = ef->next) if (ef->id == ef_id && (ef->flags & flags & ZIP_EF_BOTH)) n++; return (zip_int16_t)n; } ZIP_EXTERN int zip_file_extra_field_set(zip_t *za, zip_uint64_t idx, zip_uint16_t ef_id, zip_uint16_t ef_idx, const zip_uint8_t *data, zip_uint16_t len, zip_flags_t flags) { zip_dirent_t *de; zip_uint16_t ls, cs; zip_extra_field_t *ef, *ef_prev, *ef_new; int i, found, new_len; if ((flags & ZIP_EF_BOTH) == 0) { zip_error_set(&za->error, ZIP_ER_INVAL, 0); return -1; } if (_zip_get_dirent(za, idx, 0, NULL) == NULL) return -1; if (ZIP_IS_RDONLY(za)) { zip_error_set(&za->error, ZIP_ER_RDONLY, 0); return -1; } if (ZIP_WANT_TORRENTZIP(za)) { zip_error_set(&za->error, ZIP_ER_NOT_ALLOWED, 0); return -1; } if (ZIP_EF_IS_INTERNAL(ef_id)) { zip_error_set(&za->error, ZIP_ER_INVAL, 0); return -1; } if (_zip_file_extra_field_prepare_for_change(za, idx) < 0) return -1; de = za->entry[idx].changes; ef = de->extra_fields; ef_prev = NULL; i = 0; found = 0; for (; ef; ef = ef->next) { if (ef->id == ef_id && (ef->flags & flags & ZIP_EF_BOTH)) { if (i == ef_idx) { found = 1; break; } i++; } ef_prev = ef; } if (i < ef_idx && ef_idx != ZIP_EXTRA_FIELD_NEW) { zip_error_set(&za->error, ZIP_ER_INVAL, 0); return -1; } if (flags & ZIP_EF_LOCAL) ls = _zip_ef_size(de->extra_fields, ZIP_EF_LOCAL); else ls = 0; if (flags & ZIP_EF_CENTRAL) cs = _zip_ef_size(de->extra_fields, ZIP_EF_CENTRAL); else cs = 0; new_len = ls > cs ? ls : cs; if (found) new_len -= ef->size + 4; new_len += len + 4; if (new_len > ZIP_UINT16_MAX) { zip_error_set(&za->error, ZIP_ER_INVAL, 0); return -1; } if ((ef_new = _zip_ef_new(ef_id, len, data, flags)) == NULL) { zip_error_set(&za->error, ZIP_ER_MEMORY, 0); return -1; } if (found) { if ((ef->flags & ZIP_EF_BOTH) == (flags & ZIP_EF_BOTH)) { ef_new->next = ef->next; ef->next = NULL; _zip_ef_free(ef); if (ef_prev) ef_prev->next = ef_new; else de->extra_fields = ef_new; } else { ef->flags &= ~(flags & ZIP_EF_BOTH); ef_new->next = ef->next; ef->next = ef_new; } } else if (ef_prev) { ef_new->next = ef_prev->next; ef_prev->next = ef_new; } else de->extra_fields = ef_new; return 0; } int _zip_file_extra_field_prepare_for_change(zip_t *za, zip_uint64_t idx) { zip_entry_t *e; if (idx >= za->nentry) { zip_error_set(&za->error, ZIP_ER_INVAL, 0); return -1; } e = za->entry + idx; if (e->changes && (e->changes->changed & ZIP_DIRENT_EXTRA_FIELD)) return 0; if (e->orig) { if (_zip_read_local_ef(za, idx) < 0) return -1; } if (e->changes == NULL) { if ((e->changes = _zip_dirent_clone(e->orig)) == NULL) { zip_error_set(&za->error, ZIP_ER_MEMORY, 0); return -1; } } if (e->orig && e->orig->extra_fields) { if ((e->changes->extra_fields = _zip_ef_clone(e->orig->extra_fields, &za->error)) == NULL) return -1; } e->changes->changed |= ZIP_DIRENT_EXTRA_FIELD; return 0; } ================================================ FILE: external/libzip/lib/zip_fclose.c ================================================ /* zip_fclose.c -- close file in zip archive Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include "zipint.h" ZIP_EXTERN int zip_fclose(zip_file_t *zf) { int ret; if (zf == NULL) return ZIP_ER_INVAL; if (zf->src) zip_source_free(zf->src); ret = 0; if (zf->error.zip_err) ret = zf->error.zip_err; zip_error_fini(&zf->error); free(zf); return ret; } ================================================ FILE: external/libzip/lib/zip_fdopen.c ================================================ /* zip_fdopen.c -- open read-only archive from file descriptor Copyright (C) 2009-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "zipint.h" #ifdef HAVE_UNISTD_H #include #endif ZIP_EXTERN zip_t * zip_fdopen(int fd_orig, int _flags, int *zep) { int fd; FILE *fp; zip_t *za; zip_source_t *src; struct zip_error error; if (_flags < 0 || (_flags & ~(ZIP_CHECKCONS | ZIP_RDONLY))) { _zip_set_open_error(zep, NULL, ZIP_ER_INVAL); return NULL; } #ifndef ENABLE_FDOPEN _zip_set_open_error(zep, NULL, ZIP_ER_OPNOTSUPP); return NULL; #else /* We dup() here to avoid messing with the passed in fd. We could not restore it to the original state in case of error. */ if ((fd = dup(fd_orig)) < 0) { _zip_set_open_error(zep, NULL, ZIP_ER_OPEN); return NULL; } if ((fp = fdopen(fd, "rb")) == NULL) { close(fd); _zip_set_open_error(zep, NULL, ZIP_ER_OPEN); return NULL; } zip_error_init(&error); if ((src = zip_source_filep_create(fp, 0, -1, &error)) == NULL) { fclose(fp); _zip_set_open_error(zep, &error, 0); zip_error_fini(&error); return NULL; } if ((za = zip_open_from_source(src, _flags, &error)) == NULL) { zip_source_free(src); _zip_set_open_error(zep, &error, 0); zip_error_fini(&error); return NULL; } zip_error_fini(&error); close(fd_orig); return za; #endif } ================================================ FILE: external/libzip/lib/zip_file_add.c ================================================ /* zip_file_add.c -- add file via callback function Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "zipint.h" /* NOTE: Return type is signed so we can return -1 on error. The index can not be larger than ZIP_INT64_MAX since the size of the central directory cannot be larger than ZIP_UINT64_MAX, and each entry is larger than 2 bytes. */ ZIP_EXTERN zip_int64_t zip_file_add(zip_t *za, const char *name, zip_source_t *source, zip_flags_t flags) { if (name == NULL || source == NULL) { zip_error_set(&za->error, ZIP_ER_INVAL, 0); return -1; } return _zip_file_replace(za, ZIP_UINT64_MAX, name, source, flags); } ================================================ FILE: external/libzip/lib/zip_file_error_clear.c ================================================ /* zip_file_error_clear.c -- clear zip file error Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "zipint.h" ZIP_EXTERN void zip_file_error_clear(zip_file_t *zf) { if (zf == NULL) return; _zip_error_clear(&zf->error); } ================================================ FILE: external/libzip/lib/zip_file_error_get.c ================================================ /* zip_file_error_get.c -- get zip file error Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define _ZIP_COMPILING_DEPRECATED #include "zipint.h" ZIP_EXTERN void zip_file_error_get(zip_file_t *zf, int *zep, int *sep) { _zip_error_get(&zf->error, zep, sep); } ================================================ FILE: external/libzip/lib/zip_file_get_comment.c ================================================ /* zip_file_get_comment.c -- get file comment Copyright (C) 2006-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "zipint.h" /* lenp is 32 bit because converted comment can be longer than ZIP_UINT16_MAX */ ZIP_EXTERN const char * zip_file_get_comment(zip_t *za, zip_uint64_t idx, zip_uint32_t *lenp, zip_flags_t flags) { zip_dirent_t *de; zip_uint32_t len; const zip_uint8_t *str; if ((de = _zip_get_dirent(za, idx, flags, NULL)) == NULL) return NULL; if ((str = _zip_string_get(de->comment, &len, flags, &za->error)) == NULL) return NULL; if (lenp) *lenp = len; return (const char *)str; } ================================================ FILE: external/libzip/lib/zip_file_get_external_attributes.c ================================================ /* zip_file_get_external_attributes.c -- get opsys/external attributes Copyright (C) 2013-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "zipint.h" int zip_file_get_external_attributes(zip_t *za, zip_uint64_t idx, zip_flags_t flags, zip_uint8_t *opsys, zip_uint32_t *attributes) { zip_dirent_t *de; if ((de = _zip_get_dirent(za, idx, flags, NULL)) == NULL) return -1; if (opsys) *opsys = (zip_uint8_t)((de->version_madeby >> 8) & 0xff); if (attributes) *attributes = de->ext_attrib; return 0; } ================================================ FILE: external/libzip/lib/zip_file_get_offset.c ================================================ /* zip_file_get_offset.c -- get offset of file data in archive. Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include "zipint.h" /* _zip_file_get_offset(za, ze): Returns the offset of the file data for entry ze. On error, fills in za->error and returns 0. */ zip_uint64_t _zip_file_get_offset(const zip_t *za, zip_uint64_t idx, zip_error_t *error) { zip_uint64_t offset; zip_int32_t size; if (za->entry[idx].orig == NULL) { zip_error_set(error, ZIP_ER_INTERNAL, 0); return 0; } offset = za->entry[idx].orig->offset; if (zip_source_seek(za->src, (zip_int64_t)offset, SEEK_SET) < 0) { zip_error_set_from_source(error, za->src); return 0; } /* TODO: cache? */ if ((size = _zip_dirent_size(za->src, ZIP_EF_LOCAL, error)) < 0) return 0; if (offset + (zip_uint32_t)size > ZIP_INT64_MAX) { zip_error_set(error, ZIP_ER_SEEK, EFBIG); return 0; } return offset + (zip_uint32_t)size; } zip_uint64_t _zip_file_get_end(const zip_t *za, zip_uint64_t index, zip_error_t *error) { zip_uint64_t offset; zip_dirent_t *entry; if ((offset = _zip_file_get_offset(za, index, error)) == 0) { return 0; } entry = za->entry[index].orig; if (offset + entry->comp_size < offset || offset + entry->comp_size > ZIP_INT64_MAX) { zip_error_set(error, ZIP_ER_SEEK, EFBIG); return 0; } offset += entry->comp_size; if (entry->bitflags & ZIP_GPBF_DATA_DESCRIPTOR) { zip_uint8_t buf[4]; if (zip_source_seek(za->src, (zip_int64_t)offset, SEEK_SET) < 0) { zip_error_set_from_source(error, za->src); return 0; } if (zip_source_read(za->src, buf, 4) != 4) { zip_error_set_from_source(error, za->src); return 0; } if (memcmp(buf, DATADES_MAGIC, 4) == 0) { offset += 4; } offset += 12; if (_zip_dirent_needs_zip64(entry, 0)) { offset += 8; } if (offset > ZIP_INT64_MAX) { zip_error_set(error, ZIP_ER_SEEK, EFBIG); return 0; } } return offset; } ================================================ FILE: external/libzip/lib/zip_file_rename.c ================================================ /* zip_file_rename.c -- rename file in zip archive Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include "zipint.h" ZIP_EXTERN int zip_file_rename(zip_t *za, zip_uint64_t idx, const char *name, zip_flags_t flags) { const char *old_name; int old_is_dir, new_is_dir; if (idx >= za->nentry || (name != NULL && strlen(name) > ZIP_UINT16_MAX)) { zip_error_set(&za->error, ZIP_ER_INVAL, 0); return -1; } if (ZIP_IS_RDONLY(za)) { zip_error_set(&za->error, ZIP_ER_RDONLY, 0); return -1; } if ((old_name = zip_get_name(za, idx, 0)) == NULL) return -1; new_is_dir = (name != NULL && name[strlen(name) - 1] == '/'); old_is_dir = (old_name[strlen(old_name) - 1] == '/'); if (new_is_dir != old_is_dir) { zip_error_set(&za->error, ZIP_ER_INVAL, 0); return -1; } return _zip_set_name(za, idx, name, flags); } ================================================ FILE: external/libzip/lib/zip_file_replace.c ================================================ /* zip_file_replace.c -- replace file via callback function Copyright (C) 1999-2024 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "zipint.h" ZIP_EXTERN int zip_file_replace(zip_t *za, zip_uint64_t idx, zip_source_t *source, zip_flags_t flags) { if (idx >= za->nentry || source == NULL) { zip_error_set(&za->error, ZIP_ER_INVAL, 0); return -1; } if (_zip_file_replace(za, idx, NULL, source, flags) == -1) return -1; return 0; } /* NOTE: Signed due to -1 on error. See zip_add.c for more details. */ zip_int64_t _zip_file_replace(zip_t *za, zip_uint64_t idx, const char *name, zip_source_t *source, zip_flags_t flags) { zip_uint64_t za_nentry_prev; if (ZIP_IS_RDONLY(za)) { zip_error_set(&za->error, ZIP_ER_RDONLY, 0); return -1; } za_nentry_prev = za->nentry; if (idx == ZIP_UINT64_MAX) { zip_int64_t i = -1; if (flags & ZIP_FL_OVERWRITE) i = _zip_name_locate(za, name, flags, NULL); if (i == -1) { /* create and use new entry, used by zip_add */ if ((i = _zip_add_entry(za)) < 0) return -1; } idx = (zip_uint64_t)i; } if (name && _zip_set_name(za, idx, name, flags) != 0) { if (za->nentry != za_nentry_prev) { _zip_entry_finalize(za->entry + idx); za->nentry = za_nentry_prev; } return -1; } /* delete all extra fields - these are usually data that are * strongly coupled with the original data */ if (zip_file_extra_field_delete(za, idx, ZIP_EXTRA_FIELD_ALL, ZIP_FL_CENTRAL | ZIP_FL_LOCAL) < 0) { return -1; } /* does not change any name related data, so we can do it here; * needed for a double add of the same file name */ _zip_unchange_data(za->entry + idx); if (za->entry[idx].orig != NULL && (za->entry[idx].changes == NULL || (za->entry[idx].changes->changed & ZIP_DIRENT_COMP_METHOD) == 0)) { if (za->entry[idx].changes == NULL) { if ((za->entry[idx].changes = _zip_dirent_clone(za->entry[idx].orig)) == NULL) { zip_error_set(&za->error, ZIP_ER_MEMORY, 0); return -1; } } za->entry[idx].changes->comp_method = ZIP_CM_REPLACED_DEFAULT; za->entry[idx].changes->changed |= ZIP_DIRENT_COMP_METHOD; } za->entry[idx].source = source; return (zip_int64_t)idx; } ================================================ FILE: external/libzip/lib/zip_file_set_comment.c ================================================ /* zip_file_set_comment.c -- set comment for file in archive Copyright (C) 2006-2023 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include "zipint.h" ZIP_EXTERN int zip_file_set_comment(zip_t *za, zip_uint64_t idx, const char *comment, zip_uint16_t len, zip_flags_t flags) { zip_entry_t *e; zip_string_t *cstr; int changed; if (_zip_get_dirent(za, idx, 0, NULL) == NULL) return -1; if (ZIP_IS_RDONLY(za)) { zip_error_set(&za->error, ZIP_ER_RDONLY, 0); return -1; } if (ZIP_WANT_TORRENTZIP(za)) { zip_error_set(&za->error, ZIP_ER_NOT_ALLOWED, 0); return -1; } if (len > 0 && comment == NULL) { zip_error_set(&za->error, ZIP_ER_INVAL, 0); return -1; } if (len > 0) { if ((cstr = _zip_string_new((const zip_uint8_t *)comment, len, flags, &za->error)) == NULL) return -1; if ((flags & ZIP_FL_ENCODING_ALL) == ZIP_FL_ENC_GUESS && _zip_guess_encoding(cstr, ZIP_ENCODING_UNKNOWN) == ZIP_ENCODING_UTF8_GUESSED) cstr->encoding = ZIP_ENCODING_UTF8_KNOWN; } else cstr = NULL; e = za->entry + idx; if (e->changes) { _zip_string_free(e->changes->comment); e->changes->comment = NULL; e->changes->changed &= ~ZIP_DIRENT_COMMENT; } if (e->orig && e->orig->comment) changed = !_zip_string_equal(e->orig->comment, cstr); else changed = (cstr != NULL); if (changed) { if (e->changes == NULL) { if ((e->changes = _zip_dirent_clone(e->orig)) == NULL) { zip_error_set(&za->error, ZIP_ER_MEMORY, 0); _zip_string_free(cstr); return -1; } } e->changes->comment = cstr; e->changes->changed |= ZIP_DIRENT_COMMENT; } else { _zip_string_free(cstr); if (e->changes && e->changes->changed == 0) { _zip_dirent_free(e->changes); e->changes = NULL; } } return 0; } ================================================ FILE: external/libzip/lib/zip_file_set_encryption.c ================================================ /* zip_file_set_encryption.c -- set encryption for file in archive Copyright (C) 2016-2023 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "zipint.h" #include #include ZIP_EXTERN int zip_file_set_encryption(zip_t *za, zip_uint64_t idx, zip_uint16_t method, const char *password) { zip_entry_t *e; char *our_password = NULL; if (idx >= za->nentry) { zip_error_set(&za->error, ZIP_ER_INVAL, 0); return -1; } if (ZIP_IS_RDONLY(za)) { zip_error_set(&za->error, ZIP_ER_RDONLY, 0); return -1; } if (ZIP_WANT_TORRENTZIP(za)) { zip_error_set(&za->error, ZIP_ER_NOT_ALLOWED, 0); return -1; } if (method != ZIP_EM_NONE && _zip_get_encryption_implementation(method, ZIP_CODEC_ENCODE) == NULL) { zip_error_set(&za->error, ZIP_ER_ENCRNOTSUPP, 0); return -1; } e = za->entry + idx; if (e->changes == NULL) { if ((e->changes = _zip_dirent_clone(e->orig)) == NULL) { zip_error_set(&za->error, ZIP_ER_MEMORY, 0); return -1; } } if (password) { if ((our_password = strdup(password)) == NULL) { zip_error_set(&za->error, ZIP_ER_MEMORY, 0); return -1; } } e->changes->encryption_method = method; e->changes->changed |= ZIP_DIRENT_ENCRYPTION_METHOD; if (password) { e->changes->password = our_password; e->changes->changed |= ZIP_DIRENT_PASSWORD; } else { if (e->changes->changed & ZIP_DIRENT_PASSWORD) { _zip_crypto_clear(e->changes->password, strlen(e->changes->password)); free(e->changes->password); e->changes->password = e->orig ? e->orig->password : NULL; e->changes->changed &= ~ZIP_DIRENT_PASSWORD; } } return 0; } ================================================ FILE: external/libzip/lib/zip_file_set_external_attributes.c ================================================ /* zip_file_set_external_attributes.c -- set external attributes for entry Copyright (C) 2013-2023 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "zipint.h" ZIP_EXTERN int zip_file_set_external_attributes(zip_t *za, zip_uint64_t idx, zip_flags_t flags, zip_uint8_t opsys, zip_uint32_t attributes) { zip_entry_t *e; int changed; zip_uint8_t unchanged_opsys; zip_uint32_t unchanged_attributes; if (_zip_get_dirent(za, idx, 0, NULL) == NULL) return -1; if (ZIP_IS_RDONLY(za)) { zip_error_set(&za->error, ZIP_ER_RDONLY, 0); return -1; } if (ZIP_WANT_TORRENTZIP(za)) { zip_error_set(&za->error, ZIP_ER_NOT_ALLOWED, 0); return -1; } e = za->entry + idx; unchanged_opsys = (e->orig ? (zip_uint8_t)(e->orig->version_madeby >> 8) : (zip_uint8_t)ZIP_OPSYS_DEFAULT); unchanged_attributes = e->orig ? e->orig->ext_attrib : ZIP_EXT_ATTRIB_DEFAULT; changed = (opsys != unchanged_opsys || attributes != unchanged_attributes); if (changed) { if (e->changes == NULL) { if ((e->changes = _zip_dirent_clone(e->orig)) == NULL) { zip_error_set(&za->error, ZIP_ER_MEMORY, 0); return -1; } } e->changes->version_madeby = (zip_uint16_t)((opsys << 8) | (e->changes->version_madeby & 0xff)); e->changes->ext_attrib = attributes; e->changes->changed |= ZIP_DIRENT_ATTRIBUTES; } else if (e->changes) { e->changes->changed &= ~ZIP_DIRENT_ATTRIBUTES; if (e->changes->changed == 0) { _zip_dirent_free(e->changes); e->changes = NULL; } else { e->changes->version_madeby = (zip_uint16_t)((unchanged_opsys << 8) | (e->changes->version_madeby & 0xff)); e->changes->ext_attrib = unchanged_attributes; } } return 0; } ================================================ FILE: external/libzip/lib/zip_file_set_mtime.c ================================================ /* zip_file_set_mtime.c -- set modification time of entry. Copyright (C) 2014-2024 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "zipint.h" static int zip_file_set_time(zip_t *za, zip_uint64_t idx, zip_uint16_t dtime, zip_uint16_t ddate, zip_flags_t flags, time_t *mtime) { zip_entry_t *e; if (_zip_get_dirent(za, idx, 0, NULL) == NULL) { return -1; } if (ZIP_IS_RDONLY(za)) { zip_error_set(&za->error, ZIP_ER_RDONLY, 0); return -1; } if (ZIP_WANT_TORRENTZIP(za)) { zip_error_set(&za->error, ZIP_ER_NOT_ALLOWED, 0); return -1; } e = za->entry + idx; if (e->orig != NULL && e->orig->encryption_method == ZIP_EM_TRAD_PKWARE && !ZIP_ENTRY_CHANGED(e, ZIP_DIRENT_ENCRYPTION_METHOD) && !ZIP_ENTRY_DATA_CHANGED(e)) { zip_error_set(&za->error, ZIP_ER_OPNOTSUPP, 0); return -1; } if (e->changes == NULL) { if ((e->changes = _zip_dirent_clone(e->orig)) == NULL) { zip_error_set(&za->error, ZIP_ER_MEMORY, 0); return -1; } } e->changes->last_mod.time = dtime; e->changes->last_mod.date = ddate; if (mtime != NULL) { e->changes->last_mod_mtime = *mtime; e->changes->last_mod_mtime_valid = true; } else { e->changes->last_mod_mtime_valid = false; } e->changes->changed |= ZIP_DIRENT_LAST_MOD; return 0; } ZIP_EXTERN int zip_file_set_dostime(zip_t *za, zip_uint64_t idx, zip_uint16_t dtime, zip_uint16_t ddate, zip_flags_t flags) { return zip_file_set_time(za, idx, dtime, ddate, flags, NULL); } ZIP_EXTERN int zip_file_set_mtime(zip_t *za, zip_uint64_t idx, time_t mtime, zip_flags_t flags) { zip_dostime_t dostime; if (_zip_u2d_time(mtime, &dostime, &za->error) < 0) { return -1; } return zip_file_set_time(za, idx, dostime.time, dostime.date, flags, &mtime); } ================================================ FILE: external/libzip/lib/zip_file_strerror.c ================================================ /* zip_file_sterror.c -- get string representation of zip file error Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "zipint.h" ZIP_EXTERN const char * zip_file_strerror(zip_file_t *zf) { return zip_error_strerror(&zf->error); } ================================================ FILE: external/libzip/lib/zip_fopen.c ================================================ /* zip_fopen.c -- open file in zip archive for reading Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "zipint.h" ZIP_EXTERN zip_file_t * zip_fopen(zip_t *za, const char *fname, zip_flags_t flags) { zip_int64_t idx; if ((idx = zip_name_locate(za, fname, flags)) < 0) return NULL; return zip_fopen_index_encrypted(za, (zip_uint64_t)idx, flags, za->default_password); } ================================================ FILE: external/libzip/lib/zip_fopen_encrypted.c ================================================ /* zip_fopen_encrypted.c -- open file for reading with password Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "zipint.h" ZIP_EXTERN zip_file_t * zip_fopen_encrypted(zip_t *za, const char *fname, zip_flags_t flags, const char *password) { zip_int64_t idx; if ((idx = zip_name_locate(za, fname, flags)) < 0) return NULL; return zip_fopen_index_encrypted(za, (zip_uint64_t)idx, flags, password); } ================================================ FILE: external/libzip/lib/zip_fopen_index.c ================================================ /* zip_fopen_index.c -- open file in zip archive for reading by index Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "zipint.h" ZIP_EXTERN zip_file_t * zip_fopen_index(zip_t *za, zip_uint64_t index, zip_flags_t flags) { return zip_fopen_index_encrypted(za, index, flags, za->default_password); } ================================================ FILE: external/libzip/lib/zip_fopen_index_encrypted.c ================================================ /* zip_fopen_index_encrypted.c -- open file for reading by index w/ password Copyright (C) 1999-2023 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include "zipint.h" static zip_file_t *_zip_file_new(zip_t *za); ZIP_EXTERN zip_file_t * zip_fopen_index_encrypted(zip_t *za, zip_uint64_t index, zip_flags_t flags, const char *password) { zip_file_t *zf; zip_source_t *src; if (password != NULL && password[0] == '\0') { password = NULL; } if ((src = zip_source_zip_file_create(za, index, flags, 0, -1, password, &za->error)) == NULL) return NULL; if (zip_source_open(src) < 0) { zip_error_set_from_source(&za->error, src); zip_source_free(src); return NULL; } if ((zf = _zip_file_new(za)) == NULL) { zip_source_free(src); return NULL; } zf->src = src; return zf; } static zip_file_t * _zip_file_new(zip_t *za) { zip_file_t *zf; if ((zf = (zip_file_t *)malloc(sizeof(struct zip_file))) == NULL) { zip_error_set(&za->error, ZIP_ER_MEMORY, 0); return NULL; } zip_error_init(&zf->error); zf->src = NULL; return zf; } ================================================ FILE: external/libzip/lib/zip_fread.c ================================================ /* zip_fread.c -- read from file Copyright (C) 1999-2024 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "zipint.h" ZIP_EXTERN zip_int64_t zip_fread(zip_file_t *zf, void *outbuf, zip_uint64_t toread) { zip_int64_t n; if (zf == NULL) { return -1; } if (zf->error.zip_err != 0) { return -1; } if (toread > ZIP_INT64_MAX) { zip_error_set(&zf->error, ZIP_ER_INVAL, 0); return -1; } if (toread == 0) { return 0; } if ((n = zip_source_read(zf->src, outbuf, toread)) < 0) { zip_error_set_from_source(&zf->error, zf->src); return -1; } return n; } ================================================ FILE: external/libzip/lib/zip_fseek.c ================================================ /* zip_fseek.c -- seek in file Copyright (C) 2016-2024 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "zipint.h" ZIP_EXTERN zip_int8_t zip_fseek(zip_file_t *zf, zip_int64_t offset, int whence) { if (zf == NULL) { return -1; } if (zf->error.zip_err != 0) { return -1; } if (zip_source_seek(zf->src, offset, whence) < 0) { zip_error_set_from_source(&zf->error, zf->src); return -1; } return 0; } ZIP_EXTERN int zip_file_is_seekable(zip_file_t *zfile) { if (zfile == NULL) { return -1; } return zip_source_is_seekable(zfile->src); } ================================================ FILE: external/libzip/lib/zip_ftell.c ================================================ /* zip_ftell.c -- tell position in file Copyright (C) 2016-2024 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "zipint.h" ZIP_EXTERN zip_int64_t zip_ftell(zip_file_t *zf) { zip_int64_t res; if (zf == NULL) { return -1; } if (zf->error.zip_err != 0) { return -1; } res = zip_source_tell(zf->src); if (res < 0) { zip_error_set_from_source(&zf->error, zf->src); return -1; } return res; } ================================================ FILE: external/libzip/lib/zip_get_archive_comment.c ================================================ /* zip_get_archive_comment.c -- get archive comment Copyright (C) 2006-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include "zipint.h" ZIP_EXTERN const char * zip_get_archive_comment(zip_t *za, int *lenp, zip_flags_t flags) { zip_string_t *comment; zip_uint32_t len; const zip_uint8_t *str; if ((flags & ZIP_FL_UNCHANGED) || (za->comment_changes == NULL)) comment = za->comment_orig; else comment = za->comment_changes; if ((str = _zip_string_get(comment, &len, flags, &za->error)) == NULL) return NULL; if (lenp) *lenp = (int)len; return (const char *)str; } ================================================ FILE: external/libzip/lib/zip_get_archive_flag.c ================================================ /* zip_get_archive_flag.c -- get archive global flag Copyright (C) 2008-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "zipint.h" ZIP_EXTERN int zip_get_archive_flag(zip_t *za, zip_flags_t flag, zip_flags_t flags) { unsigned int fl; fl = (flags & ZIP_FL_UNCHANGED) ? za->flags : za->ch_flags; return (fl & flag) ? 1 : 0; } ================================================ FILE: external/libzip/lib/zip_get_encryption_implementation.c ================================================ /* zip_get_encryption_implementation.c -- get encryption implementation Copyright (C) 2009-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "zipint.h" zip_encryption_implementation _zip_get_encryption_implementation(zip_uint16_t em, int operation) { switch (em) { case ZIP_EM_TRAD_PKWARE: return operation == ZIP_CODEC_DECODE ? zip_source_pkware_decode : zip_source_pkware_encode; #if defined(HAVE_CRYPTO) case ZIP_EM_AES_128: case ZIP_EM_AES_192: case ZIP_EM_AES_256: return operation == ZIP_CODEC_DECODE ? zip_source_winzip_aes_decode : zip_source_winzip_aes_encode; #endif default: return NULL; } } ZIP_EXTERN int zip_encryption_method_supported(zip_uint16_t method, int encode) { if (method == ZIP_EM_NONE) { return 1; } return _zip_get_encryption_implementation(method, encode ? ZIP_CODEC_ENCODE : ZIP_CODEC_DECODE) != NULL; } ================================================ FILE: external/libzip/lib/zip_get_file_comment.c ================================================ /* zip_get_file_comment.c -- get file comment Copyright (C) 2006-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define _ZIP_COMPILING_DEPRECATED #include "zipint.h" ZIP_EXTERN const char * zip_get_file_comment(zip_t *za, zip_uint64_t idx, int *lenp, int flags) { zip_uint32_t len; const char *s; if ((s = zip_file_get_comment(za, idx, &len, (zip_flags_t)flags)) != NULL) { if (lenp) *lenp = (int)len; } return s; } ================================================ FILE: external/libzip/lib/zip_get_name.c ================================================ /* zip_get_name.c -- get filename for a file in zip file Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include "zipint.h" ZIP_EXTERN const char * zip_get_name(zip_t *za, zip_uint64_t idx, zip_flags_t flags) { return _zip_get_name(za, idx, flags, &za->error); } const char * _zip_get_name(zip_t *za, zip_uint64_t idx, zip_flags_t flags, zip_error_t *error) { zip_dirent_t *de; const zip_uint8_t *str; if ((de = _zip_get_dirent(za, idx, flags, error)) == NULL) return NULL; if ((str = _zip_string_get(de->filename, NULL, flags, error)) == NULL) return NULL; return (const char *)str; } ================================================ FILE: external/libzip/lib/zip_get_num_entries.c ================================================ /* zip_get_num_entries.c -- get number of entries in archive Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "zipint.h" ZIP_EXTERN zip_int64_t zip_get_num_entries(zip_t *za, zip_flags_t flags) { zip_uint64_t n; if (za == NULL) return -1; if (flags & ZIP_FL_UNCHANGED) { n = za->nentry; while (n > 0 && za->entry[n - 1].orig == NULL) --n; return (zip_int64_t)n; } return (zip_int64_t)za->nentry; } ================================================ FILE: external/libzip/lib/zip_get_num_files.c ================================================ /* zip_get_num_files.c -- get number of files in archive Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define _ZIP_COMPILING_DEPRECATED #include "zipint.h" #include ZIP_EXTERN int zip_get_num_files(zip_t *za) { if (za == NULL) return -1; if (za->nentry > INT_MAX) { zip_error_set(&za->error, ZIP_ER_OPNOTSUPP, 0); return -1; } return (int)za->nentry; } ================================================ FILE: external/libzip/lib/zip_hash.c ================================================ /* zip_hash.c -- hash table string -> uint64 Copyright (C) 2015-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "zipint.h" #include #include /* parameter for the string hash function */ #define HASH_MULTIPLIER 33 #define HASH_START 5381 /* hash table's fill ratio is kept between these by doubling/halfing its size as necessary */ #define HASH_MAX_FILL .75 #define HASH_MIN_FILL .01 /* but hash table size is kept between these */ #define HASH_MIN_SIZE 256 #define HASH_MAX_SIZE 0x80000000ul struct zip_hash_entry { const zip_uint8_t *name; zip_int64_t orig_index; zip_int64_t current_index; struct zip_hash_entry *next; zip_uint32_t hash_value; }; typedef struct zip_hash_entry zip_hash_entry_t; struct zip_hash { zip_uint32_t table_size; zip_uint64_t nentries; zip_hash_entry_t **table; }; /* free list of entries */ static void free_list(zip_hash_entry_t *entry) { while (entry != NULL) { zip_hash_entry_t *next = entry->next; free(entry); entry = next; } } /* compute hash of string, full 32 bit value */ static zip_uint32_t hash_string(const zip_uint8_t *name) { zip_uint64_t value = HASH_START; if (name == NULL) { return 0; } while (*name != 0) { value = (zip_uint64_t)(((value * HASH_MULTIPLIER) + (zip_uint8_t)*name) % 0x100000000ul); name++; } return (zip_uint32_t)value; } /* resize hash table; new_size must be a power of 2, can be larger or smaller than current size */ static bool hash_resize(zip_hash_t *hash, zip_uint32_t new_size, zip_error_t *error) { zip_hash_entry_t **new_table; if (new_size == hash->table_size) { return true; } if ((new_table = (zip_hash_entry_t **)calloc(new_size, sizeof(zip_hash_entry_t *))) == NULL) { zip_error_set(error, ZIP_ER_MEMORY, 0); return false; } if (hash->nentries > 0) { zip_uint32_t i; for (i = 0; i < hash->table_size; i++) { zip_hash_entry_t *entry = hash->table[i]; while (entry) { zip_hash_entry_t *next = entry->next; zip_uint32_t new_index = entry->hash_value % new_size; entry->next = new_table[new_index]; new_table[new_index] = entry; entry = next; } } } free(hash->table); hash->table = new_table; hash->table_size = new_size; return true; } static zip_uint32_t size_for_capacity(zip_uint64_t capacity) { double needed_size = capacity / HASH_MAX_FILL; zip_uint32_t v; if (needed_size > ZIP_UINT32_MAX) { v = ZIP_UINT32_MAX; } else { v = (zip_uint32_t)needed_size; } if (v > HASH_MAX_SIZE) { return HASH_MAX_SIZE; } /* From Bit Twiddling Hacks by Sean Eron Anderson (http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2). */ v--; v |= v >> 1; v |= v >> 2; v |= v >> 4; v |= v >> 8; v |= v >> 16; v++; return v; } zip_hash_t * _zip_hash_new(zip_error_t *error) { zip_hash_t *hash; if ((hash = (zip_hash_t *)malloc(sizeof(zip_hash_t))) == NULL) { zip_error_set(error, ZIP_ER_MEMORY, 0); return NULL; } hash->table_size = 0; hash->nentries = 0; hash->table = NULL; return hash; } void _zip_hash_free(zip_hash_t *hash) { zip_uint32_t i; if (hash == NULL) { return; } if (hash->table != NULL) { for (i = 0; i < hash->table_size; i++) { if (hash->table[i] != NULL) { free_list(hash->table[i]); } } free(hash->table); } free(hash); } /* insert into hash, return error on existence or memory issues */ bool _zip_hash_add(zip_hash_t *hash, const zip_uint8_t *name, zip_uint64_t index, zip_flags_t flags, zip_error_t *error) { zip_uint32_t hash_value, table_index; zip_hash_entry_t *entry; if (hash == NULL || name == NULL || index > ZIP_INT64_MAX) { zip_error_set(error, ZIP_ER_INVAL, 0); return false; } if (hash->table_size == 0) { if (!hash_resize(hash, HASH_MIN_SIZE, error)) { return false; } } hash_value = hash_string(name); table_index = hash_value % hash->table_size; for (entry = hash->table[table_index]; entry != NULL; entry = entry->next) { if (entry->hash_value == hash_value && strcmp((const char *)name, (const char *)entry->name) == 0) { if (((flags & ZIP_FL_UNCHANGED) && entry->orig_index != -1) || entry->current_index != -1) { zip_error_set(error, ZIP_ER_EXISTS, 0); return false; } else { break; } } } if (entry == NULL) { if ((entry = (zip_hash_entry_t *)malloc(sizeof(zip_hash_entry_t))) == NULL) { zip_error_set(error, ZIP_ER_MEMORY, 0); return false; } entry->name = name; entry->next = hash->table[table_index]; hash->table[table_index] = entry; entry->hash_value = hash_value; entry->orig_index = -1; hash->nentries++; if (hash->nentries > hash->table_size * HASH_MAX_FILL && hash->table_size < HASH_MAX_SIZE) { if (!hash_resize(hash, hash->table_size * 2, error)) { return false; } } } if (flags & ZIP_FL_UNCHANGED) { entry->orig_index = (zip_int64_t)index; } entry->current_index = (zip_int64_t)index; return true; } /* remove entry from hash, error if not found */ bool _zip_hash_delete(zip_hash_t *hash, const zip_uint8_t *name, zip_error_t *error) { zip_uint32_t hash_value, index; zip_hash_entry_t *entry, *previous; if (hash == NULL || name == NULL) { zip_error_set(error, ZIP_ER_INVAL, 0); return false; } if (hash->nentries > 0) { hash_value = hash_string(name); index = hash_value % hash->table_size; previous = NULL; entry = hash->table[index]; while (entry) { if (entry->hash_value == hash_value && strcmp((const char *)name, (const char *)entry->name) == 0) { if (entry->orig_index == -1) { if (previous) { previous->next = entry->next; } else { hash->table[index] = entry->next; } free(entry); hash->nentries--; if (hash->nentries < hash->table_size * HASH_MIN_FILL && hash->table_size > HASH_MIN_SIZE) { if (!hash_resize(hash, hash->table_size / 2, error)) { return false; } } } else { entry->current_index = -1; } return true; } previous = entry; entry = entry->next; } } zip_error_set(error, ZIP_ER_NOENT, 0); return false; } /* find value for entry in hash, -1 if not found */ zip_int64_t _zip_hash_lookup(zip_hash_t *hash, const zip_uint8_t *name, zip_flags_t flags, zip_error_t *error) { zip_uint32_t hash_value, index; zip_hash_entry_t *entry; if (hash == NULL || name == NULL) { zip_error_set(error, ZIP_ER_INVAL, 0); return -1; } if (hash->nentries > 0) { hash_value = hash_string(name); index = hash_value % hash->table_size; for (entry = hash->table[index]; entry != NULL; entry = entry->next) { if (strcmp((const char *)name, (const char *)entry->name) == 0) { if (flags & ZIP_FL_UNCHANGED) { if (entry->orig_index != -1) { return entry->orig_index; } } else { if (entry->current_index != -1) { return entry->current_index; } } break; } } } zip_error_set(error, ZIP_ER_NOENT, 0); return -1; } bool _zip_hash_reserve_capacity(zip_hash_t *hash, zip_uint64_t capacity, zip_error_t *error) { zip_uint32_t new_size; if (capacity == 0) { return true; } new_size = size_for_capacity(capacity); if (new_size <= hash->table_size) { return true; } if (!hash_resize(hash, new_size, error)) { return false; } return true; } bool _zip_hash_revert(zip_hash_t *hash, zip_error_t *error) { zip_uint32_t i; zip_hash_entry_t *entry, *previous; for (i = 0; i < hash->table_size; i++) { previous = NULL; entry = hash->table[i]; while (entry) { if (entry->orig_index == -1) { zip_hash_entry_t *p; if (previous) { previous->next = entry->next; } else { hash->table[i] = entry->next; } p = entry; entry = entry->next; /* previous does not change */ free(p); hash->nentries--; } else { entry->current_index = entry->orig_index; previous = entry; entry = entry->next; } } } if (hash->nentries < hash->table_size * HASH_MIN_FILL && hash->table_size > HASH_MIN_SIZE) { zip_uint32_t new_size = hash->table_size / 2; while (hash->nentries < new_size * HASH_MIN_FILL && new_size > HASH_MIN_SIZE) { new_size /= 2; } if (!hash_resize(hash, new_size, error)) { return false; } } return true; } ================================================ FILE: external/libzip/lib/zip_io_util.c ================================================ /* zip_io_util.c -- I/O helper functions Copyright (C) 1999-2024 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include "zipint.h" int _zip_read(zip_source_t *src, zip_uint8_t *b, zip_uint64_t length, zip_error_t *error) { zip_int64_t n; if (length > ZIP_INT64_MAX) { zip_error_set(error, ZIP_ER_INTERNAL, 0); return -1; } if ((n = zip_source_read(src, b, length)) < 0) { zip_error_set_from_source(error, src); return -1; } if (n < (zip_int64_t)length) { zip_error_set(error, ZIP_ER_EOF, 0); return -1; } return 0; } zip_uint8_t * _zip_read_data(zip_buffer_t *buffer, zip_source_t *src, size_t length, bool nulp, zip_error_t *error) { zip_uint8_t *r; if (length == 0 && !nulp) { return NULL; } r = (zip_uint8_t *)malloc(length + (nulp ? 1 : 0)); if (r == NULL) { zip_error_set(error, ZIP_ER_MEMORY, 0); return NULL; } if (buffer) { zip_uint8_t *data = _zip_buffer_get(buffer, length); if (data == NULL) { zip_error_set(error, ZIP_ER_MEMORY, 0); free(r); return NULL; } (void)memcpy_s(r, length, data, length); } else { if (_zip_read(src, r, length, error) < 0) { free(r); return NULL; } } if (nulp) { zip_uint8_t *o; /* replace any in-string NUL characters with spaces */ r[length] = 0; for (o = r; o < r + length; o++) if (*o == '\0') *o = ' '; } return r; } zip_string_t * _zip_read_string(zip_buffer_t *buffer, zip_source_t *src, zip_uint16_t len, bool nulp, zip_error_t *error) { zip_uint8_t *raw; zip_string_t *s; if ((raw = _zip_read_data(buffer, src, len, nulp, error)) == NULL) return NULL; s = _zip_string_new(raw, len, ZIP_FL_ENC_GUESS, error); free(raw); return s; } int _zip_write(zip_t *za, const void *data, zip_uint64_t length) { zip_int64_t n; if ((n = zip_source_write(za->src, data, length)) < 0) { zip_error_set_from_source(&za->error, za->src); return -1; } if ((zip_uint64_t)n != length) { zip_error_set(&za->error, ZIP_ER_WRITE, EINTR); return -1; } if (za->write_crc != NULL) { zip_uint64_t position = 0; while (position < length) { zip_uint64_t nn = ZIP_MIN(UINT_MAX, length - position); *za->write_crc = (zip_uint32_t)crc32(*za->write_crc, (const Bytef *)data + position, (uInt)nn); position += nn; } } return 0; } ================================================ FILE: external/libzip/lib/zip_libzip_version.c ================================================ /* zip_libzip_version.c -- return run-time version of library Copyright (C) 2017-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "zipint.h" ZIP_EXTERN const char * zip_libzip_version(void) { return LIBZIP_VERSION; } ================================================ FILE: external/libzip/lib/zip_memdup.c ================================================ /* zip_memdup.c -- internal zip function, "strdup" with len Copyright (C) 1999-2024 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include "zipint.h" void * _zip_memdup(const void *mem, size_t len, zip_error_t *error) { void *ret; if (len == 0) return NULL; ret = malloc(len); if (ret == NULL) { zip_error_set(error, ZIP_ER_MEMORY, 0); return NULL; } (void)memcpy_s(ret, len, mem, len); return ret; } ================================================ FILE: external/libzip/lib/zip_name_locate.c ================================================ /* zip_name_locate.c -- get index by name Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #ifdef HAVE_STRINGS_H #include #endif #include "zipint.h" ZIP_EXTERN zip_int64_t zip_name_locate(zip_t *za, const char *fname, zip_flags_t flags) { return _zip_name_locate(za, fname, flags, &za->error); } zip_int64_t _zip_name_locate(zip_t *za, const char *fname, zip_flags_t flags, zip_error_t *error) { int (*cmp)(const char *, const char *); size_t fname_length; zip_string_t *str = NULL; const char *fn, *p; zip_uint64_t i; if (za == NULL) { return -1; } if (fname == NULL) { zip_error_set(error, ZIP_ER_INVAL, 0); return -1; } fname_length = strlen(fname); if (fname_length > ZIP_UINT16_MAX) { zip_error_set(error, ZIP_ER_INVAL, 0); return -1; } if ((flags & (ZIP_FL_ENC_UTF_8 | ZIP_FL_ENC_RAW)) == 0 && fname[0] != '\0') { if ((str = _zip_string_new((const zip_uint8_t *)fname, (zip_uint16_t)strlen(fname), flags, error)) == NULL) { return -1; } if ((fname = (const char *)_zip_string_get(str, NULL, 0, error)) == NULL) { _zip_string_free(str); return -1; } } if (flags & (ZIP_FL_NOCASE | ZIP_FL_NODIR | ZIP_FL_ENC_RAW | ZIP_FL_ENC_STRICT)) { /* can't use hash table */ cmp = (flags & ZIP_FL_NOCASE) ? strcasecmp : strcmp; for (i = 0; i < za->nentry; i++) { fn = _zip_get_name(za, i, flags, error); /* newly added (partially filled) entry or error */ if (fn == NULL) continue; if (flags & ZIP_FL_NODIR) { p = strrchr(fn, '/'); if (p) fn = p + 1; } if (cmp(fname, fn) == 0) { _zip_error_clear(error); _zip_string_free(str); return (zip_int64_t)i; } } zip_error_set(error, ZIP_ER_NOENT, 0); _zip_string_free(str); return -1; } else { zip_int64_t ret = _zip_hash_lookup(za->names, (const zip_uint8_t *)fname, flags, error); _zip_string_free(str); return ret; } } ================================================ FILE: external/libzip/lib/zip_new.c ================================================ /* zip_new.c -- create and init struct zip Copyright (C) 1999-2024 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include "zipint.h" /* _zip_new: creates a new zipfile struct, and sets the contents to zero; returns the new struct. */ zip_t * _zip_new(zip_error_t *error) { zip_t *za; za = (zip_t *)malloc(sizeof(struct zip)); if (za == NULL) { zip_error_set(error, ZIP_ER_MEMORY, 0); return NULL; } if ((za->names = _zip_hash_new(error)) == NULL) { free(za); return NULL; } za->src = NULL; za->open_flags = 0; zip_error_init(&za->error); za->flags = za->ch_flags = 0; za->default_password = NULL; za->comment_orig = za->comment_changes = NULL; za->comment_changed = 0; za->nentry = za->nentry_alloc = 0; za->entry = NULL; za->nopen_source = za->nopen_source_alloc = 0; za->open_source = NULL; za->progress = NULL; za->torrent_mtime = 0; return za; } ================================================ FILE: external/libzip/lib/zip_open.c ================================================ /* zip_open.c -- open zip archive by name Copyright (C) 1999-2024 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include "zipint.h" typedef enum { EXISTS_ERROR = -1, EXISTS_NOT = 0, EXISTS_OK } exists_t; typedef enum { CDIR_OK, CDIR_INVALID, CDIR_NOT_FOUND } cdir_status_t; static bool check_eocd(zip_cdir_t *cd, unsigned int flags, zip_error_t *error); static bool check_magic(zip_uint64_t offset, zip_buffer_t *buffer, zip_uint64_t buffer_offset, zip_source_t *src, const char* magic); static zip_t *_zip_allocate_new(zip_source_t *src, unsigned int flags, zip_error_t *error); static zip_int64_t _zip_checkcons(zip_t *za, zip_cdir_t *cdir, zip_error_t *error); static void zip_check_torrentzip(zip_t *za, const zip_cdir_t *cdir); static zip_cdir_t *_zip_find_central_dir(zip_t *za, zip_uint64_t len); static exists_t _zip_file_exists(zip_source_t *src, zip_error_t *error); static int _zip_headercomp(const zip_dirent_t *, const zip_dirent_t *); static bool _zip_read_cdir(zip_t *za, zip_buffer_t *buffer, zip_uint64_t buf_offset, zip_cdir_t **cdirp, zip_error_t *error); static zip_cdir_t *_zip_read_eocd(zip_buffer_t *buffer, zip_uint64_t buf_offset, zip_error_t *error); static cdir_status_t _zip_read_eocd64(zip_cdir_t *cdir, zip_source_t *src, zip_buffer_t *buffer, zip_uint64_t buf_offset, unsigned int flags, zip_error_t *error); static const unsigned char *find_eocd(zip_buffer_t *buffer, const unsigned char *last); ZIP_EXTERN zip_t * zip_open(const char *fn, int _flags, int *zep) { zip_t *za; zip_source_t *src; struct zip_error error; zip_error_init(&error); if ((src = zip_source_file_create(fn, 0, -1, &error)) == NULL) { _zip_set_open_error(zep, &error, 0); zip_error_fini(&error); return NULL; } if ((za = zip_open_from_source(src, _flags, &error)) == NULL) { zip_source_free(src); _zip_set_open_error(zep, &error, 0); zip_error_fini(&error); return NULL; } zip_error_fini(&error); return za; } ZIP_EXTERN zip_t * zip_open_from_source(zip_source_t *src, int _flags, zip_error_t *error) { unsigned int flags; zip_int64_t supported; exists_t exists; if (_flags < 0 || src == NULL) { zip_error_set(error, ZIP_ER_INVAL, 0); return NULL; } flags = (unsigned int)_flags; supported = zip_source_supports(src); if ((supported & ZIP_SOURCE_SUPPORTS_SEEKABLE) != ZIP_SOURCE_SUPPORTS_SEEKABLE) { zip_error_set(error, ZIP_ER_OPNOTSUPP, 0); return NULL; } if ((supported & ZIP_SOURCE_SUPPORTS_WRITABLE) != ZIP_SOURCE_SUPPORTS_WRITABLE) { flags |= ZIP_RDONLY; } if ((flags & (ZIP_RDONLY | ZIP_TRUNCATE)) == (ZIP_RDONLY | ZIP_TRUNCATE)) { zip_error_set(error, ZIP_ER_RDONLY, 0); return NULL; } exists = _zip_file_exists(src, error); switch (exists) { case EXISTS_ERROR: return NULL; case EXISTS_NOT: if ((flags & ZIP_CREATE) == 0) { zip_error_set(error, ZIP_ER_NOENT, 0); return NULL; } return _zip_allocate_new(src, flags, error); default: { zip_t *za; if (flags & ZIP_EXCL) { zip_error_set(error, ZIP_ER_EXISTS, 0); return NULL; } if (zip_source_open(src) < 0) { zip_error_set_from_source(error, src); return NULL; } if (flags & ZIP_TRUNCATE) { za = _zip_allocate_new(src, flags, error); } else { /* ZIP_CREATE gets ignored if file exists and not ZIP_EXCL, just like open() */ za = _zip_open(src, flags, error); } if (za == NULL) { zip_source_close(src); return NULL; } return za; } } } static bool _is_truncated_zip(zip_source_t *src) { unsigned char data[4]; /* check if the source is a truncated zip archive: true if yes, no if not or can't be determined */ if (zip_source_seek(src, 0, SEEK_SET) < 0) { return false; } if (zip_source_read(src, data, 4) != 4) { return false; } if (memcmp(data, LOCAL_MAGIC, 4) == 0) { /* file starts with a ZIP local header signature */ return true; } return false; } zip_t * _zip_open(zip_source_t *src, unsigned int flags, zip_error_t *error) { zip_t *za; zip_cdir_t *cdir; struct zip_stat st; zip_uint64_t len, idx; zip_stat_init(&st); if (zip_source_stat(src, &st) < 0) { zip_error_set_from_source(error, src); return NULL; } if ((st.valid & ZIP_STAT_SIZE) == 0) { zip_error_set(error, ZIP_ER_SEEK, EOPNOTSUPP); return NULL; } len = st.size; if ((za = _zip_allocate_new(src, flags, error)) == NULL) { return NULL; } /* treat empty files as empty archives */ if (len == 0 && zip_source_accept_empty(src)) { return za; } if ((cdir = _zip_find_central_dir(za, len)) == NULL) { _zip_error_copy(error, &za->error); if (zip_error_code_zip(&za->error) == ZIP_ER_NOZIP) { /* not a zip - find out if it's truncated */ if (_is_truncated_zip(src)) { zip_error_set(error, ZIP_ER_TRUNCATED_ZIP, 0); } } /* keep src so discard does not get rid of it */ zip_source_keep(src); zip_discard(za); return NULL; } za->entry = cdir->entry; za->nentry = cdir->nentry; za->nentry_alloc = cdir->nentry_alloc; zip_check_torrentzip(za, cdir); if (ZIP_IS_TORRENTZIP(za)) { /* Torrentzip uses the archive comment to detect changes by tools that are not torrentzip aware. */ _zip_string_free(cdir->comment); } else { za->comment_orig = cdir->comment; } free(cdir); _zip_hash_reserve_capacity(za->names, za->nentry, &za->error); for (idx = 0; idx < za->nentry; idx++) { const zip_uint8_t *name = _zip_string_get(za->entry[idx].orig->filename, NULL, 0, error); if (name == NULL) { /* keep src so discard does not get rid of it */ zip_source_keep(src); zip_discard(za); return NULL; } if (_zip_hash_add(za->names, name, idx, ZIP_FL_UNCHANGED, &za->error) == false) { if (za->error.zip_err != ZIP_ER_EXISTS || (flags & ZIP_CHECKCONS)) { _zip_error_copy(error, &za->error); /* keep src so discard does not get rid of it */ zip_source_keep(src); zip_discard(za); return NULL; } } } za->ch_flags = za->flags; return za; } void _zip_set_open_error(int *zep, const zip_error_t *err, int ze) { if (err) { ze = zip_error_code_zip(err); switch (zip_error_system_type(err)) { case ZIP_ET_SYS: case ZIP_ET_LIBZIP: errno = zip_error_code_system(err); break; default: break; } } if (zep) *zep = ze; } /* _zip_readcdir: tries to find a valid end-of-central-directory at the beginning of buf, and then the corresponding central directory entries. Returns a struct zip_cdir which contains the central directory entries, or NULL if unsuccessful. */ static bool _zip_read_cdir(zip_t *za, zip_buffer_t *buffer, zip_uint64_t buf_offset, zip_cdir_t **cdirp, zip_error_t *error) { zip_cdir_t *cd; zip_uint16_t comment_len; zip_uint64_t i, left; zip_uint64_t eocd_offset = _zip_buffer_offset(buffer); zip_buffer_t *cd_buffer; bool eocd64_found = false; *cdirp = NULL; if ((cd = _zip_read_eocd(buffer, buf_offset, error)) == NULL) { return false; } if (eocd_offset >= EOCD64LOCLEN && memcmp(_zip_buffer_data(buffer) + eocd_offset - EOCD64LOCLEN, EOCD64LOC_MAGIC, 4) == 0) { eocd64_found = true; _zip_buffer_set_offset(buffer, eocd_offset - EOCD64LOCLEN); switch (_zip_read_eocd64(cd, za->src, buffer, buf_offset, za->flags, error)) { case CDIR_OK: break; case CDIR_INVALID: _zip_cdir_free(cd); return true; case CDIR_NOT_FOUND: _zip_cdir_free(cd); return false; } } if ((cd->eocd_disk != 0 || cd->this_disk != 0) && !eocd64_found && cd->eocd_disk != cd->this_disk) { /* If the central directory doesn't start on this disk, we can't check that offset is valid. Check as much as we can instead. */ if (cd->this_disk < cd->eocd_disk) { /* Disks before the start of the central directory don't contain an EOCD. */ _zip_cdir_free(cd); return false; } if (cd->size <= cd->eocd_offset) { /* The complete central directory would fit on this disk. */ _zip_cdir_free(cd); return false; } } if (!eocd64_found) { if (cd->this_disk == 0 && cd->eocd_disk == 0 && cd->eocd_offset == 0 && cd->offset == 0 && cd->num_entries == 0) { /* An empty archive doesn't contain central directory entries. */ } else if (!check_magic(cd->offset, buffer, buf_offset, za->src, CENTRAL_MAGIC)) { _zip_cdir_free(cd); return false; } } /* We accept this EOCD as valid and won't search for an earlier one if it is unusable. */ if (!check_eocd(cd, za->flags, error)) { _zip_cdir_free(cd); return true; } _zip_buffer_set_offset(buffer, eocd_offset + 20); comment_len = _zip_buffer_get_16(buffer); if (cd->offset + cd->size > buf_offset + eocd_offset) { /* cdir spans past EOCD record */ zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_CDIR_OVERLAPS_EOCD); _zip_cdir_free(cd); return true; } if (comment_len || (za->open_flags & ZIP_CHECKCONS)) { zip_uint64_t tail_len; _zip_buffer_set_offset(buffer, eocd_offset + EOCDLEN); tail_len = _zip_buffer_left(buffer); if (tail_len != comment_len) { if (za->open_flags & ZIP_CHECKCONS) { zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_COMMENT_LENGTH_INVALID); _zip_cdir_free(cd); return true; } if (tail_len < comment_len) { comment_len = tail_len; } } if (comment_len) { if ((cd->comment = _zip_string_new(_zip_buffer_get(buffer, comment_len), comment_len, ZIP_FL_ENC_GUESS, error)) == NULL) { _zip_cdir_free(cd); return true; } } } if (cd->offset >= buf_offset) { zip_uint8_t *data; /* if buffer already read in, use it */ _zip_buffer_set_offset(buffer, cd->offset - buf_offset); if ((data = _zip_buffer_get(buffer, cd->size)) == NULL) { zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_CDIR_LENGTH_INVALID); _zip_cdir_free(cd); return true; } if ((cd_buffer = _zip_buffer_new(data, cd->size)) == NULL) { zip_error_set(error, ZIP_ER_MEMORY, 0); _zip_cdir_free(cd); return true; } } else { cd_buffer = NULL; if (zip_source_seek(za->src, (zip_int64_t)cd->offset, SEEK_SET) < 0) { zip_error_set_from_source(error, za->src); _zip_cdir_free(cd); return true; } /* possible consistency check: cd->offset = len-(cd->size+cd->comment_len+EOCDLEN) ? */ if (zip_source_tell(za->src) != (zip_int64_t)cd->offset) { zip_error_set(error, ZIP_ER_NOZIP, 0); _zip_cdir_free(cd); return true; } } if (!_zip_cdir_grow(cd, cd->num_entries, error)) { _zip_cdir_free(cd); _zip_buffer_free(cd_buffer); return true; } left = (zip_uint64_t)cd->size; i = 0; while (left > 0) { bool grown = false; zip_int64_t entry_size; if (i == cd->nentry) { /* InfoZIP has a hack to avoid using Zip64: it stores nentries % 0x10000 */ /* This hack isn't applicable if we're using Zip64, or if there is no central directory entry following. */ if (cd->is_zip64 || left < CDENTRYSIZE) { break; } if (!_zip_cdir_grow(cd, 0x10000, error)) { _zip_cdir_free(cd); _zip_buffer_free(cd_buffer); return true; } grown = true; } if ((cd->entry[i].orig = _zip_dirent_new()) == NULL || (entry_size = _zip_dirent_read(cd->entry[i].orig, za->src, cd_buffer, false, 0, za->open_flags & ZIP_CHECKCONS, error)) < 0) { if (zip_error_code_zip(error) == ZIP_ER_INCONS) { zip_error_set(error, ZIP_ER_INCONS, ADD_INDEX_TO_DETAIL(zip_error_code_system(error), i)); } else if (grown && zip_error_code_zip(error) == ZIP_ER_NOZIP) { zip_error_set(error, ZIP_ER_INCONS, MAKE_DETAIL_WITH_INDEX(ZIP_ER_DETAIL_CDIR_ENTRY_INVALID, i)); } _zip_cdir_free(cd); _zip_buffer_free(cd_buffer); return true; } i++; left -= (zip_uint64_t)entry_size; } /* If we didn't fill all we grew, cd->num_entries was wrong. */ if (i != cd->nentry || left > 0) { zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_CDIR_WRONG_ENTRIES_COUNT); _zip_buffer_free(cd_buffer); _zip_cdir_free(cd); return true; } if (za->open_flags & ZIP_CHECKCONS) { bool ok; if (cd_buffer) { ok = _zip_buffer_eof(cd_buffer); } else { zip_int64_t offset = zip_source_tell(za->src); if (offset < 0) { zip_error_set_from_source(error, za->src); _zip_cdir_free(cd); return true; } ok = ((zip_uint64_t)offset == cd->offset + cd->size); } if (!ok) { zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_CDIR_LENGTH_INVALID); _zip_buffer_free(cd_buffer); _zip_cdir_free(cd); return true; } } _zip_buffer_free(cd_buffer); *cdirp = cd; return true; } static bool check_magic(zip_uint64_t offset, zip_buffer_t *buffer, zip_uint64_t buffer_offset, zip_source_t *src, const char* magic) { if (buffer_offset <= offset) { zip_uint8_t* data; if (_zip_buffer_set_offset(buffer, offset - buffer_offset) < 0 || (data = _zip_buffer_get(buffer, MAGIC_LEN)) == NULL) { return false; } return memcmp(data, magic, MAGIC_LEN) == 0; } else { zip_uint8_t data[MAGIC_LEN]; if (zip_source_seek(src, offset, SEEK_SET) < 0 || zip_source_read(src, data, MAGIC_LEN) != MAGIC_LEN) { return false; } return memcmp(data, magic, MAGIC_LEN) == 0; } } /* _zip_checkcons: Checks the consistency of the central directory by comparing central directory entries with local headers and checking for plausible file and header offsets. Returns -1 if not plausible, else the difference between the lowest and the highest fileposition reached */ static zip_int64_t _zip_checkcons(zip_t *za, zip_cdir_t *cd, zip_error_t *error) { zip_uint64_t i; zip_uint64_t min, max, j; struct zip_dirent temp; int detail; _zip_dirent_init(&temp); if (cd->nentry) { max = cd->entry[0].orig->offset; min = cd->entry[0].orig->offset; } else min = max = 0; for (i = 0; i < cd->nentry; i++) { if (cd->entry[i].orig->offset < min) min = cd->entry[i].orig->offset; if (min > (zip_uint64_t)cd->offset) { zip_error_set(error, ZIP_ER_NOZIP, 0); return -1; } j = cd->entry[i].orig->offset + cd->entry[i].orig->comp_size + _zip_string_length(cd->entry[i].orig->filename) + LENTRYSIZE; if (j > max) max = j; if (max > (zip_uint64_t)cd->offset) { zip_error_set(error, ZIP_ER_NOZIP, 0); return -1; } if (zip_source_seek(za->src, (zip_int64_t)cd->entry[i].orig->offset, SEEK_SET) < 0) { zip_error_set_from_source(error, za->src); return -1; } if (_zip_dirent_read(&temp, za->src, NULL, true, cd->entry[i].orig->comp_size, true, error) == -1) { if (zip_error_code_zip(error) == ZIP_ER_INCONS) { zip_error_set(error, ZIP_ER_INCONS, ADD_INDEX_TO_DETAIL(zip_error_code_system(error), i)); } _zip_dirent_finalize(&temp); return -1; } if (_zip_headercomp(cd->entry[i].orig, &temp) != 0) { zip_error_set(error, ZIP_ER_INCONS, MAKE_DETAIL_WITH_INDEX(ZIP_ER_DETAIL_ENTRY_HEADER_MISMATCH, i)); _zip_dirent_finalize(&temp); return -1; } cd->entry[i].orig->extra_fields = _zip_ef_merge(cd->entry[i].orig->extra_fields, temp.extra_fields); cd->entry[i].orig->local_extra_fields_read = 1; temp.extra_fields = NULL; _zip_dirent_finalize(&temp); if ((detail = zip_dirent_check_consistency(cd->entry[i].orig)) != 0) { zip_error_set(error, ZIP_ER_INCONS, MAKE_DETAIL_WITH_INDEX(detail, i)); return -1; } } return (max - min) < ZIP_INT64_MAX ? (zip_int64_t)(max - min) : ZIP_INT64_MAX; } /* _zip_headercomp: compares a central directory entry and a local file header Return 0 if they are consistent, -1 if not. */ static int _zip_headercomp(const zip_dirent_t *central, const zip_dirent_t *local) { if ((central->version_needed < local->version_needed) #if 0 /* some zip-files have different values in local and global headers for the bitflags */ || (central->bitflags != local->bitflags) #endif || (central->comp_method != local->comp_method) || (central->last_mod.time != local->last_mod.time) || (central->last_mod.date != local->last_mod.date) || !_zip_string_equal(central->filename, local->filename)) return -1; if ((central->crc != local->crc) || (central->comp_size != local->comp_size) || (central->uncomp_size != local->uncomp_size)) { /* InfoZip stores valid values in local header even when data descriptor is used. This is in violation of the appnote. macOS Archive sets the compressed size even when data descriptor is used ( but not the others), also in violation of the appnote. */ /* if data descriptor is not used, the values must match */ if ((local->bitflags & ZIP_GPBF_DATA_DESCRIPTOR) == 0) { return -1; } /* when using a data descriptor, the local header value must be zero or match */ if ((local->crc != 0 && central->crc != local->crc) || (local->comp_size != 0 && central->comp_size != local->comp_size) || (local->uncomp_size != 0 && central->uncomp_size != local->uncomp_size)) { return -1; } } return 0; } static zip_t * _zip_allocate_new(zip_source_t *src, unsigned int flags, zip_error_t *error) { zip_t *za; if ((za = _zip_new(error)) == NULL) { return NULL; } za->src = src; za->open_flags = flags; za->flags = 0; za->ch_flags = 0; za->write_crc = NULL; if (flags & ZIP_RDONLY) { za->flags |= ZIP_AFL_RDONLY; za->ch_flags |= ZIP_AFL_RDONLY; } return za; } /* * tests for file existence */ static exists_t _zip_file_exists(zip_source_t *src, zip_error_t *error) { struct zip_stat st; zip_stat_init(&st); if (zip_source_stat(src, &st) != 0) { zip_error_t *src_error = zip_source_error(src); if (zip_error_code_zip(src_error) == ZIP_ER_READ && zip_error_code_system(src_error) == ENOENT) { return EXISTS_NOT; } _zip_error_copy(error, src_error); return EXISTS_ERROR; } return EXISTS_OK; } static zip_cdir_t * _zip_find_central_dir(zip_t *za, zip_uint64_t len) { zip_cdir_t *cdir; const zip_uint8_t *match; zip_int64_t buf_offset; zip_uint64_t buflen; zip_error_t error; zip_buffer_t *buffer; if (len < EOCDLEN) { zip_error_set(&za->error, ZIP_ER_NOZIP, 0); return NULL; } buflen = (len < CDBUFSIZE ? len : CDBUFSIZE); if (zip_source_seek(za->src, -(zip_int64_t)buflen, SEEK_END) < 0) { zip_error_t *src_error = zip_source_error(za->src); if (zip_error_code_zip(src_error) != ZIP_ER_SEEK || zip_error_code_system(src_error) != EFBIG) { /* seek before start of file on my machine */ _zip_error_copy(&za->error, src_error); return NULL; } } if ((buf_offset = zip_source_tell(za->src)) < 0) { zip_error_set_from_source(&za->error, za->src); return NULL; } if ((buffer = _zip_buffer_new_from_source(za->src, buflen, NULL, &za->error)) == NULL) { return NULL; } cdir = NULL; if (buflen >= CDBUFSIZE) { /* EOCD64 locator is before EOCD, so leave place for it */ _zip_buffer_set_offset(buffer, EOCD64LOCLEN); } zip_error_set(&error, ZIP_ER_NOZIP, 0); match = NULL; while ((match = find_eocd(buffer, match)) != NULL) { _zip_buffer_set_offset(buffer, (zip_uint64_t)(match - _zip_buffer_data(buffer))); if (_zip_read_cdir(za, buffer, (zip_uint64_t)buf_offset, &cdir, &error)) { if (cdir != NULL && (za->open_flags & ZIP_CHECKCONS) && _zip_checkcons(za, cdir, &error) < 0) { _zip_cdir_free(cdir); cdir = NULL; } break; } } _zip_buffer_free(buffer); if (cdir == NULL) { _zip_error_copy(&za->error, &error); } return cdir; } static const unsigned char * find_eocd(zip_buffer_t *buffer, const unsigned char *last) { const unsigned char *data = _zip_buffer_data(buffer); const unsigned char *p; if (last == NULL) { last = data + _zip_buffer_size(buffer) - MAGIC_LEN; } else if (last == _zip_buffer_data(buffer)) { return NULL; } else { last -= 1; } for (p = last; p >= data; p -= 1) { if (*p == EOCD_MAGIC[0]) { if (memcmp(p, EOCD_MAGIC, MAGIC_LEN) == 0) { return p; } } } return NULL; } static zip_cdir_t * _zip_read_eocd(zip_buffer_t *buffer, zip_uint64_t buf_offset, zip_error_t *error) { zip_cdir_t *cd; if (_zip_buffer_left(buffer) < EOCDLEN) { zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_EOCD_LENGTH_INVALID); return NULL; } if ((cd = _zip_cdir_new(error)) == NULL) { return NULL; } cd->eocd_offset = buf_offset + _zip_buffer_offset(buffer); /* This function is only called where EOCD magic was found, so no need to check that here. */ _zip_buffer_skip(buffer, MAGIC_LEN); cd->is_zip64 = false; cd->this_disk = _zip_buffer_get_16(buffer); cd->eocd_disk = _zip_buffer_get_16(buffer); /* number of cdir-entries on this disk */ cd->disk_entries = _zip_buffer_get_16(buffer); /* number of cdir-entries */ cd->num_entries = _zip_buffer_get_16(buffer); cd->size = _zip_buffer_get_32(buffer); cd->offset = _zip_buffer_get_32(buffer); return cd; } static bool check_eocd(zip_cdir_t *cd, unsigned int flags, zip_error_t *error) { if (cd->disk_entries != cd->num_entries || cd->this_disk != 0 || cd->eocd_disk != 0) { zip_error_set(error, ZIP_ER_MULTIDISK, 0); return false; } if (cd->offset + cd->size < cd->offset) { zip_error_set(error, ZIP_ER_SEEK, EFBIG); return false; } if ((flags & ZIP_CHECKCONS) && cd->offset + cd->size != cd->eocd_offset) { zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_CDIR_LENGTH_INVALID); return false; } return true; } cdir_status_t _zip_read_eocd64(zip_cdir_t *cdir, zip_source_t *src, zip_buffer_t *buffer, zip_uint64_t buf_offset, unsigned int flags, zip_error_t *error) { zip_uint64_t offset; zip_uint8_t eocd[EOCD64LEN]; zip_uint64_t eocd_offset; zip_uint64_t size, nentry, i, eocdloc_offset; bool free_buffer; zip_uint32_t num_disks, eocd_disk, this_disk; eocdloc_offset = _zip_buffer_offset(buffer); _zip_buffer_get(buffer, 4); /* magic already verified */ eocd_disk = _zip_buffer_get_32(buffer); eocd_offset = _zip_buffer_get_64(buffer); num_disks = _zip_buffer_get_32(buffer); if (!check_magic(eocd_offset, buffer, buf_offset, src, EOCD64_MAGIC)) { return CDIR_NOT_FOUND; } if (num_disks != 1) { zip_error_set(error, ZIP_ER_MULTIDISK, 0); return CDIR_INVALID; } /* valid seek value for start of EOCD */ if (eocd_offset > ZIP_INT64_MAX) { zip_error_set(error, ZIP_ER_SEEK, EFBIG); return CDIR_INVALID; } /* does EOCD fit before EOCD locator? */ if (eocd_offset + EOCD64LEN > eocdloc_offset + buf_offset) { zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_EOCD64_OVERLAPS_EOCD); return CDIR_INVALID; } /* make sure current position of buffer is beginning of EOCD */ if (eocd_offset >= buf_offset && eocd_offset + EOCD64LEN <= buf_offset + _zip_buffer_size(buffer)) { _zip_buffer_set_offset(buffer, eocd_offset - buf_offset); free_buffer = false; } else { if (zip_source_seek(src, (zip_int64_t)eocd_offset, SEEK_SET) < 0) { zip_error_set_from_source(error, src); return CDIR_INVALID; } if ((buffer = _zip_buffer_new_from_source(src, EOCD64LEN, eocd, error)) == NULL) { return CDIR_INVALID; } free_buffer = true; } if (memcmp(_zip_buffer_get(buffer, 4), EOCD64_MAGIC, 4) != 0) { zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_EOCD64_WRONG_MAGIC); if (free_buffer) { _zip_buffer_free(buffer); } return CDIR_INVALID; } /* size of EOCD */ size = _zip_buffer_get_64(buffer); /* is there a hole between EOCD and EOCD locator, or do they overlap? */ if ((flags & ZIP_CHECKCONS) && size + eocd_offset + 12 != buf_offset + eocdloc_offset) { zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_EOCD64_OVERLAPS_EOCD); if (free_buffer) { _zip_buffer_free(buffer); } return CDIR_INVALID; } _zip_buffer_get(buffer, 4); /* skip version made by/needed */ this_disk = _zip_buffer_get_32(buffer); if (_zip_buffer_get_32(buffer) != eocd_disk) { zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_EOCD64_LOCATOR_MISMATCH); if (free_buffer) { _zip_buffer_free(buffer); } return CDIR_INVALID; } i = _zip_buffer_get_64(buffer); nentry = _zip_buffer_get_64(buffer); if (nentry != i) { zip_error_set(error, ZIP_ER_MULTIDISK, 0); if (free_buffer) { _zip_buffer_free(buffer); } return CDIR_INVALID; } size = _zip_buffer_get_64(buffer); offset = _zip_buffer_get_64(buffer); /* did we read past the end of the buffer? */ if (!_zip_buffer_ok(buffer)) { zip_error_set(error, ZIP_ER_INTERNAL, 0); if (free_buffer) { _zip_buffer_free(buffer); } return CDIR_INVALID; } if (free_buffer) { _zip_buffer_free(buffer); } if (offset > ZIP_INT64_MAX || offset + size < offset) { zip_error_set(error, ZIP_ER_SEEK, EFBIG); return CDIR_INVALID; } if (nentry > size / CDENTRYSIZE) { zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_CDIR_INVALID); return CDIR_INVALID; } if ((cdir->size != 0xffffffff && cdir->size != size) || (cdir->offset != 0xffffffff && cdir->offset != offset) || (cdir->num_entries != 0xffff && cdir->num_entries != nentry) || (cdir->disk_entries != 0xffff && cdir->disk_entries != i) || (cdir->this_disk != 0xffff && cdir->this_disk != this_disk) || (cdir->eocd_disk != 0xffff && cdir->eocd_disk != eocd_disk)) { zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_EOCD64_MISMATCH); return CDIR_INVALID; } cdir->is_zip64 = true; cdir->size = size; cdir->offset = offset; cdir->disk_entries = i; cdir->num_entries = nentry; cdir->this_disk = this_disk; cdir->eocd_disk = eocd_disk; return CDIR_OK; } static int decode_hex(char c) { if (c >= '0' && c <= '9') { return c - '0'; } else if (c >= 'A' && c <= 'F') { return c - 'A' + 10; } else { return -1; } } /* _zip_check_torrentzip: check whether ZA has a valid TORRENTZIP comment, i.e. is torrentzipped */ static void zip_check_torrentzip(zip_t *za, const zip_cdir_t *cdir) { zip_uint32_t crc_should; char buf[8 + 1]; size_t i; if (cdir == NULL) { return; } if (_zip_string_length(cdir->comment) != TORRENTZIP_SIGNATURE_LENGTH + TORRENTZIP_CRC_LENGTH || strncmp((const char *)cdir->comment->raw, TORRENTZIP_SIGNATURE, TORRENTZIP_SIGNATURE_LENGTH) != 0) return; memcpy(buf, cdir->comment->raw + TORRENTZIP_SIGNATURE_LENGTH, TORRENTZIP_CRC_LENGTH); buf[TORRENTZIP_CRC_LENGTH] = '\0'; crc_should = 0; for (i = 0; i < TORRENTZIP_CRC_LENGTH; i += 2) { int low, high; high = decode_hex((buf[i])); low = decode_hex(buf[i + 1]); if (high < 0 || low < 0) { return; } crc_should = (crc_should << 8) + (high << 4) + low; } { zip_stat_t st; zip_source_t *src_window; zip_source_t *src_crc; zip_uint8_t buffer[512]; zip_int64_t ret; zip_stat_init(&st); st.valid |= ZIP_STAT_SIZE | ZIP_STAT_CRC; st.size = cdir->size; st.crc = crc_should; if ((src_window = _zip_source_window_new(za->src, cdir->offset, cdir->size, &st, 0, NULL, NULL, NULL, 0, false, NULL)) == NULL) { return; } if ((src_crc = zip_source_crc_create(src_window, 1, NULL)) == NULL) { zip_source_free(src_window); return; } if (zip_source_open(src_crc) != 0) { zip_source_free(src_crc); return; } while ((ret = zip_source_read(src_crc, buffer, sizeof(buffer))) > 0) { } zip_source_free(src_crc); if (ret < 0) { return; } } /* TODO: if check consistency, check cdir entries for valid values */ za->flags |= ZIP_AFL_IS_TORRENTZIP; } ================================================ FILE: external/libzip/lib/zip_pkware.c ================================================ /* zip_pkware.c -- Traditional PKWARE de/encryption backend routines Copyright (C) 2009-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include "zipint.h" #define PKWARE_KEY0 305419896 #define PKWARE_KEY1 591751049 #define PKWARE_KEY2 878082192 static void update_keys(zip_pkware_keys_t *keys, zip_uint8_t b) { keys->key[0] = (zip_uint32_t)crc32(keys->key[0] ^ 0xffffffffUL, &b, 1) ^ 0xffffffffUL; keys->key[1] = (keys->key[1] + (keys->key[0] & 0xff)) * 134775813 + 1; b = (zip_uint8_t)(keys->key[1] >> 24); keys->key[2] = (zip_uint32_t)crc32(keys->key[2] ^ 0xffffffffUL, &b, 1) ^ 0xffffffffUL; } static zip_uint8_t crypt_byte(zip_pkware_keys_t *keys) { zip_uint16_t tmp; tmp = (zip_uint16_t)(keys->key[2] | 2); tmp = (zip_uint16_t)(((zip_uint32_t)tmp * (tmp ^ 1)) >> 8); return (zip_uint8_t)tmp; } void _zip_pkware_keys_reset(zip_pkware_keys_t *keys) { keys->key[0] = PKWARE_KEY0; keys->key[1] = PKWARE_KEY1; keys->key[2] = PKWARE_KEY2; } void _zip_pkware_encrypt(zip_pkware_keys_t *keys, zip_uint8_t *out, const zip_uint8_t *in, zip_uint64_t len) { zip_uint64_t i; zip_uint8_t b; zip_uint8_t tmp; for (i = 0; i < len; i++) { b = in[i]; if (out != NULL) { tmp = crypt_byte(keys); update_keys(keys, b); b ^= tmp; out[i] = b; } else { /* during initialization, we're only interested in key updates */ update_keys(keys, b); } } } void _zip_pkware_decrypt(zip_pkware_keys_t *keys, zip_uint8_t *out, const zip_uint8_t *in, zip_uint64_t len) { zip_uint64_t i; zip_uint8_t b; zip_uint8_t tmp; for (i = 0; i < len; i++) { b = in[i]; /* during initialization, we're only interested in key updates */ if (out != NULL) { tmp = crypt_byte(keys); b ^= tmp; out[i] = b; } update_keys(keys, b); } } ================================================ FILE: external/libzip/lib/zip_progress.c ================================================ /* zip_progress.c -- progress reporting Copyright (C) 2017-2024 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #define _ZIP_COMPILING_DEPRECATED #include "zipint.h" struct zip_progress { zip_t *za; zip_progress_callback callback_progress; void (*ud_progress_free)(void *); void *ud_progress; zip_cancel_callback callback_cancel; void (*ud_cancel_free)(void *); void *ud_cancel; double precision; /* state */ double last_update; /* last value callback function was called with */ double start; /* start of sub-progress section */ double end; /* end of sub-progress section */ }; static void _zip_progress_free_cancel_callback(zip_progress_t *progress); static void _zip_progress_free_progress_callback(zip_progress_t *progress); static zip_progress_t *_zip_progress_new(zip_t *za); static void _zip_progress_set_cancel_callback(zip_progress_t *progress, zip_cancel_callback callback, void (*ud_free)(void *), void *ud); static void _zip_progress_set_progress_callback(zip_progress_t *progress, double precision, zip_progress_callback callback, void (*ud_free)(void *), void *ud); void _zip_progress_end(zip_progress_t *progress) { _zip_progress_update(progress, 1.0); } void _zip_progress_free(zip_progress_t *progress) { if (progress == NULL) { return; } _zip_progress_free_progress_callback(progress); _zip_progress_free_cancel_callback(progress); free(progress); } static zip_progress_t * _zip_progress_new(zip_t *za) { zip_progress_t *progress = (zip_progress_t *)malloc(sizeof(*progress)); if (progress == NULL) { zip_error_set(&za->error, ZIP_ER_MEMORY, 0); return NULL; } progress->za = za; progress->callback_progress = NULL; progress->ud_progress_free = NULL; progress->ud_progress = NULL; progress->precision = 0.0; progress->callback_cancel = NULL; progress->ud_cancel_free = NULL; progress->ud_cancel = NULL; return progress; } static void _zip_progress_free_progress_callback(zip_progress_t *progress) { if (progress->ud_progress_free) { progress->ud_progress_free(progress->ud_progress); } progress->callback_progress = NULL; progress->ud_progress = NULL; progress->ud_progress_free = NULL; } static void _zip_progress_free_cancel_callback(zip_progress_t *progress) { if (progress->ud_cancel_free) { progress->ud_cancel_free(progress->ud_cancel); } progress->callback_cancel = NULL; progress->ud_cancel = NULL; progress->ud_cancel_free = NULL; } static void _zip_progress_set_progress_callback(zip_progress_t *progress, double precision, zip_progress_callback callback, void (*ud_free)(void *), void *ud) { _zip_progress_free_progress_callback(progress); progress->callback_progress = callback; progress->ud_progress_free = ud_free; progress->ud_progress = ud; progress->precision = precision; } void _zip_progress_set_cancel_callback(zip_progress_t *progress, zip_cancel_callback callback, void (*ud_free)(void *), void *ud) { _zip_progress_free_cancel_callback(progress); progress->callback_cancel = callback; progress->ud_cancel_free = ud_free; progress->ud_cancel = ud; } int _zip_progress_start(zip_progress_t *progress) { if (progress == NULL) { return 0; } if (progress->callback_progress != NULL) { progress->last_update = 0.0; progress->callback_progress(progress->za, 0.0, progress->ud_progress); } if (progress->callback_cancel != NULL) { if (progress->callback_cancel(progress->za, progress->ud_cancel)) { return -1; } } return 0; } int _zip_progress_subrange(zip_progress_t *progress, double start, double end) { if (progress == NULL) { return 0; } progress->start = start; progress->end = end; return _zip_progress_update(progress, 0.0); } int _zip_progress_update(zip_progress_t *progress, double sub_current) { double current; if (progress == NULL) { return 0; } if (progress->callback_progress != NULL) { current = ZIP_MIN(ZIP_MAX(sub_current, 0.0), 1.0) * (progress->end - progress->start) + progress->start; if (current - progress->last_update > progress->precision || (progress->last_update < 1 && current == 1)) { progress->callback_progress(progress->za, current, progress->ud_progress); progress->last_update = current; } } if (progress->callback_cancel != NULL) { if (progress->callback_cancel(progress->za, progress->ud_cancel)) { return -1; } } return 0; } ZIP_EXTERN int zip_register_progress_callback_with_state(zip_t *za, double precision, zip_progress_callback callback, void (*ud_free)(void *), void *ud) { if (callback != NULL) { if (za->progress == NULL) { if ((za->progress = _zip_progress_new(za)) == NULL) { return -1; } } _zip_progress_set_progress_callback(za->progress, precision, callback, ud_free, ud); } else { if (za->progress != NULL) { if (za->progress->callback_cancel == NULL) { _zip_progress_free(za->progress); za->progress = NULL; } else { _zip_progress_free_progress_callback(za->progress); } } } return 0; } ZIP_EXTERN int zip_register_cancel_callback_with_state(zip_t *za, zip_cancel_callback callback, void (*ud_free)(void *), void *ud) { if (callback != NULL) { if (za->progress == NULL) { if ((za->progress = _zip_progress_new(za)) == NULL) { return -1; } } _zip_progress_set_cancel_callback(za->progress, callback, ud_free, ud); } else { if (za->progress != NULL) { if (za->progress->callback_progress == NULL) { _zip_progress_free(za->progress); za->progress = NULL; } else { _zip_progress_free_cancel_callback(za->progress); } } } return 0; } struct legacy_ud { zip_progress_callback_t callback; }; static void _zip_legacy_progress_callback(zip_t *za, double progress, void *vud) { struct legacy_ud *ud = (struct legacy_ud *)vud; ud->callback(progress); } ZIP_EXTERN void zip_register_progress_callback(zip_t *za, zip_progress_callback_t progress_callback) { struct legacy_ud *ud; if (progress_callback == NULL) { zip_register_progress_callback_with_state(za, 0, NULL, NULL, NULL); } if ((ud = (struct legacy_ud *)malloc(sizeof(*ud))) == NULL) { return; } ud->callback = progress_callback; if (zip_register_progress_callback_with_state(za, 0.001, _zip_legacy_progress_callback, free, ud) < 0) { free(ud); } } ================================================ FILE: external/libzip/lib/zip_random_unix.c ================================================ /* zip_random_unix.c -- fill the user's buffer with random stuff (Unix version) Copyright (C) 2016-2023 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "zipint.h" #ifdef HAVE_CRYPTO #include "zip_crypto.h" #endif #ifdef HAVE_ARC4RANDOM #include #ifndef HAVE_SECURE_RANDOM ZIP_EXTERN bool zip_secure_random(zip_uint8_t *buffer, zip_uint16_t length) { arc4random_buf(buffer, length); return true; } #endif #ifndef HAVE_RANDOM_UINT32 zip_uint32_t zip_random_uint32(void) { return arc4random(); } #endif #else /* HAVE_ARC4RANDOM */ #ifndef HAVE_SECURE_RANDOM #include #include ZIP_EXTERN bool zip_secure_random(zip_uint8_t *buffer, zip_uint16_t length) { int fd; if ((fd = open("/dev/urandom", O_RDONLY)) < 0) { return false; } if (read(fd, buffer, length) != length) { close(fd); return false; } close(fd); return true; } #endif #ifndef HAVE_RANDOM_UINT32 #include #ifndef HAVE_RANDOM #define srandom srand #define random rand #endif zip_uint32_t zip_random_uint32(void) { static bool seeded = false; zip_uint32_t value; if (zip_secure_random((zip_uint8_t *)&value, sizeof(value))) { return value; } if (!seeded) { srandom((unsigned int)time(NULL)); seeded = true; } return (zip_uint32_t)random(); } #endif #endif /* HAVE_ARC4RANDOM */ ================================================ FILE: external/libzip/lib/zip_random_uwp.c ================================================ /* zip_random_uwp.c -- fill the user's buffer with random stuff (UWP version) Copyright (C) 2017-2023 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "zipint.h" #ifdef HAVE_CRYPTO #include "zip_crypto.h" #endif #ifndef HAVE_SECURE_RANDOM #include #include ZIP_EXTERN bool zip_secure_random(zip_uint8_t *buffer, zip_uint16_t length) { BCRYPT_ALG_HANDLE hAlg = NULL; NTSTATUS hr = BCryptOpenAlgorithmProvider(&hAlg, BCRYPT_RNG_ALGORITHM, MS_PRIMITIVE_PROVIDER, 0); if (!BCRYPT_SUCCESS(hr) || hAlg == NULL) { return false; } hr = BCryptGenRandom(&hAlg, buffer, length, 0); BCryptCloseAlgorithmProvider(&hAlg, 0); if (!BCRYPT_SUCCESS(hr)) { return false; } return true; } #endif #ifndef HAVE_RANDOM_UINT32 #include zip_uint32_t zip_random_uint32(void) { static bool seeded = false; zip_uint32_t value; if (zip_secure_random((zip_uint8_t *)&value, sizeof(value))) { return value; } if (!seeded) { srand((unsigned int)time(NULL)); seeded = true; } return (zip_uint32_t)rand(); } #endif ================================================ FILE: external/libzip/lib/zip_random_win32.c ================================================ /* zip_random_win32.c -- fill the user's buffer with random stuff (Windows version) Copyright (C) 2016-2023 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "zipint.h" #ifdef HAVE_CRYPTO #include "zip_crypto.h" #endif #include #ifndef HAVE_SECURE_RANDOM #include ZIP_EXTERN bool zip_secure_random(zip_uint8_t *buffer, zip_uint16_t length) { HCRYPTPROV hprov; if (!CryptAcquireContext(&hprov, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) { return false; } if (!CryptGenRandom(hprov, length, buffer)) { return false; } if (!CryptReleaseContext(hprov, 0)) { return false; } return true; } #endif #ifndef HAVE_RANDOM_UINT32 #include zip_uint32_t zip_random_uint32(void) { static bool seeded = false; zip_uint32_t value; if (zip_secure_random((zip_uint8_t *)&value, sizeof(value))) { return value; } if (!seeded) { srand((unsigned int)time(NULL)); seeded = true; } return (zip_uint32_t)rand(); } #endif ================================================ FILE: external/libzip/lib/zip_realloc.c ================================================ /* zip_realloc.c -- reallocate with additional elements Copyright (C) 2009-2025 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include "zipint.h" bool zip_realloc(void **memory, zip_uint64_t *alloced_elements, zip_uint64_t element_size, zip_uint64_t additional_elements, zip_error_t *error) { zip_uint64_t new_alloced_elements; void *new_memory; if (additional_elements == 0) { return true; } new_alloced_elements = *alloced_elements + additional_elements; if (new_alloced_elements < additional_elements || new_alloced_elements > SIZE_MAX / element_size) { zip_error_set(error, ZIP_ER_MEMORY, 0); return false; } if ((new_memory = realloc(*memory, (size_t)(new_alloced_elements * element_size))) == NULL) { zip_error_set(error, ZIP_ER_MEMORY, 0); return false; } *memory = new_memory; *alloced_elements = new_alloced_elements; return true; } ================================================ FILE: external/libzip/lib/zip_rename.c ================================================ /* zip_rename.c -- rename file in zip archive Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define _ZIP_COMPILING_DEPRECATED #include "zipint.h" ZIP_EXTERN int zip_rename(zip_t *za, zip_uint64_t idx, const char *name) { return zip_file_rename(za, idx, name, 0); } ================================================ FILE: external/libzip/lib/zip_replace.c ================================================ /* zip_replace.c -- replace file via callback function Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define _ZIP_COMPILING_DEPRECATED #include "zipint.h" ZIP_EXTERN int zip_replace(zip_t *za, zip_uint64_t idx, zip_source_t *source) { return zip_file_replace(za, idx, source, 0); } ================================================ FILE: external/libzip/lib/zip_set_archive_comment.c ================================================ /* zip_set_archive_comment.c -- set archive comment Copyright (C) 2006-2023 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include "zipint.h" ZIP_EXTERN int zip_set_archive_comment(zip_t *za, const char *comment, zip_uint16_t len) { zip_string_t *cstr; if (ZIP_IS_RDONLY(za)) { zip_error_set(&za->error, ZIP_ER_RDONLY, 0); return -1; } if (ZIP_WANT_TORRENTZIP(za)) { zip_error_set(&za->error, ZIP_ER_NOT_ALLOWED, 0); return -1; } if (len > 0 && comment == NULL) { zip_error_set(&za->error, ZIP_ER_INVAL, 0); return -1; } if (len > 0) { if ((cstr = _zip_string_new((const zip_uint8_t *)comment, len, ZIP_FL_ENC_GUESS, &za->error)) == NULL) return -1; if (_zip_guess_encoding(cstr, ZIP_ENCODING_UNKNOWN) == ZIP_ENCODING_CP437) { _zip_string_free(cstr); zip_error_set(&za->error, ZIP_ER_INVAL, 0); return -1; } } else cstr = NULL; _zip_string_free(za->comment_changes); za->comment_changes = NULL; if (((za->comment_orig && _zip_string_equal(za->comment_orig, cstr)) || (za->comment_orig == NULL && cstr == NULL))) { _zip_string_free(cstr); za->comment_changed = 0; } else { za->comment_changes = cstr; za->comment_changed = 1; } return 0; } ================================================ FILE: external/libzip/lib/zip_set_archive_flag.c ================================================ /* zip_get_archive_flag.c -- set archive global flag Copyright (C) 2008-2023 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "zipint.h" ZIP_EXTERN int zip_set_archive_flag(zip_t *za, zip_flags_t flag, int value) { unsigned int new_flags; if (flag == ZIP_AFL_IS_TORRENTZIP) { zip_error_set(&za->error, ZIP_ER_INVAL, 0); return -1; } /* TODO: when setting ZIP_AFL_WANT_TORRENTZIP, we should error out if any changes have been made that are not allowed for torrentzip. */ if (value) { new_flags = za->ch_flags | flag; } else { new_flags = za->ch_flags & ~flag; } if (new_flags == za->ch_flags) { return 0; } /* Allow removing ZIP_AFL_RDONLY if manually set, not if archive was opened read-only. */ if (za->flags & ZIP_AFL_RDONLY) { zip_error_set(&za->error, ZIP_ER_RDONLY, 0); return -1; } if ((flag & ZIP_AFL_RDONLY) && value && (za->ch_flags & ZIP_AFL_RDONLY) == 0) { if (_zip_changed(za, NULL)) { zip_error_set(&za->error, ZIP_ER_CHANGED, 0); return -1; } } za->ch_flags = new_flags; return 0; } ================================================ FILE: external/libzip/lib/zip_set_default_password.c ================================================ /* zip_set_default_password.c -- set default password for decryption Copyright (C) 2009-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include "zipint.h" ZIP_EXTERN int zip_set_default_password(zip_t *za, const char *passwd) { if (za == NULL) return -1; free(za->default_password); if (passwd && passwd[0] != '\0') { if ((za->default_password = strdup(passwd)) == NULL) { zip_error_set(&za->error, ZIP_ER_MEMORY, 0); return -1; } } else za->default_password = NULL; return 0; } ================================================ FILE: external/libzip/lib/zip_set_file_comment.c ================================================ /* zip_set_file_comment.c -- set comment for file in archive Copyright (C) 2006-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define _ZIP_COMPILING_DEPRECATED #include "zipint.h" ZIP_EXTERN int zip_set_file_comment(zip_t *za, zip_uint64_t idx, const char *comment, int len) { if (len < 0 || len > ZIP_UINT16_MAX) { zip_error_set(&za->error, ZIP_ER_INVAL, 0); return -1; } return zip_file_set_comment(za, idx, comment, (zip_uint16_t)len, 0); } ================================================ FILE: external/libzip/lib/zip_set_file_compression.c ================================================ /* zip_set_file_compression.c -- set compression for file in archive Copyright (C) 2012-2023 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "zipint.h" ZIP_EXTERN int zip_set_file_compression(zip_t *za, zip_uint64_t idx, zip_int32_t method, zip_uint32_t flags) { zip_entry_t *e; if (idx >= za->nentry) { zip_error_set(&za->error, ZIP_ER_INVAL, 0); return -1; } if (ZIP_IS_RDONLY(za)) { zip_error_set(&za->error, ZIP_ER_RDONLY, 0); return -1; } if (ZIP_WANT_TORRENTZIP(za)) { zip_error_set(&za->error, ZIP_ER_NOT_ALLOWED, 0); return -1; } if (!zip_compression_method_supported(method, true)) { zip_error_set(&za->error, ZIP_ER_COMPNOTSUPP, 0); return -1; } e = za->entry + idx; /* TODO: do we want to recompress if level is set? Only if it's * different than what bit flags tell us, but those are not * defined for all compression methods, or not directly mappable * to levels */ if (e->changes == NULL) { if ((e->changes = _zip_dirent_clone(e->orig)) == NULL) { zip_error_set(&za->error, ZIP_ER_MEMORY, 0); return -1; } } e->changes->comp_method = method; e->changes->compression_level = (zip_uint16_t)flags; e->changes->changed |= ZIP_DIRENT_COMP_METHOD; return 0; } ================================================ FILE: external/libzip/lib/zip_set_name.c ================================================ /* zip_set_name.c -- rename helper function Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include "zipint.h" int _zip_set_name(zip_t *za, zip_uint64_t idx, const char *name, zip_flags_t flags) { zip_entry_t *e; zip_string_t *str; bool same_as_orig; zip_int64_t i; const zip_uint8_t *old_name, *new_name; zip_string_t *old_str; if (idx >= za->nentry) { zip_error_set(&za->error, ZIP_ER_INVAL, 0); return -1; } if (ZIP_IS_RDONLY(za)) { zip_error_set(&za->error, ZIP_ER_RDONLY, 0); return -1; } if (name && name[0] != '\0') { /* TODO: check for string too long */ if ((str = _zip_string_new((const zip_uint8_t *)name, (zip_uint16_t)strlen(name), flags, &za->error)) == NULL) return -1; if ((flags & ZIP_FL_ENCODING_ALL) == ZIP_FL_ENC_GUESS && _zip_guess_encoding(str, ZIP_ENCODING_UNKNOWN) == ZIP_ENCODING_UTF8_GUESSED) str->encoding = ZIP_ENCODING_UTF8_KNOWN; } else str = NULL; /* TODO: encoding flags needed for CP437? */ if ((i = _zip_name_locate(za, name, 0, NULL)) >= 0 && (zip_uint64_t)i != idx) { _zip_string_free(str); zip_error_set(&za->error, ZIP_ER_EXISTS, 0); return -1; } /* no effective name change */ if (i >= 0 && (zip_uint64_t)i == idx) { _zip_string_free(str); return 0; } e = za->entry + idx; if (e->orig) same_as_orig = _zip_string_equal(e->orig->filename, str); else same_as_orig = false; if (!same_as_orig && e->changes == NULL) { if ((e->changes = _zip_dirent_clone(e->orig)) == NULL) { zip_error_set(&za->error, ZIP_ER_MEMORY, 0); _zip_string_free(str); return -1; } } if ((new_name = _zip_string_get(same_as_orig ? e->orig->filename : str, NULL, 0, &za->error)) == NULL) { _zip_string_free(str); return -1; } if (e->changes) { old_str = e->changes->filename; } else if (e->orig) { old_str = e->orig->filename; } else { old_str = NULL; } if (old_str) { if ((old_name = _zip_string_get(old_str, NULL, 0, &za->error)) == NULL) { _zip_string_free(str); return -1; } } else { old_name = NULL; } if (_zip_hash_add(za->names, new_name, idx, 0, &za->error) == false) { _zip_string_free(str); return -1; } if (old_name) { _zip_hash_delete(za->names, old_name, NULL); } if (same_as_orig) { if (e->changes) { if (e->changes->changed & ZIP_DIRENT_FILENAME) { _zip_string_free(e->changes->filename); e->changes->changed &= ~ZIP_DIRENT_FILENAME; if (e->changes->changed == 0) { _zip_dirent_free(e->changes); e->changes = NULL; } else { /* TODO: what if not cloned? can that happen? */ e->changes->filename = e->orig->filename; } } } _zip_string_free(str); } else { if (e->changes->changed & ZIP_DIRENT_FILENAME) { _zip_string_free(e->changes->filename); } e->changes->changed |= ZIP_DIRENT_FILENAME; e->changes->filename = str; } return 0; } ================================================ FILE: external/libzip/lib/zip_source_accept_empty.c ================================================ /* zip_source_accept_empty.c -- if empty source is a valid archive Copyright (C) 2019-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "zipint.h" bool zip_source_accept_empty(zip_source_t *src) { zip_int64_t ret; if ((zip_source_supports(src) & ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_ACCEPT_EMPTY)) == 0) { if (ZIP_SOURCE_IS_LAYERED(src)) { return zip_source_accept_empty(src->src); } return true; } ret = _zip_source_call(src, NULL, 0, ZIP_SOURCE_ACCEPT_EMPTY); return ret != 0; } ================================================ FILE: external/libzip/lib/zip_source_begin_write.c ================================================ /* zip_source_begin_write.c -- start a new file for writing Copyright (C) 2014-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "zipint.h" ZIP_EXTERN int zip_source_begin_write(zip_source_t *src) { if (ZIP_SOURCE_IS_LAYERED(src)) { zip_error_set(&src->error, ZIP_ER_OPNOTSUPP, 0); return -1; } if (ZIP_SOURCE_IS_OPEN_WRITING(src)) { zip_error_set(&src->error, ZIP_ER_INVAL, 0); return -1; } if (_zip_source_call(src, NULL, 0, ZIP_SOURCE_BEGIN_WRITE) < 0) { return -1; } src->write_state = ZIP_SOURCE_WRITE_OPEN; return 0; } ================================================ FILE: external/libzip/lib/zip_source_begin_write_cloning.c ================================================ /* zip_source_begin_write_cloning.c -- clone part of file for writing Copyright (C) 2017-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "zipint.h" ZIP_EXTERN int zip_source_begin_write_cloning(zip_source_t *src, zip_uint64_t offset) { if (ZIP_SOURCE_IS_LAYERED(src)) { zip_error_set(&src->error, ZIP_ER_OPNOTSUPP, 0); return -1; } if (ZIP_SOURCE_IS_OPEN_WRITING(src)) { zip_error_set(&src->error, ZIP_ER_INVAL, 0); return -1; } if (_zip_source_call(src, NULL, offset, ZIP_SOURCE_BEGIN_WRITE_CLONING) < 0) { return -1; } src->write_state = ZIP_SOURCE_WRITE_OPEN; return 0; } ================================================ FILE: external/libzip/lib/zip_source_buffer.c ================================================ /* zip_source_buffer.c -- create zip data source from buffer Copyright (C) 1999-2023 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include "zipint.h" #ifndef WRITE_FRAGMENT_SIZE #define WRITE_FRAGMENT_SIZE (64 * 1024) #endif struct buffer { zip_buffer_fragment_t *fragments; /* fragments */ zip_uint64_t *fragment_offsets; /* offset of each fragment from start of buffer, nfragments+1 entries */ zip_uint64_t nfragments; /* number of allocated fragments */ zip_uint64_t fragments_capacity; /* size of fragments (number of pointers) */ zip_uint64_t first_owned_fragment; /* first fragment to free data from */ zip_uint64_t shared_fragments; /* number of shared fragments */ struct buffer *shared_buffer; /* buffer fragments are shared with */ zip_uint64_t size; /* size of buffer */ zip_uint64_t offset; /* current offset in buffer */ zip_uint64_t current_fragment; /* fragment current offset is in */ }; typedef struct buffer buffer_t; struct read_data { zip_error_t error; time_t mtime; zip_file_attributes_t attributes; buffer_t *in; buffer_t *out; }; #define buffer_capacity(buffer) ((buffer)->fragment_offsets[(buffer)->nfragments]) #define buffer_size(buffer) ((buffer)->size) static buffer_t *buffer_clone(buffer_t *buffer, zip_uint64_t length, zip_error_t *error); static zip_uint64_t buffer_find_fragment(const buffer_t *buffer, zip_uint64_t offset); static void buffer_free(buffer_t *buffer); static bool buffer_grow_fragments(buffer_t *buffer, zip_uint64_t capacity, zip_error_t *error); static buffer_t *buffer_new(const zip_buffer_fragment_t *fragments, zip_uint64_t nfragments, int free_data, zip_error_t *error); static zip_int64_t buffer_read(buffer_t *buffer, zip_uint8_t *data, zip_uint64_t length); static int buffer_seek(buffer_t *buffer, void *data, zip_uint64_t len, zip_error_t *error); static zip_int64_t buffer_write(buffer_t *buffer, const zip_uint8_t *data, zip_uint64_t length, zip_error_t *); static zip_int64_t read_data(void *, void *, zip_uint64_t, zip_source_cmd_t); zip_source_t *zip_source_buffer_with_attributes_create(const void *data, zip_uint64_t len, int freep, zip_file_attributes_t *attributes, zip_error_t *error); zip_source_t *zip_source_buffer_fragment_with_attributes_create(const zip_buffer_fragment_t *fragments, zip_uint64_t nfragments, int freep, zip_file_attributes_t *attributes, zip_error_t *error); ZIP_EXTERN zip_source_t * zip_source_buffer(zip_t *za, const void *data, zip_uint64_t len, int freep) { if (za == NULL) return NULL; return zip_source_buffer_with_attributes_create(data, len, freep, NULL, &za->error); } ZIP_EXTERN zip_source_t * zip_source_buffer_create(const void *data, zip_uint64_t len, int freep, zip_error_t *error) { return zip_source_buffer_with_attributes_create(data, len, freep, NULL, error); } zip_source_t * zip_source_buffer_with_attributes_create(const void *data, zip_uint64_t len, int freep, zip_file_attributes_t *attributes, zip_error_t *error) { zip_buffer_fragment_t fragment; if (data == NULL) { if (len > 0) { zip_error_set(error, ZIP_ER_INVAL, 0); return NULL; } return zip_source_buffer_fragment_with_attributes_create(NULL, 0, freep, attributes, error); } fragment.data = (zip_uint8_t *)data; fragment.length = len; return zip_source_buffer_fragment_with_attributes_create(&fragment, 1, freep, attributes, error); } ZIP_EXTERN zip_source_t * zip_source_buffer_fragment(zip_t *za, const zip_buffer_fragment_t *fragments, zip_uint64_t nfragments, int freep) { if (za == NULL) { return NULL; } return zip_source_buffer_fragment_with_attributes_create(fragments, nfragments, freep, NULL, &za->error); } ZIP_EXTERN zip_source_t * zip_source_buffer_fragment_create(const zip_buffer_fragment_t *fragments, zip_uint64_t nfragments, int freep, zip_error_t *error) { return zip_source_buffer_fragment_with_attributes_create(fragments, nfragments, freep, NULL, error); } zip_source_t * zip_source_buffer_fragment_with_attributes_create(const zip_buffer_fragment_t *fragments, zip_uint64_t nfragments, int freep, zip_file_attributes_t *attributes, zip_error_t *error) { struct read_data *ctx; zip_source_t *zs; buffer_t *buffer; if (fragments == NULL && nfragments > 0) { zip_error_set(error, ZIP_ER_INVAL, 0); return NULL; } if ((buffer = buffer_new(fragments, nfragments, freep, error)) == NULL) { return NULL; } if ((ctx = (struct read_data *)malloc(sizeof(*ctx))) == NULL) { zip_error_set(error, ZIP_ER_MEMORY, 0); buffer_free(buffer); return NULL; } ctx->in = buffer; ctx->out = NULL; ctx->mtime = time(NULL); if (attributes) { (void)memcpy_s(&ctx->attributes, sizeof(ctx->attributes), attributes, sizeof(ctx->attributes)); } else { zip_file_attributes_init(&ctx->attributes); } zip_error_init(&ctx->error); if ((zs = zip_source_function_create(read_data, ctx, error)) == NULL) { buffer_free(ctx->in); free(ctx); return NULL; } return zs; } zip_source_t * zip_source_buffer_with_attributes(zip_t *za, const void *data, zip_uint64_t len, int freep, zip_file_attributes_t *attributes) { return zip_source_buffer_with_attributes_create(data, len, freep, attributes, &za->error); } static zip_int64_t read_data(void *state, void *data, zip_uint64_t len, zip_source_cmd_t cmd) { struct read_data *ctx = (struct read_data *)state; switch (cmd) { case ZIP_SOURCE_BEGIN_WRITE: if ((ctx->out = buffer_new(NULL, 0, 0, &ctx->error)) == NULL) { return -1; } ctx->out->offset = 0; ctx->out->current_fragment = 0; return 0; case ZIP_SOURCE_BEGIN_WRITE_CLONING: if ((ctx->out = buffer_clone(ctx->in, len, &ctx->error)) == NULL) { return -1; } ctx->out->offset = len; ctx->out->current_fragment = ctx->out->nfragments; return 0; case ZIP_SOURCE_CLOSE: return 0; case ZIP_SOURCE_COMMIT_WRITE: buffer_free(ctx->in); ctx->in = ctx->out; ctx->out = NULL; return 0; case ZIP_SOURCE_ERROR: return zip_error_to_data(&ctx->error, data, len); case ZIP_SOURCE_FREE: buffer_free(ctx->in); buffer_free(ctx->out); free(ctx); return 0; case ZIP_SOURCE_GET_FILE_ATTRIBUTES: { if (len < sizeof(ctx->attributes)) { zip_error_set(&ctx->error, ZIP_ER_INVAL, 0); return -1; } (void)memcpy_s(data, sizeof(ctx->attributes), &ctx->attributes, sizeof(ctx->attributes)); return sizeof(ctx->attributes); } case ZIP_SOURCE_OPEN: ctx->in->offset = 0; ctx->in->current_fragment = 0; return 0; case ZIP_SOURCE_READ: if (len > ZIP_INT64_MAX) { zip_error_set(&ctx->error, ZIP_ER_INVAL, 0); return -1; } return buffer_read(ctx->in, data, len); case ZIP_SOURCE_REMOVE: { buffer_t *empty = buffer_new(NULL, 0, 0, &ctx->error); if (empty == NULL) { return -1; } buffer_free(ctx->in); ctx->in = empty; return 0; } case ZIP_SOURCE_ROLLBACK_WRITE: buffer_free(ctx->out); ctx->out = NULL; return 0; case ZIP_SOURCE_SEEK: return buffer_seek(ctx->in, data, len, &ctx->error); case ZIP_SOURCE_SEEK_WRITE: return buffer_seek(ctx->out, data, len, &ctx->error); case ZIP_SOURCE_STAT: { zip_stat_t *st; if (len < sizeof(*st)) { zip_error_set(&ctx->error, ZIP_ER_INVAL, 0); return -1; } st = (zip_stat_t *)data; zip_stat_init(st); st->mtime = ctx->mtime; st->size = ctx->in->size; st->comp_size = st->size; st->comp_method = ZIP_CM_STORE; st->encryption_method = ZIP_EM_NONE; st->valid = ZIP_STAT_MTIME | ZIP_STAT_SIZE | ZIP_STAT_COMP_SIZE | ZIP_STAT_COMP_METHOD | ZIP_STAT_ENCRYPTION_METHOD; return sizeof(*st); } case ZIP_SOURCE_SUPPORTS: return zip_source_make_command_bitmap(ZIP_SOURCE_GET_FILE_ATTRIBUTES, ZIP_SOURCE_OPEN, ZIP_SOURCE_READ, ZIP_SOURCE_CLOSE, ZIP_SOURCE_STAT, ZIP_SOURCE_ERROR, ZIP_SOURCE_FREE, ZIP_SOURCE_SEEK, ZIP_SOURCE_TELL, ZIP_SOURCE_BEGIN_WRITE, ZIP_SOURCE_BEGIN_WRITE_CLONING, ZIP_SOURCE_COMMIT_WRITE, ZIP_SOURCE_REMOVE, ZIP_SOURCE_ROLLBACK_WRITE, ZIP_SOURCE_SEEK_WRITE, ZIP_SOURCE_TELL_WRITE, ZIP_SOURCE_WRITE, ZIP_SOURCE_SUPPORTS_REOPEN, -1); case ZIP_SOURCE_TELL: if (ctx->in->offset > ZIP_INT64_MAX) { zip_error_set(&ctx->error, ZIP_ER_TELL, EOVERFLOW); return -1; } return (zip_int64_t)ctx->in->offset; case ZIP_SOURCE_TELL_WRITE: if (ctx->out->offset > ZIP_INT64_MAX) { zip_error_set(&ctx->error, ZIP_ER_TELL, EOVERFLOW); return -1; } return (zip_int64_t)ctx->out->offset; case ZIP_SOURCE_WRITE: if (len > ZIP_INT64_MAX) { zip_error_set(&ctx->error, ZIP_ER_INVAL, 0); return -1; } return buffer_write(ctx->out, data, len, &ctx->error); default: zip_error_set(&ctx->error, ZIP_ER_OPNOTSUPP, 0); return -1; } } static buffer_t * buffer_clone(buffer_t *buffer, zip_uint64_t offset, zip_error_t *error) { zip_uint64_t fragment, fragment_offset, waste; buffer_t *clone; if (offset == 0) { return buffer_new(NULL, 0, 1, error); } if (offset > buffer->size) { zip_error_set(error, ZIP_ER_INVAL, 0); return NULL; } if (buffer->shared_buffer != NULL) { zip_error_set(error, ZIP_ER_INUSE, 0); return NULL; } fragment = buffer_find_fragment(buffer, offset); fragment_offset = offset - buffer->fragment_offsets[fragment]; if (fragment_offset == 0) { /* We can't be at beginning of fragment zero if offset > 0. */ fragment--; fragment_offset = buffer->fragments[fragment].length; } /* TODO: This should also consider the length of the fully shared fragments */ waste = buffer->fragments[fragment].length - fragment_offset; if (waste > offset) { zip_error_set(error, ZIP_ER_OPNOTSUPP, 0); return NULL; } if ((clone = buffer_new(buffer->fragments, fragment + 1, 0, error)) == NULL) { return NULL; } #ifndef __clang_analyzer__ /* clone->fragments can't be null, since it was created with at least one fragment */ clone->fragments[fragment].length = fragment_offset; #endif clone->fragment_offsets[clone->nfragments] = offset; clone->size = offset; clone->first_owned_fragment = ZIP_MIN(buffer->first_owned_fragment, clone->nfragments); buffer->shared_buffer = clone; clone->shared_buffer = buffer; buffer->shared_fragments = fragment + 1; clone->shared_fragments = fragment + 1; return clone; } static zip_uint64_t buffer_find_fragment(const buffer_t *buffer, zip_uint64_t offset) { zip_uint64_t low, high, mid; if (buffer->nfragments == 0) { return 0; } low = 0; high = buffer->nfragments - 1; while (low < high) { mid = (high - low) / 2 + low; if (buffer->fragment_offsets[mid] > offset) { high = mid - 1; } else if (mid == buffer->nfragments || buffer->fragment_offsets[mid + 1] > offset) { return mid; } else { low = mid + 1; } } return low; } static void buffer_free(buffer_t *buffer) { zip_uint64_t i; if (buffer == NULL) { return; } if (buffer->shared_buffer != NULL) { buffer->shared_buffer->shared_buffer = NULL; buffer->shared_buffer->shared_fragments = 0; buffer->first_owned_fragment = ZIP_MAX(buffer->first_owned_fragment, buffer->shared_fragments); } for (i = buffer->first_owned_fragment; i < buffer->nfragments; i++) { free(buffer->fragments[i].data); } free(buffer->fragments); free(buffer->fragment_offsets); free(buffer); } static bool buffer_grow_fragments(buffer_t *buffer, zip_uint64_t capacity, zip_error_t *error) { zip_uint64_t additional_fragments; zip_uint64_t offset_capacity = buffer->fragments_capacity + 1; if (capacity <= buffer->fragments_capacity) { return true; } additional_fragments = capacity - buffer->fragments_capacity; if (!ZIP_REALLOC(buffer->fragments, buffer->fragments_capacity, additional_fragments, error)) { return false; } /* The size of both buffer->fragments and buffer->fragment_offsets is stored in buffer->fragments_capacity, so use a temporary capacity variable here for reallocating buffer->fragment_offsets. */ if (!ZIP_REALLOC(buffer->fragment_offsets, offset_capacity, additional_fragments, error)) { buffer->fragments_capacity -= additional_fragments; return false; } return true; } static buffer_t * buffer_new(const zip_buffer_fragment_t *fragments, zip_uint64_t nfragments, int free_data, zip_error_t *error) { buffer_t *buffer; if ((buffer = malloc(sizeof(*buffer))) == NULL) { return NULL; } buffer->offset = 0; buffer->first_owned_fragment = 0; buffer->size = 0; buffer->fragments = NULL; buffer->fragment_offsets = NULL; buffer->nfragments = 0; buffer->fragments_capacity = 0; buffer->shared_buffer = NULL; buffer->shared_fragments = 0; if (nfragments == 0) { if ((buffer->fragment_offsets = malloc(sizeof(buffer->fragment_offsets[0]))) == NULL) { free(buffer); zip_error_set(error, ZIP_ER_MEMORY, 0); return NULL; } buffer->fragment_offsets[0] = 0; } else { zip_uint64_t i, j, offset; if (!buffer_grow_fragments(buffer, nfragments, NULL)) { zip_error_set(error, ZIP_ER_MEMORY, 0); buffer_free(buffer); return NULL; } offset = 0; for (i = 0, j = 0; i < nfragments; i++) { if (fragments[i].length == 0) { continue; } if (fragments[i].data == NULL) { zip_error_set(error, ZIP_ER_INVAL, 0); buffer_free(buffer); return NULL; } buffer->fragments[j].data = fragments[i].data; buffer->fragments[j].length = fragments[i].length; buffer->fragment_offsets[i] = offset; /* TODO: overflow */ offset += fragments[i].length; j++; } buffer->nfragments = j; buffer->first_owned_fragment = free_data ? 0 : buffer->nfragments; buffer->fragment_offsets[buffer->nfragments] = offset; buffer->size = offset; } return buffer; } static zip_int64_t buffer_read(buffer_t *buffer, zip_uint8_t *data, zip_uint64_t length) { zip_uint64_t n, i, fragment_offset; length = ZIP_MIN(length, buffer->size - buffer->offset); if (length == 0) { return 0; } if (length > ZIP_INT64_MAX) { return -1; } i = buffer->current_fragment; fragment_offset = buffer->offset - buffer->fragment_offsets[i]; n = 0; while (n < length) { zip_uint64_t left = ZIP_MIN(length - n, buffer->fragments[i].length - fragment_offset); #if ZIP_UINT64_MAX > SIZE_MAX left = ZIP_MIN(left, SIZE_MAX); #endif (void)memcpy_s(data + n, (size_t)left, buffer->fragments[i].data + fragment_offset, (size_t)left); if (left == buffer->fragments[i].length - fragment_offset) { i++; } n += left; fragment_offset = 0; } buffer->offset += n; buffer->current_fragment = i; return (zip_int64_t)n; } static int buffer_seek(buffer_t *buffer, void *data, zip_uint64_t len, zip_error_t *error) { zip_int64_t new_offset = zip_source_seek_compute_offset(buffer->offset, buffer->size, data, len, error); if (new_offset < 0) { return -1; } buffer->offset = (zip_uint64_t)new_offset; buffer->current_fragment = buffer_find_fragment(buffer, buffer->offset); return 0; } static zip_int64_t buffer_write(buffer_t *buffer, const zip_uint8_t *data, zip_uint64_t length, zip_error_t *error) { zip_uint64_t copied, i, fragment_offset, capacity; if (buffer->offset + length + WRITE_FRAGMENT_SIZE - 1 < length) { zip_error_set(error, ZIP_ER_INVAL, 0); return -1; } /* grow buffer if needed */ capacity = buffer_capacity(buffer); if (buffer->offset + length > capacity) { zip_uint64_t needed_fragments = buffer->nfragments + (length - (capacity - buffer->offset) + WRITE_FRAGMENT_SIZE - 1) / WRITE_FRAGMENT_SIZE; if (needed_fragments > buffer->fragments_capacity) { zip_uint64_t new_capacity = buffer->fragments_capacity; if (new_capacity == 0) { new_capacity = 16; } while (new_capacity < needed_fragments) { new_capacity *= 2; } if (!buffer_grow_fragments(buffer, new_capacity, error)) { zip_error_set(error, ZIP_ER_MEMORY, 0); return -1; } } while (buffer->nfragments < needed_fragments) { if ((buffer->fragments[buffer->nfragments].data = malloc(WRITE_FRAGMENT_SIZE)) == NULL) { zip_error_set(error, ZIP_ER_MEMORY, 0); return -1; } buffer->fragments[buffer->nfragments].length = WRITE_FRAGMENT_SIZE; buffer->nfragments++; capacity += WRITE_FRAGMENT_SIZE; buffer->fragment_offsets[buffer->nfragments] = capacity; } } i = buffer->current_fragment; fragment_offset = buffer->offset - buffer->fragment_offsets[i]; copied = 0; while (copied < length) { zip_uint64_t n = ZIP_MIN(ZIP_MIN(length - copied, buffer->fragments[i].length - fragment_offset), SIZE_MAX); #if ZIP_UINT64_MAX > SIZE_MAX n = ZIP_MIN(n, SIZE_MAX); #endif (void)memcpy_s(buffer->fragments[i].data + fragment_offset, (size_t)n, data + copied, (size_t)n); if (n == buffer->fragments[i].length - fragment_offset) { i++; fragment_offset = 0; } else { fragment_offset += n; } copied += n; } buffer->offset += copied; buffer->current_fragment = i; if (buffer->offset > buffer->size) { buffer->size = buffer->offset; } return (zip_int64_t)copied; } ================================================ FILE: external/libzip/lib/zip_source_call.c ================================================ /* zip_source_call.c -- invoke callback command on zip_source Copyright (C) 2009-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "zipint.h" zip_int64_t _zip_source_call(zip_source_t *src, void *data, zip_uint64_t length, zip_source_cmd_t command) { zip_int64_t ret; if ((src->supports & ZIP_SOURCE_MAKE_COMMAND_BITMASK(command)) == 0) { zip_error_set(&src->error, ZIP_ER_OPNOTSUPP, 0); return -1; } if (src->src == NULL) { ret = src->cb.f(src->ud, data, length, command); } else { ret = src->cb.l(src->src, src->ud, data, length, command); } if (ret < 0) { if (command != ZIP_SOURCE_ERROR && command != ZIP_SOURCE_SUPPORTS) { int e[2]; if (_zip_source_call(src, e, sizeof(e), ZIP_SOURCE_ERROR) < 0) { zip_error_set(&src->error, ZIP_ER_INTERNAL, 0); } else { zip_error_set(&src->error, e[0], e[1]); } } } return ret; } ================================================ FILE: external/libzip/lib/zip_source_close.c ================================================ /* zip_source_close.c -- close zip_source (stop reading) Copyright (C) 2009-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "zipint.h" int zip_source_close(zip_source_t *src) { if (!ZIP_SOURCE_IS_OPEN_READING(src)) { zip_error_set(&src->error, ZIP_ER_INVAL, 0); return -1; } src->open_count--; if (src->open_count == 0) { _zip_source_call(src, NULL, 0, ZIP_SOURCE_CLOSE); if (ZIP_SOURCE_IS_LAYERED(src)) { if (zip_source_close(src->src) < 0) { zip_error_set(&src->error, ZIP_ER_INTERNAL, 0); } } } return 0; } ================================================ FILE: external/libzip/lib/zip_source_commit_write.c ================================================ /* zip_source_commit_write.c -- commit changes to file Copyright (C) 2014-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "zipint.h" ZIP_EXTERN int zip_source_commit_write(zip_source_t *src) { if (ZIP_SOURCE_IS_LAYERED(src)) { zip_error_set(&src->error, ZIP_ER_OPNOTSUPP, 0); return -1; } if (!ZIP_SOURCE_IS_OPEN_WRITING(src)) { zip_error_set(&src->error, ZIP_ER_INVAL, 0); return -1; } if (src->open_count > 1) { zip_error_set(&src->error, ZIP_ER_INUSE, 0); return -1; } else if (ZIP_SOURCE_IS_OPEN_READING(src)) { if (zip_source_close(src) < 0) { return -1; } } if (_zip_source_call(src, NULL, 0, ZIP_SOURCE_COMMIT_WRITE) < 0) { src->write_state = ZIP_SOURCE_WRITE_FAILED; return -1; } src->write_state = ZIP_SOURCE_WRITE_CLOSED; return 0; } ================================================ FILE: external/libzip/lib/zip_source_compress.c ================================================ /* zip_source_compress.c -- (de)compression routines Copyright (C) 2017-2023 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include "zipint.h" struct context { zip_error_t error; bool end_of_input; bool end_of_stream; bool can_store; bool is_stored; /* only valid if end_of_stream is true */ bool compress; bool check_consistency; zip_int32_t method; zip_uint64_t size; zip_int64_t first_read; zip_uint8_t buffer[BUFSIZE]; zip_compression_algorithm_t *algorithm; void *ud; }; struct implementation { zip_uint16_t method; zip_compression_algorithm_t *compress; zip_compression_algorithm_t *decompress; }; static struct implementation implementations[] = { {ZIP_CM_DEFLATE, &zip_algorithm_deflate_compress, &zip_algorithm_deflate_decompress}, #if defined(HAVE_LIBBZ2) {ZIP_CM_BZIP2, &zip_algorithm_bzip2_compress, &zip_algorithm_bzip2_decompress}, #endif #if defined(HAVE_LIBLZMA) {ZIP_CM_LZMA, &zip_algorithm_xz_compress, &zip_algorithm_xz_decompress}, /* Disabled - because 7z isn't able to unpack ZIP+LZMA2 archives made this way - and vice versa. {ZIP_CM_LZMA2, &zip_algorithm_xz_compress, &zip_algorithm_xz_decompress}, */ {ZIP_CM_XZ, &zip_algorithm_xz_compress, &zip_algorithm_xz_decompress}, #endif #if defined(HAVE_LIBZSTD) {ZIP_CM_ZSTD, &zip_algorithm_zstd_compress, &zip_algorithm_zstd_decompress}, #endif }; static size_t implementations_size = sizeof(implementations) / sizeof(implementations[0]); static zip_source_t *compression_source_new(zip_t *za, zip_source_t *src, zip_int32_t method, bool compress, zip_uint32_t compression_flags); static zip_int64_t compress_callback(zip_source_t *, void *, void *, zip_uint64_t, zip_source_cmd_t); static void context_free(struct context *ctx); static struct context *context_new(zip_int32_t method, bool compress, zip_uint32_t compression_flags, zip_compression_algorithm_t *algorithm, bool check_consistency); static zip_int64_t compress_read(zip_source_t *, struct context *, void *, zip_uint64_t); zip_compression_algorithm_t *_zip_get_compression_algorithm(zip_int32_t method, bool compress) { size_t i; zip_uint16_t real_method = ZIP_CM_ACTUAL(method); for (i = 0; i < implementations_size; i++) { if (implementations[i].method == real_method) { if (compress) { return implementations[i].compress; } else { return implementations[i].decompress; } } } return NULL; } ZIP_EXTERN int zip_compression_method_supported(zip_int32_t method, int compress) { if (method == ZIP_CM_STORE) { return 1; } return _zip_get_compression_algorithm(method, compress) != NULL; } zip_source_t *zip_source_compress(zip_t *za, zip_source_t *src, zip_int32_t method, zip_uint32_t compression_flags) { return compression_source_new(za, src, method, true, compression_flags); } zip_source_t * zip_source_decompress(zip_t *za, zip_source_t *src, zip_int32_t method) { return compression_source_new(za, src, method, false, 0); } static zip_source_t *compression_source_new(zip_t *za, zip_source_t *src, zip_int32_t method, bool compress, zip_uint32_t compression_flags) { struct context *ctx; zip_source_t *s2; zip_compression_algorithm_t *algorithm = NULL; if (src == NULL) { zip_error_set(&za->error, ZIP_ER_INVAL, 0); return NULL; } if ((algorithm = _zip_get_compression_algorithm(method, compress)) == NULL) { zip_error_set(&za->error, ZIP_ER_COMPNOTSUPP, 0); return NULL; } if ((ctx = context_new(method, compress, compression_flags, algorithm, za->open_flags & ZIP_CHECKCONS)) == NULL) { zip_error_set(&za->error, ZIP_ER_MEMORY, 0); return NULL; } if ((s2 = zip_source_layered(za, src, compress_callback, ctx)) == NULL) { context_free(ctx); return NULL; } return s2; } static struct context *context_new(zip_int32_t method, bool compress, zip_uint32_t compression_flags, zip_compression_algorithm_t *algorithm, bool check_consistency) { struct context *ctx; if ((ctx = (struct context *)malloc(sizeof(*ctx))) == NULL) { return NULL; } zip_error_init(&ctx->error); ctx->can_store = compress ? ZIP_CM_IS_DEFAULT(method) : false; ctx->algorithm = algorithm; ctx->method = method; ctx->compress = compress; ctx->end_of_input = false; ctx->end_of_stream = false; ctx->is_stored = false; ctx->check_consistency = check_consistency; if ((ctx->ud = ctx->algorithm->allocate(ZIP_CM_ACTUAL(method), compression_flags, &ctx->error)) == NULL) { zip_error_fini(&ctx->error); free(ctx); return NULL; } return ctx; } static void context_free(struct context *ctx) { if (ctx == NULL) { return; } ctx->algorithm->deallocate(ctx->ud); zip_error_fini(&ctx->error); free(ctx); } static zip_int64_t compress_read(zip_source_t *src, struct context *ctx, void *data, zip_uint64_t len) { zip_compression_status_t ret; bool end; zip_int64_t n; zip_uint64_t out_offset; zip_uint64_t out_len; if (zip_error_code_zip(&ctx->error) != ZIP_ER_OK) { return -1; } if (len == 0 || ctx->end_of_stream) { return 0; } out_offset = 0; end = false; while (!end && out_offset < len) { out_len = len - out_offset; ret = ctx->algorithm->process(ctx->ud, (zip_uint8_t *)data + out_offset, &out_len); if (ret != ZIP_COMPRESSION_ERROR) { out_offset += out_len; } switch (ret) { case ZIP_COMPRESSION_END: ctx->end_of_stream = true; if (!ctx->end_of_input) { n = zip_source_read(src, ctx->buffer, 1); if (n < 0) { zip_error_set_from_source(&ctx->error, src); end = true; break; } else if (n == 0) { ctx->end_of_input = true; n = ctx->algorithm->end_of_input(ctx->ud) ? 1 : 0; } if (n > 0 && ctx->check_consistency) { /* garbage after stream, or compression ended before all data read */ zip_error_set(&ctx->error, ZIP_ER_INCONS, ZIP_ER_DETAIL_COMPRESSED_DATA_TRAILING_GARBAGE); end = true; break; } } if (ctx->first_read < 0) { /* we got end of processed stream before reading any input data */ zip_error_set(&ctx->error, ZIP_ER_INTERNAL, 0); end = true; break; } if (ctx->can_store && (zip_uint64_t)ctx->first_read <= out_offset) { ctx->is_stored = true; ctx->size = (zip_uint64_t)ctx->first_read; (void)memcpy_s(data, ctx->size, ctx->buffer, ctx->size); return (zip_int64_t)ctx->size; } end = true; break; case ZIP_COMPRESSION_OK: break; case ZIP_COMPRESSION_NEED_DATA: if (ctx->end_of_input) { /* TODO: error: stream not ended, but no more input */ end = true; break; } if ((n = zip_source_read(src, ctx->buffer, sizeof(ctx->buffer))) < 0) { zip_error_set_from_source(&ctx->error, src); end = true; break; } else if (n == 0) { ctx->end_of_input = true; ctx->algorithm->end_of_input(ctx->ud); if (ctx->first_read < 0) { ctx->first_read = 0; } } else { if (ctx->first_read >= 0) { /* we overwrote a previously filled ctx->buffer */ ctx->can_store = false; } else { ctx->first_read = n; } ctx->algorithm->input(ctx->ud, ctx->buffer, (zip_uint64_t)n); } break; case ZIP_COMPRESSION_ERROR: /* error set by algorithm */ if (zip_error_code_zip(&ctx->error) == ZIP_ER_OK) { zip_error_set(&ctx->error, ZIP_ER_INTERNAL, 0); } end = true; break; } } if (out_offset > 0) { ctx->can_store = false; ctx->size += out_offset; return (zip_int64_t)out_offset; } return (zip_error_code_zip(&ctx->error) == ZIP_ER_OK) ? 0 : -1; } static zip_int64_t compress_callback(zip_source_t *src, void *ud, void *data, zip_uint64_t len, zip_source_cmd_t cmd) { struct context *ctx; ctx = (struct context *)ud; switch (cmd) { case ZIP_SOURCE_OPEN: { zip_stat_t st; zip_file_attributes_t attributes; ctx->size = 0; ctx->end_of_input = false; ctx->end_of_stream = false; ctx->is_stored = false; ctx->first_read = -1; if (zip_source_stat(src, &st) < 0 || zip_source_get_file_attributes(src, &attributes) < 0) { zip_error_set_from_source(&ctx->error, src); return -1; } if (!ctx->algorithm->start(ctx->ud, &st, &attributes)) { return -1; } return 0; } case ZIP_SOURCE_READ: return compress_read(src, ctx, data, len); case ZIP_SOURCE_CLOSE: if (!ctx->algorithm->end(ctx->ud)) { return -1; } return 0; case ZIP_SOURCE_STAT: { zip_stat_t *st; st = (zip_stat_t *)data; if (ctx->compress) { if (ctx->end_of_stream) { st->comp_method = ctx->is_stored ? ZIP_CM_STORE : ZIP_CM_ACTUAL(ctx->method); st->comp_size = ctx->size; st->valid |= ZIP_STAT_COMP_SIZE | ZIP_STAT_COMP_METHOD; } else { st->valid &= ~(ZIP_STAT_COMP_SIZE | ZIP_STAT_COMP_METHOD); } } else { st->comp_method = ZIP_CM_STORE; st->valid |= ZIP_STAT_COMP_METHOD; st->valid &= ~ZIP_STAT_COMP_SIZE; if (ctx->end_of_stream) { st->size = ctx->size; st->valid |= ZIP_STAT_SIZE; } } } return 0; case ZIP_SOURCE_ERROR: return zip_error_to_data(&ctx->error, data, len); case ZIP_SOURCE_FREE: context_free(ctx); return 0; case ZIP_SOURCE_GET_FILE_ATTRIBUTES: { zip_file_attributes_t *attributes = (zip_file_attributes_t *)data; if (len < sizeof(*attributes)) { zip_error_set(&ctx->error, ZIP_ER_INVAL, 0); return -1; } attributes->valid |= ZIP_FILE_ATTRIBUTES_VERSION_NEEDED | ZIP_FILE_ATTRIBUTES_GENERAL_PURPOSE_BIT_FLAGS; attributes->version_needed = ctx->algorithm->version_needed; attributes->general_purpose_bit_mask = ZIP_FILE_ATTRIBUTES_GENERAL_PURPOSE_BIT_FLAGS_ALLOWED_MASK; attributes->general_purpose_bit_flags = (ctx->is_stored ? 0 : ctx->algorithm->general_purpose_bit_flags(ctx->ud)); return sizeof(*attributes); } case ZIP_SOURCE_SUPPORTS: return ZIP_SOURCE_SUPPORTS_READABLE | zip_source_make_command_bitmap(ZIP_SOURCE_GET_FILE_ATTRIBUTES, ZIP_SOURCE_SUPPORTS_REOPEN, -1); default: return zip_source_pass_to_lower_layer(src, data, len, cmd); } } ================================================ FILE: external/libzip/lib/zip_source_crc.c ================================================ /* zip_source_crc.c -- pass-through source that calculates CRC32 and size Copyright (C) 2009-2023 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include "zipint.h" struct crc_context { int validate; /* whether to check CRC on EOF and return error on mismatch */ int crc_complete; /* whether CRC was computed for complete file */ zip_error_t error; zip_uint64_t size; zip_uint64_t position; /* current reading position */ zip_uint64_t crc_position; /* how far we've computed the CRC */ zip_uint32_t crc; }; static zip_int64_t crc_read(zip_source_t *, void *, void *, zip_uint64_t, zip_source_cmd_t); zip_source_t * zip_source_crc_create(zip_source_t *src, int validate, zip_error_t *error) { struct crc_context *ctx; if (src == NULL) { zip_error_set(error, ZIP_ER_INVAL, 0); return NULL; } if ((ctx = (struct crc_context *)malloc(sizeof(*ctx))) == NULL) { zip_error_set(error, ZIP_ER_MEMORY, 0); return NULL; } zip_error_init(&ctx->error); ctx->validate = validate; ctx->crc_complete = 0; ctx->crc_position = 0; ctx->crc = (zip_uint32_t)crc32(0, NULL, 0); ctx->size = 0; return zip_source_layered_create(src, crc_read, ctx, error); } static zip_int64_t crc_read(zip_source_t *src, void *_ctx, void *data, zip_uint64_t len, zip_source_cmd_t cmd) { struct crc_context *ctx; zip_int64_t n; ctx = (struct crc_context *)_ctx; switch (cmd) { case ZIP_SOURCE_OPEN: ctx->position = 0; return 0; case ZIP_SOURCE_READ: if ((n = zip_source_read(src, data, len)) < 0) { zip_error_set_from_source(&ctx->error, src); return -1; } if (n == 0) { if (ctx->crc_position == ctx->position) { ctx->crc_complete = 1; ctx->size = ctx->position; if (ctx->validate) { struct zip_stat st; if (zip_source_stat(src, &st) < 0) { zip_error_set_from_source(&ctx->error, src); return -1; } if ((st.valid & ZIP_STAT_CRC) && st.crc != ctx->crc) { zip_error_set(&ctx->error, ZIP_ER_CRC, 0); return -1; } if ((st.valid & ZIP_STAT_SIZE) && st.size != ctx->size) { /* We don't have the index here, but the caller should know which file they are reading from. */ zip_error_set(&ctx->error, ZIP_ER_INCONS, MAKE_DETAIL_WITH_INDEX(ZIP_ER_DETAIL_INVALID_FILE_LENGTH, MAX_DETAIL_INDEX)); return -1; } } } } else if (!ctx->crc_complete && ctx->position <= ctx->crc_position) { zip_uint64_t i, nn; for (i = ctx->crc_position - ctx->position; i < (zip_uint64_t)n; i += nn) { nn = ZIP_MIN(UINT_MAX, (zip_uint64_t)n - i); ctx->crc = (zip_uint32_t)crc32(ctx->crc, (const Bytef *)data + i, (uInt)nn); ctx->crc_position += nn; } } ctx->position += (zip_uint64_t)n; return n; case ZIP_SOURCE_CLOSE: return 0; case ZIP_SOURCE_STAT: { zip_stat_t *st; st = (zip_stat_t *)data; if (ctx->crc_complete) { if ((st->valid & ZIP_STAT_SIZE) && st->size != ctx->size) { zip_error_set(&ctx->error, ZIP_ER_DATA_LENGTH, 0); return -1; } /* TODO: Set comp_size, comp_method, encryption_method? After all, this only works for uncompressed data. */ st->size = ctx->size; st->crc = ctx->crc; st->comp_size = ctx->size; st->comp_method = ZIP_CM_STORE; st->encryption_method = ZIP_EM_NONE; st->valid |= ZIP_STAT_SIZE | ZIP_STAT_CRC | ZIP_STAT_COMP_SIZE | ZIP_STAT_COMP_METHOD | ZIP_STAT_ENCRYPTION_METHOD; } return 0; } case ZIP_SOURCE_ERROR: return zip_error_to_data(&ctx->error, data, len); case ZIP_SOURCE_FREE: free(ctx); return 0; case ZIP_SOURCE_SUPPORTS: { zip_int64_t mask = zip_source_supports(src); if (mask < 0) { zip_error_set_from_source(&ctx->error, src); return -1; } mask &= ~zip_source_make_command_bitmap(ZIP_SOURCE_BEGIN_WRITE, ZIP_SOURCE_COMMIT_WRITE, ZIP_SOURCE_ROLLBACK_WRITE, ZIP_SOURCE_SEEK_WRITE, ZIP_SOURCE_TELL_WRITE, ZIP_SOURCE_REMOVE, ZIP_SOURCE_GET_FILE_ATTRIBUTES, -1); mask |= zip_source_make_command_bitmap(ZIP_SOURCE_FREE, -1); return mask; } case ZIP_SOURCE_SEEK: { zip_int64_t new_position; zip_source_args_seek_t *args = ZIP_SOURCE_GET_ARGS(zip_source_args_seek_t, data, len, &ctx->error); if (args == NULL) { return -1; } if (zip_source_seek(src, args->offset, args->whence) < 0 || (new_position = zip_source_tell(src)) < 0) { zip_error_set_from_source(&ctx->error, src); return -1; } ctx->position = (zip_uint64_t)new_position; return 0; } case ZIP_SOURCE_TELL: return (zip_int64_t)ctx->position; default: return zip_source_pass_to_lower_layer(src, data, len, cmd); } } ================================================ FILE: external/libzip/lib/zip_source_error.c ================================================ /* zip_source_error.c -- get last error from zip_source Copyright (C) 2009-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "zipint.h" zip_error_t * zip_source_error(zip_source_t *src) { return &src->error; } bool _zip_source_had_error(zip_source_t *src) { return zip_source_error(src)->zip_err != ZIP_ER_OK; } ================================================ FILE: external/libzip/lib/zip_source_file.h ================================================ #ifndef _HAD_ZIP_SOURCE_FILE_H #define _HAD_ZIP_SOURCE_FILE_H /* zip_source_file.h -- header for common file operations Copyright (C) 2020-2024 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ struct zip_source_file_stat { zip_uint64_t size; /* must be valid for regular files */ time_t mtime; /* must always be valid, is initialized to current time */ bool exists; /* must always be valid */ bool regular_file; /* must always be valid */ }; typedef struct zip_source_file_context zip_source_file_context_t; typedef struct zip_source_file_operations zip_source_file_operations_t; typedef struct zip_source_file_stat zip_source_file_stat_t; struct zip_source_file_context { zip_error_t error; /* last error information */ zip_int64_t supports; /* reading */ char *fname; /* name of file to read from */ void *f; /* file to read from */ zip_stat_t st; /* stat information passed in */ zip_file_attributes_t attributes; /* additional file attributes */ zip_error_t stat_error; /* error returned for stat */ zip_uint64_t start; /* start offset of data to read */ zip_uint64_t len; /* length of the file, 0 for up to EOF */ zip_uint64_t offset; /* current offset relative to start (0 is beginning of part we read) */ /* writing */ char *tmpname; void *fout; zip_source_file_operations_t *ops; void *ops_userdata; }; /* The following methods must be implemented to support each feature: - close, read, seek, and stat must always be implemented. - To support specifying the file by name, open, and strdup must be implemented. - For write support, the file must be specified by name and close, commit_write, create_temp_output, remove, rollback_write, and tell must be implemented. - create_temp_output_cloning is always optional. */ struct zip_source_file_operations { void (*close)(zip_source_file_context_t *ctx); zip_int64_t (*commit_write)(zip_source_file_context_t *ctx); zip_int64_t (*create_temp_output)(zip_source_file_context_t *ctx); zip_int64_t (*create_temp_output_cloning)(zip_source_file_context_t *ctx, zip_uint64_t len); bool (*open)(zip_source_file_context_t *ctx); zip_int64_t (*read)(zip_source_file_context_t *ctx, void *buf, zip_uint64_t len); zip_int64_t (*remove)(zip_source_file_context_t *ctx); void (*rollback_write)(zip_source_file_context_t *ctx); bool (*seek)(zip_source_file_context_t *ctx, void *f, zip_int64_t offset, int whence); bool (*stat)(zip_source_file_context_t *ctx, zip_source_file_stat_t *st); char *(*string_duplicate)(zip_source_file_context_t *ctx, const char *); zip_int64_t (*tell)(zip_source_file_context_t *ctx, void *f); zip_int64_t (*write)(zip_source_file_context_t *ctx, const void *data, zip_uint64_t len); }; zip_source_t *zip_source_file_common_new(const char *fname, void *file, zip_uint64_t start, zip_int64_t len, const zip_stat_t *st, zip_source_file_operations_t *ops, void *ops_userdata, zip_error_t *error); #endif /* _HAD_ZIP_SOURCE_FILE_H */ ================================================ FILE: external/libzip/lib/zip_source_file_common.c ================================================ /* zip_source_file_common.c -- create data source from file Copyright (C) 1999-2023 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include "zipint.h" #include "zip_source_file.h" static zip_int64_t read_file(void *state, void *data, zip_uint64_t len, zip_source_cmd_t cmd); static void zip_source_file_stat_init(zip_source_file_stat_t *st) { st->size = 0; st->mtime = time(NULL); st->exists = false; st->regular_file = false; } zip_source_t * zip_source_file_common_new(const char *fname, void *file, zip_uint64_t start, zip_int64_t len, const zip_stat_t *st, zip_source_file_operations_t *ops, void *ops_userdata, zip_error_t *error) { zip_source_file_context_t *ctx; zip_source_t *zs; zip_source_file_stat_t sb; zip_uint64_t length; if (ops == NULL) { zip_error_set(error, ZIP_ER_INVAL, 0); return NULL; } if (ops->close == NULL || ops->read == NULL || ops->seek == NULL || ops->stat == NULL) { zip_error_set(error, ZIP_ER_INTERNAL, 0); return NULL; } if (ops->write != NULL && (ops->commit_write == NULL || ops->create_temp_output == NULL || ops->remove == NULL || ops->rollback_write == NULL || ops->tell == NULL)) { zip_error_set(error, ZIP_ER_INTERNAL, 0); return NULL; } if (fname != NULL) { if (ops->open == NULL || ops->string_duplicate == NULL) { zip_error_set(error, ZIP_ER_INTERNAL, 0); return NULL; } } else if (file == NULL) { zip_error_set(error, ZIP_ER_INVAL, 0); return NULL; } if (len < 0) { if (len == -1) { len = ZIP_LENGTH_TO_END; } // TODO: return ZIP_ER_INVAL if len != ZIP_LENGTH_UNCHECKED? length = 0; } else { length = (zip_uint64_t)len; } if (start > ZIP_INT64_MAX || start + length < start) { zip_error_set(error, ZIP_ER_INVAL, 0); return NULL; } if ((ctx = (zip_source_file_context_t *)malloc(sizeof(zip_source_file_context_t))) == NULL) { zip_error_set(error, ZIP_ER_MEMORY, 0); return NULL; } ctx->ops = ops; ctx->ops_userdata = ops_userdata; ctx->fname = NULL; if (fname) { if ((ctx->fname = ops->string_duplicate(ctx, fname)) == NULL) { zip_error_set(error, ZIP_ER_MEMORY, 0); free(ctx); return NULL; } } ctx->f = file; ctx->start = start; ctx->len = length; if (st) { (void)memcpy_s(&ctx->st, sizeof(ctx->st), st, sizeof(*st)); ctx->st.name = NULL; ctx->st.valid &= ~ZIP_STAT_NAME; } else { zip_stat_init(&ctx->st); } if (ctx->len > 0) { ctx->st.size = ctx->len; ctx->st.valid |= ZIP_STAT_SIZE; } zip_error_init(&ctx->stat_error); ctx->tmpname = NULL; ctx->fout = NULL; zip_error_init(&ctx->error); zip_file_attributes_init(&ctx->attributes); ctx->supports = ZIP_SOURCE_SUPPORTS_READABLE | zip_source_make_command_bitmap(ZIP_SOURCE_SUPPORTS, ZIP_SOURCE_TELL, ZIP_SOURCE_SUPPORTS_REOPEN, -1); zip_source_file_stat_init(&sb); if (!ops->stat(ctx, &sb)) { _zip_error_copy(error, &ctx->error); free(ctx->fname); free(ctx); return NULL; } if (!sb.exists) { if (ctx->fname && ctx->start == 0 && ctx->len == 0 && ops->write != NULL) { ctx->supports = ZIP_SOURCE_SUPPORTS_WRITABLE; /* zip_open_from_source checks for this to detect non-existing files */ zip_error_set(&ctx->stat_error, ZIP_ER_READ, ENOENT); } else { zip_error_set(&ctx->stat_error, ZIP_ER_READ, ENOENT); free(ctx->fname); free(ctx); return NULL; } } else { if ((ctx->st.valid & ZIP_STAT_MTIME) == 0) { ctx->st.mtime = sb.mtime; ctx->st.valid |= ZIP_STAT_MTIME; } if (sb.regular_file) { ctx->supports = ZIP_SOURCE_SUPPORTS_SEEKABLE; if (ctx->start + ctx->len > sb.size) { zip_error_set(error, ZIP_ER_INVAL, 0); free(ctx->fname); free(ctx); return NULL; } if (ctx->len == 0) { if (len != ZIP_LENGTH_UNCHECKED) { ctx->len = sb.size - ctx->start; ctx->st.size = ctx->len; ctx->st.valid |= ZIP_STAT_SIZE; } /* when using a partial file, don't allow writing */ if (ctx->fname && start == 0 && ops->write != NULL) { ctx->supports = ZIP_SOURCE_SUPPORTS_WRITABLE; } } } ctx->supports |= ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_GET_FILE_ATTRIBUTES); } ctx->supports |= ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_ACCEPT_EMPTY); if (ops->create_temp_output_cloning != NULL) { if (ctx->supports & ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_BEGIN_WRITE)) { ctx->supports |= ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_BEGIN_WRITE_CLONING); } } if ((zs = zip_source_function_create(read_file, ctx, error)) == NULL) { free(ctx->fname); free(ctx); return NULL; } return zs; } static zip_int64_t read_file(void *state, void *data, zip_uint64_t len, zip_source_cmd_t cmd) { zip_source_file_context_t *ctx; char *buf; ctx = (zip_source_file_context_t *)state; buf = (char *)data; switch (cmd) { case ZIP_SOURCE_ACCEPT_EMPTY: return 0; case ZIP_SOURCE_BEGIN_WRITE: /* write support should not be set if fname is NULL */ if (ctx->fname == NULL) { zip_error_set(&ctx->error, ZIP_ER_INTERNAL, 0); return -1; } return ctx->ops->create_temp_output(ctx); case ZIP_SOURCE_BEGIN_WRITE_CLONING: /* write support should not be set if fname is NULL */ if (ctx->fname == NULL) { zip_error_set(&ctx->error, ZIP_ER_INTERNAL, 0); return -1; } return ctx->ops->create_temp_output_cloning(ctx, len); case ZIP_SOURCE_CLOSE: if (ctx->fname) { ctx->ops->close(ctx); ctx->f = NULL; } return 0; case ZIP_SOURCE_COMMIT_WRITE: { zip_int64_t ret = ctx->ops->commit_write(ctx); ctx->fout = NULL; if (ret == 0) { free(ctx->tmpname); ctx->tmpname = NULL; } return ret; } case ZIP_SOURCE_ERROR: return zip_error_to_data(&ctx->error, data, len); case ZIP_SOURCE_FREE: free(ctx->fname); free(ctx->tmpname); if (ctx->f) { ctx->ops->close(ctx); } free(ctx); return 0; case ZIP_SOURCE_GET_FILE_ATTRIBUTES: if (len < sizeof(ctx->attributes)) { zip_error_set(&ctx->error, ZIP_ER_INVAL, 0); return -1; } (void)memcpy_s(data, sizeof(ctx->attributes), &ctx->attributes, sizeof(ctx->attributes)); return sizeof(ctx->attributes); case ZIP_SOURCE_OPEN: if (ctx->fname) { if (ctx->ops->open(ctx) == false) { return -1; } } if (ctx->start > 0) { /* TODO: rewind on re-open */ if (ctx->ops->seek(ctx, ctx->f, (zip_int64_t)ctx->start, SEEK_SET) == false) { /* TODO: skip by reading */ return -1; } } ctx->offset = 0; return 0; case ZIP_SOURCE_READ: { zip_int64_t i; zip_uint64_t n; if (ctx->len > 0) { n = ZIP_MIN(ctx->len - ctx->offset, len); } else { n = len; } if ((i = ctx->ops->read(ctx, buf, n)) < 0) { zip_error_set(&ctx->error, ZIP_ER_READ, errno); return -1; } ctx->offset += (zip_uint64_t)i; return i; } case ZIP_SOURCE_REMOVE: return ctx->ops->remove(ctx); case ZIP_SOURCE_ROLLBACK_WRITE: ctx->ops->rollback_write(ctx); ctx->fout = NULL; free(ctx->tmpname); ctx->tmpname = NULL; return 0; case ZIP_SOURCE_SEEK: { zip_int64_t new_offset = zip_source_seek_compute_offset(ctx->offset, ctx->len, data, len, &ctx->error); if (new_offset < 0) { return -1; } /* The actual offset inside the file must be representable as zip_int64_t. */ if (new_offset > ZIP_INT64_MAX - (zip_int64_t)ctx->start) { zip_error_set(&ctx->error, ZIP_ER_SEEK, EOVERFLOW); return -1; } ctx->offset = (zip_uint64_t)new_offset; if (ctx->ops->seek(ctx, ctx->f, (zip_int64_t)(ctx->offset + ctx->start), SEEK_SET) == false) { return -1; } return 0; } case ZIP_SOURCE_SEEK_WRITE: { zip_source_args_seek_t *args; args = ZIP_SOURCE_GET_ARGS(zip_source_args_seek_t, data, len, &ctx->error); if (args == NULL) { return -1; } if (ctx->ops->seek(ctx, ctx->fout, args->offset, args->whence) == false) { return -1; } return 0; } case ZIP_SOURCE_STAT: { if (len < sizeof(ctx->st)) return -1; if (zip_error_code_zip(&ctx->stat_error) != 0) { zip_error_set(&ctx->error, zip_error_code_zip(&ctx->stat_error), zip_error_code_system(&ctx->stat_error)); return -1; } (void)memcpy_s(data, sizeof(ctx->st), &ctx->st, sizeof(ctx->st)); return sizeof(ctx->st); } case ZIP_SOURCE_SUPPORTS: return ctx->supports; case ZIP_SOURCE_TELL: return (zip_int64_t)ctx->offset; case ZIP_SOURCE_TELL_WRITE: return ctx->ops->tell(ctx, ctx->fout); case ZIP_SOURCE_WRITE: return ctx->ops->write(ctx, data, len); default: zip_error_set(&ctx->error, ZIP_ER_OPNOTSUPP, 0); return -1; } } ================================================ FILE: external/libzip/lib/zip_source_file_stdio.c ================================================ /* zip_source_file_stdio.c -- read-only stdio file source implementation Copyright (C) 2020-2023 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "zipint.h" #include "zip_source_file.h" #include "zip_source_file_stdio.h" #include #include #include #ifdef _WIN32 #ifndef S_IWUSR #define S_IWUSR _S_IWRITE #endif #endif /* clang-format off */ static zip_source_file_operations_t ops_stdio_read = { _zip_stdio_op_close, NULL, NULL, NULL, NULL, _zip_stdio_op_read, NULL, NULL, _zip_stdio_op_seek, _zip_stdio_op_stat, NULL, _zip_stdio_op_tell, NULL }; /* clang-format on */ ZIP_EXTERN zip_source_t * zip_source_filep(zip_t *za, FILE *file, zip_uint64_t start, zip_int64_t len) { if (za == NULL) { return NULL; } return zip_source_filep_create(file, start, len, &za->error); } ZIP_EXTERN zip_source_t * zip_source_filep_create(FILE *file, zip_uint64_t start, zip_int64_t length, zip_error_t *error) { if (file == NULL || length < ZIP_LENGTH_UNCHECKED) { zip_error_set(error, ZIP_ER_INVAL, 0); return NULL; } return zip_source_file_common_new(NULL, file, start, length, NULL, &ops_stdio_read, NULL, error); } void _zip_stdio_op_close(zip_source_file_context_t *ctx) { fclose((FILE *)ctx->f); } zip_int64_t _zip_stdio_op_read(zip_source_file_context_t *ctx, void *buf, zip_uint64_t len) { size_t i; #if SIZE_MAX < ZIP_UINT64_MAX if (len > SIZE_MAX) { len = SIZE_MAX; } #endif if ((i = fread(buf, 1, (size_t)len, ctx->f)) == 0) { if (ferror((FILE *)ctx->f)) { zip_error_set(&ctx->error, ZIP_ER_READ, errno); return -1; } } return (zip_int64_t)i; } bool _zip_stdio_op_seek(zip_source_file_context_t *ctx, void *f, zip_int64_t offset, int whence) { #if ZIP_FSEEK_MAX > ZIP_INT64_MAX if (offset > ZIP_FSEEK_MAX || offset < ZIP_FSEEK_MIN) { zip_error_set(&ctx->error, ZIP_ER_SEEK, EOVERFLOW); return false; } #endif if (zip_os_fseek((FILE *)f, (zip_off_t)offset, whence) < 0) { zip_error_set(&ctx->error, ZIP_ER_SEEK, errno); return false; } return true; } bool _zip_stdio_op_stat(zip_source_file_context_t *ctx, zip_source_file_stat_t *st) { zip_os_stat_t sb; int ret; if (ctx->fname) { ret = zip_os_stat(ctx->fname, &sb); } else { ret = zip_os_fstat(fileno((FILE *)ctx->f), &sb); } if (ret < 0) { if (errno == ENOENT) { st->exists = false; return true; } zip_error_set(&ctx->error, ZIP_ER_READ, errno); return false; } st->size = (zip_uint64_t)sb.st_size; st->mtime = sb.st_mtime; st->regular_file = S_ISREG(sb.st_mode); st->exists = true; /* We're using UNIX file API, even on Windows; thus, we supply external file attributes with Unix values. */ /* TODO: This could be improved on Windows by providing Windows-specific file attributes */ ctx->attributes.valid = ZIP_FILE_ATTRIBUTES_HOST_SYSTEM | ZIP_FILE_ATTRIBUTES_EXTERNAL_FILE_ATTRIBUTES; ctx->attributes.host_system = ZIP_OPSYS_UNIX; ctx->attributes.external_file_attributes = (((zip_uint32_t)sb.st_mode) << 16) | ((sb.st_mode & S_IWUSR) ? 0 : 1); return true; } zip_int64_t _zip_stdio_op_tell(zip_source_file_context_t *ctx, void *f) { zip_off_t offset = zip_os_ftell((FILE *)f); if (offset < 0) { zip_error_set(&ctx->error, ZIP_ER_SEEK, errno); } return offset; } ================================================ FILE: external/libzip/lib/zip_source_file_stdio.h ================================================ #ifndef _HAD_ZIP_SOURCE_FILE_STDIO_H #define _HAD_ZIP_SOURCE_FILE_STDIO_H /* zip_source_file_stdio.h -- common header for stdio file implementation Copyright (C) 2020-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include void _zip_stdio_op_close(zip_source_file_context_t *ctx); zip_int64_t _zip_stdio_op_read(zip_source_file_context_t *ctx, void *buf, zip_uint64_t len); bool _zip_stdio_op_seek(zip_source_file_context_t *ctx, void *f, zip_int64_t offset, int whence); bool _zip_stdio_op_stat(zip_source_file_context_t *ctx, zip_source_file_stat_t *st); zip_int64_t _zip_stdio_op_tell(zip_source_file_context_t *ctx, void *f); #endif /* _HAD_ZIP_SOURCE_FILE_STDIO_H */ ================================================ FILE: external/libzip/lib/zip_source_file_stdio_named.c ================================================ /* zip_source_file_stdio_named.c -- source for stdio file opened by name Copyright (C) 1999-2023 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "zipint.h" #include "zip_source_file.h" #include "zip_source_file_stdio.h" #include #include #include #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_CLONEFILE #include #include #define CAN_CLONE #endif #ifdef HAVE_FICLONERANGE #include #include #define CAN_CLONE #endif static int create_temp_file(zip_source_file_context_t *ctx, bool create_file); static zip_int64_t _zip_stdio_op_commit_write(zip_source_file_context_t *ctx); static zip_int64_t _zip_stdio_op_create_temp_output(zip_source_file_context_t *ctx); #ifdef CAN_CLONE static zip_int64_t _zip_stdio_op_create_temp_output_cloning(zip_source_file_context_t *ctx, zip_uint64_t offset); #endif static bool _zip_stdio_op_open(zip_source_file_context_t *ctx); static zip_int64_t _zip_stdio_op_remove(zip_source_file_context_t *ctx); static void _zip_stdio_op_rollback_write(zip_source_file_context_t *ctx); static char *_zip_stdio_op_strdup(zip_source_file_context_t *ctx, const char *string); static zip_int64_t _zip_stdio_op_write(zip_source_file_context_t *ctx, const void *data, zip_uint64_t len); static FILE *_zip_fopen_close_on_exec(const char *name, bool writeable); /* clang-format off */ static zip_source_file_operations_t ops_stdio_named = { _zip_stdio_op_close, _zip_stdio_op_commit_write, _zip_stdio_op_create_temp_output, #ifdef CAN_CLONE _zip_stdio_op_create_temp_output_cloning, #else NULL, #endif _zip_stdio_op_open, _zip_stdio_op_read, _zip_stdio_op_remove, _zip_stdio_op_rollback_write, _zip_stdio_op_seek, _zip_stdio_op_stat, _zip_stdio_op_strdup, _zip_stdio_op_tell, _zip_stdio_op_write }; /* clang-format on */ ZIP_EXTERN zip_source_t * zip_source_file(zip_t *za, const char *fname, zip_uint64_t start, zip_int64_t len) { if (za == NULL) return NULL; return zip_source_file_create(fname, start, len, &za->error); } ZIP_EXTERN zip_source_t * zip_source_file_create(const char *fname, zip_uint64_t start, zip_int64_t length, zip_error_t *error) { if (fname == NULL || length < ZIP_LENGTH_UNCHECKED) { zip_error_set(error, ZIP_ER_INVAL, 0); return NULL; } return zip_source_file_common_new(fname, NULL, start, length, NULL, &ops_stdio_named, NULL, error); } static zip_int64_t _zip_stdio_op_commit_write(zip_source_file_context_t *ctx) { if (fclose(ctx->fout) < 0) { zip_error_set(&ctx->error, ZIP_ER_WRITE, errno); return -1; } if (rename(ctx->tmpname, ctx->fname) < 0) { zip_error_set(&ctx->error, ZIP_ER_RENAME, errno); return -1; } return 0; } static zip_int64_t _zip_stdio_op_create_temp_output(zip_source_file_context_t *ctx) { int fd = create_temp_file(ctx, true); if (fd < 0) { return -1; } if ((ctx->fout = fdopen(fd, "r+b")) == NULL) { zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno); close(fd); (void)remove(ctx->tmpname); free(ctx->tmpname); ctx->tmpname = NULL; return -1; } return 0; } #ifdef CAN_CLONE static zip_int64_t _zip_stdio_op_create_temp_output_cloning(zip_source_file_context_t *ctx, zip_uint64_t offset) { FILE *tfp; if (offset > ZIP_OFF_MAX) { zip_error_set(&ctx->error, ZIP_ER_SEEK, E2BIG); return -1; } #ifdef HAVE_CLONEFILE /* clonefile insists on creating the file, so just create a name */ if (create_temp_file(ctx, false) < 0) { return -1; } if (clonefile(ctx->fname, ctx->tmpname, 0) < 0) { zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno); free(ctx->tmpname); ctx->tmpname = NULL; return -1; } if ((tfp = _zip_fopen_close_on_exec(ctx->tmpname, true)) == NULL) { zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno); (void)remove(ctx->tmpname); free(ctx->tmpname); ctx->tmpname = NULL; return -1; } #else { int fd; struct file_clone_range range; zip_os_stat_t st; if (zip_os_fstat(fileno(ctx->f), &st) < 0) { zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno); return -1; } if ((fd = create_temp_file(ctx, true)) < 0) { return -1; } range.src_fd = fileno(ctx->f); range.src_offset = 0; range.src_length = ((offset + st.st_blksize - 1) / st.st_blksize) * st.st_blksize; if (range.src_length > st.st_size) { range.src_length = 0; } range.dest_offset = 0; if (ioctl(fd, FICLONERANGE, &range) < 0) { zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno); (void)close(fd); (void)remove(ctx->tmpname); free(ctx->tmpname); ctx->tmpname = NULL; return -1; } if ((tfp = fdopen(fd, "r+b")) == NULL) { zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno); (void)close(fd); (void)remove(ctx->tmpname); free(ctx->tmpname); ctx->tmpname = NULL; return -1; } } #endif if (ftruncate(fileno(tfp), (off_t)offset) < 0) { (void)fclose(tfp); (void)remove(ctx->tmpname); free(ctx->tmpname); ctx->tmpname = NULL; return -1; } if (zip_os_fseek(tfp, (zip_off_t)offset, SEEK_SET) < 0) { zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno); (void)fclose(tfp); (void)remove(ctx->tmpname); free(ctx->tmpname); ctx->tmpname = NULL; return -1; } ctx->fout = tfp; return 0; } #endif static bool _zip_stdio_op_open(zip_source_file_context_t *ctx) { if ((ctx->f = _zip_fopen_close_on_exec(ctx->fname, false)) == NULL) { zip_error_set(&ctx->error, ZIP_ER_OPEN, errno); return false; } return true; } static zip_int64_t _zip_stdio_op_remove(zip_source_file_context_t *ctx) { if (remove(ctx->fname) < 0) { zip_error_set(&ctx->error, ZIP_ER_REMOVE, errno); return -1; } return 0; } static void _zip_stdio_op_rollback_write(zip_source_file_context_t *ctx) { if (ctx->fout) { fclose(ctx->fout); } (void)remove(ctx->tmpname); } static char * _zip_stdio_op_strdup(zip_source_file_context_t *ctx, const char *string) { return strdup(string); } static zip_int64_t _zip_stdio_op_write(zip_source_file_context_t *ctx, const void *data, zip_uint64_t len) { size_t ret; clearerr((FILE *)ctx->fout); ret = fwrite(data, 1, len, (FILE *)ctx->fout); if (ret != len || ferror((FILE *)ctx->fout)) { zip_error_set(&ctx->error, ZIP_ER_WRITE, errno); return -1; } return (zip_int64_t)ret; } static int create_temp_file(zip_source_file_context_t *ctx, bool create_file) { char *temp; int mode; zip_os_stat_t st; int fd = 0; char *start, *end; if (zip_os_stat(ctx->fname, &st) == 0) { mode = st.st_mode; } else { mode = -1; } size_t temp_size = strlen(ctx->fname) + 13; if ((temp = (char *)malloc(temp_size)) == NULL) { zip_error_set(&ctx->error, ZIP_ER_MEMORY, 0); return -1; } snprintf_s(temp, temp_size, "%s.XXXXXX.part", ctx->fname); end = temp + strlen(temp) - 5; start = end - 6; for (;;) { zip_uint32_t value = zip_random_uint32(); char *xs = start; while (xs < end) { char digit = value % 36; if (digit < 10) { *(xs++) = digit + '0'; } else { *(xs++) = digit - 10 + 'a'; } value /= 36; } if (create_file) { if ((fd = open(temp, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC, mode == -1 ? 0666 : (mode_t)mode)) >= 0) { if (mode != -1) { /* open() honors umask(), which we don't want in this case */ #ifdef HAVE_FCHMOD (void)fchmod(fd, (mode_t)mode); #else (void)chmod(temp, (mode_t)mode); #endif } break; } if (errno != EEXIST) { zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno); free(temp); return -1; } } else { if (zip_os_stat(temp, &st) < 0) { if (errno == ENOENT) { break; } else { zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno); free(temp); return -1; } } } } ctx->tmpname = temp; return fd; /* initialized to 0 if !create_file */ } /* * fopen replacement that sets the close-on-exec flag * some implementations support an fopen 'e' flag for that, * but e.g. macOS doesn't. */ static FILE *_zip_fopen_close_on_exec(const char *name, bool writeable) { int fd; int flags; FILE *fp; flags = O_CLOEXEC; if (writeable) { flags |= O_RDWR; } else { flags |= O_RDONLY; } /* mode argument needed on Windows */ if ((fd = open(name, flags, 0666)) < 0) { return NULL; } if ((fp = fdopen(fd, writeable ? "r+b" : "rb")) == NULL) { return NULL; } return fp; } ================================================ FILE: external/libzip/lib/zip_source_file_win32.c ================================================ /* zip_source_file_win32.c -- read-only Windows file source implementation Copyright (C) 1999-2023 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "zip_source_file_win32.h" static bool _zip_win32_op_stat(zip_source_file_context_t *ctx, zip_source_file_stat_t *st); static bool _zip_stat_win32(zip_source_file_context_t *ctx, zip_source_file_stat_t *st, HANDLE h); /* clang-format off */ static zip_source_file_operations_t ops_win32_read = { _zip_win32_op_close, NULL, NULL, NULL, NULL, _zip_win32_op_read, NULL, NULL, _zip_win32_op_seek, _zip_win32_op_stat, NULL, _zip_win32_op_tell, NULL }; /* clang-format on */ ZIP_EXTERN zip_source_t * zip_source_win32handle(zip_t *za, HANDLE h, zip_uint64_t start, zip_int64_t len) { if (za == NULL) { return NULL; } return zip_source_win32handle_create(h, start, len, &za->error); } ZIP_EXTERN zip_source_t * zip_source_win32handle_create(HANDLE h, zip_uint64_t start, zip_int64_t length, zip_error_t *error) { if (h == INVALID_HANDLE_VALUE || length < ZIP_LENGTH_UNCHECKED) { zip_error_set(error, ZIP_ER_INVAL, 0); return NULL; } return zip_source_file_common_new(NULL, h, start, length, NULL, &ops_win32_read, NULL, error); } void _zip_win32_op_close(zip_source_file_context_t *ctx) { CloseHandle((HANDLE)ctx->f); } zip_int64_t _zip_win32_op_read(zip_source_file_context_t *ctx, void *buf, zip_uint64_t len) { DWORD i; /* TODO: cap len to "DWORD_MAX" */ if (!ReadFile((HANDLE)ctx->f, buf, (DWORD)len, &i, NULL)) { zip_error_set(&ctx->error, ZIP_ER_READ, _zip_win32_error_to_errno(GetLastError())); return -1; } return (zip_int64_t)i; } bool _zip_win32_op_seek(zip_source_file_context_t *ctx, void *f, zip_int64_t offset, int whence) { LARGE_INTEGER li; DWORD method; switch (whence) { case SEEK_SET: method = FILE_BEGIN; break; case SEEK_END: method = FILE_END; break; case SEEK_CUR: method = FILE_CURRENT; break; default: zip_error_set(&ctx->error, ZIP_ER_SEEK, EINVAL); return false; } li.QuadPart = (LONGLONG)offset; if (!SetFilePointerEx((HANDLE)f, li, NULL, method)) { zip_error_set(&ctx->error, ZIP_ER_SEEK, _zip_win32_error_to_errno(GetLastError())); return false; } return true; } static bool _zip_win32_op_stat(zip_source_file_context_t *ctx, zip_source_file_stat_t *st) { return _zip_stat_win32(ctx, st, (HANDLE)ctx->f); } zip_int64_t _zip_win32_op_tell(zip_source_file_context_t *ctx, void *f) { LARGE_INTEGER zero; LARGE_INTEGER new_offset; zero.QuadPart = 0; if (!SetFilePointerEx((HANDLE)f, zero, &new_offset, FILE_CURRENT)) { zip_error_set(&ctx->error, ZIP_ER_SEEK, _zip_win32_error_to_errno(GetLastError())); return -1; } return (zip_int64_t)new_offset.QuadPart; } int _zip_win32_error_to_errno(DWORD win32err) { /* Note: This list isn't exhaustive, but should cover common cases. */ switch (win32err) { case ERROR_INVALID_PARAMETER: return EINVAL; case ERROR_FILE_NOT_FOUND: case ERROR_PATH_NOT_FOUND: return ENOENT; case ERROR_INVALID_HANDLE: return EBADF; case ERROR_ACCESS_DENIED: return EACCES; case ERROR_FILE_EXISTS: return EEXIST; case ERROR_TOO_MANY_OPEN_FILES: return EMFILE; case ERROR_DISK_FULL: return ENOSPC; default: return 10000 + win32err; } } static bool _zip_stat_win32(zip_source_file_context_t *ctx, zip_source_file_stat_t *st, HANDLE h) { FILETIME mtimeft; time_t mtime; LARGE_INTEGER size; if (!GetFileTime(h, NULL, NULL, &mtimeft)) { zip_error_set(&ctx->error, ZIP_ER_READ, _zip_win32_error_to_errno(GetLastError())); return false; } if (!_zip_filetime_to_time_t(mtimeft, &mtime)) { zip_error_set(&ctx->error, ZIP_ER_READ, ERANGE); return false; } st->exists = true; st->mtime = mtime; if (GetFileType(h) == FILE_TYPE_DISK) { st->regular_file = 1; if (!GetFileSizeEx(h, &size)) { zip_error_set(&ctx->error, ZIP_ER_READ, _zip_win32_error_to_errno(GetLastError())); return false; } st->size = (zip_uint64_t)size.QuadPart; } /* TODO: fill in ctx->attributes */ return true; } bool _zip_filetime_to_time_t(FILETIME ft, time_t *t) { /* Inspired by http://stackoverflow.com/questions/6161776/convert-windows-filetime-to-second-in-unix-linux */ const zip_int64_t WINDOWS_TICK = 10000000LL; const zip_int64_t SEC_TO_UNIX_EPOCH = 11644473600LL; ULARGE_INTEGER li; zip_int64_t secs; time_t temp; li.LowPart = ft.dwLowDateTime; li.HighPart = ft.dwHighDateTime; secs = (li.QuadPart / WINDOWS_TICK - SEC_TO_UNIX_EPOCH); temp = (time_t)secs; if (secs != (zip_int64_t)temp) { return false; } *t = temp; return true; } ================================================ FILE: external/libzip/lib/zip_source_file_win32.h ================================================ #ifndef _HAD_ZIP_SOURCE_FILE_WIN32_H #define _HAD_ZIP_SOURCE_FILE_WIN32_H /* zip_source_file_win32.h -- common header for Windows file implementation Copyright (C) 2020-2024 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* 0x0501 => Windows XP; needs to be at least this value because of GetFileSizeEx */ #if !defined(MS_UWP) && !defined(_WIN32_WINNT) #define _WIN32_WINNT 0x0501 #endif #include #include #include #include "zipint.h" #include "zip_source_file.h" struct zip_win32_file_operations { char *(*allocate_tempname)(const char *name, size_t extra_chars, size_t *lengthp); HANDLE(__stdcall *create_file)(const void *name, DWORD access, DWORD share_mode, PSECURITY_ATTRIBUTES security_attributes, DWORD creation_disposition, DWORD file_attributes, HANDLE template_file); BOOL(__stdcall *delete_file)(const void *name); DWORD(__stdcall *get_file_attributes)(const void *name); BOOL(__stdcall *get_file_attributes_ex)(const void *name, GET_FILEEX_INFO_LEVELS info_level, void *information); void (*make_tempname)(char *buf, size_t len, const char *name, zip_uint32_t i); BOOL(__stdcall *move_file)(const void *from, const void *to, DWORD flags); BOOL(__stdcall *set_file_attributes)(const void *name, DWORD attributes); char *(*string_duplicate)(const char *string); HANDLE(__stdcall *find_first_file)(const void *name, void *data); }; typedef struct zip_win32_file_operations zip_win32_file_operations_t; extern zip_source_file_operations_t _zip_source_file_win32_named_ops; void _zip_win32_op_close(zip_source_file_context_t *ctx); zip_int64_t _zip_win32_op_read(zip_source_file_context_t *ctx, void *buf, zip_uint64_t len); bool _zip_win32_op_seek(zip_source_file_context_t *ctx, void *f, zip_int64_t offset, int whence); zip_int64_t _zip_win32_op_tell(zip_source_file_context_t *ctx, void *f); bool _zip_filetime_to_time_t(FILETIME ft, time_t *t); int _zip_win32_error_to_errno(DWORD win32err); #endif /* _HAD_ZIP_SOURCE_FILE_WIN32_H */ ================================================ FILE: external/libzip/lib/zip_source_file_win32_ansi.c ================================================ /* zip_source_file_win32_ansi.c -- source for Windows file opened by ANSI name Copyright (C) 1999-2024 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "zip_source_file_win32.h" static char *ansi_allocate_tempname(const char *name, size_t extra_chars, size_t *lengthp); static HANDLE __stdcall ansi_create_file(const void *name, DWORD access, DWORD share_mode, PSECURITY_ATTRIBUTES security_attributes, DWORD creation_disposition, DWORD file_attributes, HANDLE template_file); static BOOL __stdcall ansi_delete_file(const void *name); static DWORD __stdcall ansi_get_file_attributes(const void *name); static BOOL __stdcall ansi_get_file_attributes_ex(const void *name, GET_FILEEX_INFO_LEVELS info_level, void *information); static void ansi_make_tempname(char *buf, size_t len, const char *name, zip_uint32_t i); static BOOL __stdcall ansi_move_file(const void *from, const void *to, DWORD flags); static BOOL __stdcall ansi_set_file_attributes(const void *name, DWORD attributes); static HANDLE __stdcall ansi_find_first_file(const void *name, void* data); /* clang-format off */ zip_win32_file_operations_t ops_ansi = { ansi_allocate_tempname, ansi_create_file, ansi_delete_file, ansi_get_file_attributes, ansi_get_file_attributes_ex, ansi_make_tempname, ansi_move_file, ansi_set_file_attributes, strdup, ansi_find_first_file, }; /* clang-format on */ ZIP_EXTERN zip_source_t * zip_source_win32a(zip_t *za, const char *fname, zip_uint64_t start, zip_int64_t len) { if (za == NULL) return NULL; return zip_source_win32a_create(fname, start, len, &za->error); } ZIP_EXTERN zip_source_t * zip_source_win32a_create(const char *fname, zip_uint64_t start, zip_int64_t length, zip_error_t *error) { if (fname == NULL || length < ZIP_LENGTH_UNCHECKED) { zip_error_set(error, ZIP_ER_INVAL, 0); return NULL; } return zip_source_file_common_new(fname, NULL, start, length, NULL, &_zip_source_file_win32_named_ops, &ops_ansi, error); } static char * ansi_allocate_tempname(const char *name, size_t extra_chars, size_t *lengthp) { *lengthp = strlen(name) + extra_chars; return (char *)malloc(*lengthp); } static HANDLE __stdcall ansi_create_file(const void *name, DWORD access, DWORD share_mode, PSECURITY_ATTRIBUTES security_attributes, DWORD creation_disposition, DWORD file_attributes, HANDLE template_file) { return CreateFileA((const char *)name, access, share_mode, security_attributes, creation_disposition, file_attributes, template_file); } static BOOL __stdcall ansi_delete_file(const void *name) { return DeleteFileA((const char *)name); } static DWORD __stdcall ansi_get_file_attributes(const void *name) { return GetFileAttributesA((const char *)name); } static BOOL __stdcall ansi_get_file_attributes_ex(const void *name, GET_FILEEX_INFO_LEVELS info_level, void *information) { return GetFileAttributesExA((const char *)name, info_level, information); } static void ansi_make_tempname(char *buf, size_t len, const char *name, zip_uint32_t i) { snprintf_s(buf, len, "%s.%08x", name, i); } static BOOL __stdcall ansi_move_file(const void *from, const void *to, DWORD flags) { return MoveFileExA((const char *)from, (const char *)to, flags); } static BOOL __stdcall ansi_set_file_attributes(const void *name, DWORD attributes) { return SetFileAttributesA((const char *)name, attributes); } static HANDLE __stdcall ansi_find_first_file(const void *name, void *data) { return FindFirstFileA((const char *)name, data); } ================================================ FILE: external/libzip/lib/zip_source_file_win32_named.c ================================================ /* zip_source_file_win32_named.c -- source for Windows file opened by name Copyright (C) 1999-2024 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "zip_source_file_win32.h" static zip_int64_t _zip_win32_named_op_commit_write(zip_source_file_context_t *ctx); static zip_int64_t _zip_win32_named_op_create_temp_output(zip_source_file_context_t *ctx); static bool _zip_win32_named_op_open(zip_source_file_context_t *ctx); static zip_int64_t _zip_win32_named_op_remove(zip_source_file_context_t *ctx); static void _zip_win32_named_op_rollback_write(zip_source_file_context_t *ctx); static bool _zip_win32_named_op_stat(zip_source_file_context_t *ctx, zip_source_file_stat_t *st); static char *_zip_win32_named_op_string_duplicate(zip_source_file_context_t *ctx, const char *string); static zip_int64_t _zip_win32_named_op_write(zip_source_file_context_t *ctx, const void *data, zip_uint64_t len); static HANDLE win32_named_open(zip_source_file_context_t *ctx, const char *name, bool temporary, PSECURITY_ATTRIBUTES security_attributes); /* clang-format off */ zip_source_file_operations_t _zip_source_file_win32_named_ops = { _zip_win32_op_close, _zip_win32_named_op_commit_write, _zip_win32_named_op_create_temp_output, NULL, _zip_win32_named_op_open, _zip_win32_op_read, _zip_win32_named_op_remove, _zip_win32_named_op_rollback_write, _zip_win32_op_seek, _zip_win32_named_op_stat, _zip_win32_named_op_string_duplicate, _zip_win32_op_tell, _zip_win32_named_op_write }; /* clang-format on */ static zip_int64_t _zip_win32_named_op_commit_write(zip_source_file_context_t *ctx) { zip_win32_file_operations_t *file_ops = (zip_win32_file_operations_t *)ctx->ops_userdata; DWORD attributes; if (!CloseHandle((HANDLE)ctx->fout)) { zip_error_set(&ctx->error, ZIP_ER_WRITE, _zip_win32_error_to_errno(GetLastError())); return -1; } attributes = file_ops->get_file_attributes(ctx->tmpname); if (attributes == INVALID_FILE_ATTRIBUTES) { zip_error_set(&ctx->error, ZIP_ER_RENAME, _zip_win32_error_to_errno(GetLastError())); return -1; } if (attributes & FILE_ATTRIBUTE_TEMPORARY) { if (!file_ops->set_file_attributes(ctx->tmpname, attributes & ~FILE_ATTRIBUTE_TEMPORARY)) { zip_error_set(&ctx->error, ZIP_ER_RENAME, _zip_win32_error_to_errno(GetLastError())); return -1; } } if (!file_ops->move_file(ctx->tmpname, ctx->fname, MOVEFILE_REPLACE_EXISTING)) { zip_error_set(&ctx->error, ZIP_ER_RENAME, _zip_win32_error_to_errno(GetLastError())); return -1; } return 0; } static zip_int64_t _zip_win32_named_op_create_temp_output(zip_source_file_context_t *ctx) { zip_win32_file_operations_t *file_ops = (zip_win32_file_operations_t *)ctx->ops_userdata; zip_uint32_t value, i; HANDLE th = INVALID_HANDLE_VALUE; PSECURITY_ATTRIBUTES psa = NULL; PSECURITY_DESCRIPTOR psd = NULL; #ifdef HAVE_GETSECURITYINFO SECURITY_ATTRIBUTES sa; #endif char *tempname = NULL; size_t tempname_size = 0; #ifdef HAVE_GETSECURITYINFO if ((HANDLE)ctx->f != INVALID_HANDLE_VALUE && GetFileType((HANDLE)ctx->f) == FILE_TYPE_DISK) { if (GetSecurityInfo((HANDLE)ctx->f, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION | UNPROTECTED_DACL_SECURITY_INFORMATION, NULL, NULL, NULL, NULL, &psd) == ERROR_SUCCESS) { sa.nLength = sizeof(SECURITY_ATTRIBUTES); sa.bInheritHandle = FALSE; sa.lpSecurityDescriptor = psd; psa = &sa; } } #endif #ifndef MS_UWP value = GetTickCount(); #else value = (zip_uint32_t)(GetTickCount64() & 0xffffffff); #endif if ((tempname = file_ops->allocate_tempname(ctx->fname, 10, &tempname_size)) == NULL) { zip_error_set(&ctx->error, ZIP_ER_MEMORY, 0); return -1; } for (i = 0; i < 1024 && th == INVALID_HANDLE_VALUE; i++) { file_ops->make_tempname(tempname, tempname_size, ctx->fname, value + i); th = win32_named_open(ctx, tempname, true, psa); if (th == INVALID_HANDLE_VALUE && GetLastError() != ERROR_FILE_EXISTS) break; } if (th == INVALID_HANDLE_VALUE) { free(tempname); LocalFree(psd); zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, _zip_win32_error_to_errno(GetLastError())); return -1; } LocalFree(psd); ctx->fout = th; ctx->tmpname = tempname; return 0; } static bool _zip_win32_named_op_open(zip_source_file_context_t *ctx) { HANDLE h = win32_named_open(ctx, ctx->fname, false, NULL); if (h == INVALID_HANDLE_VALUE) { return false; } ctx->f = h; return true; } static zip_int64_t _zip_win32_named_op_remove(zip_source_file_context_t *ctx) { zip_win32_file_operations_t *file_ops = (zip_win32_file_operations_t *)ctx->ops_userdata; if (!file_ops->delete_file(ctx->fname)) { zip_error_set(&ctx->error, ZIP_ER_REMOVE, _zip_win32_error_to_errno(GetLastError())); return -1; } return 0; } static void _zip_win32_named_op_rollback_write(zip_source_file_context_t *ctx) { zip_win32_file_operations_t *file_ops = (zip_win32_file_operations_t *)ctx->ops_userdata; if (ctx->fout) { CloseHandle((HANDLE)ctx->fout); } file_ops->delete_file(ctx->tmpname); } static bool _zip_win32_named_op_stat(zip_source_file_context_t *ctx, zip_source_file_stat_t *st) { zip_win32_file_operations_t *file_ops = (zip_win32_file_operations_t *)ctx->ops_userdata; WIN32_FILE_ATTRIBUTE_DATA file_attributes; if (!file_ops->get_file_attributes_ex(ctx->fname, GetFileExInfoStandard, &file_attributes)) { DWORD error = GetLastError(); if (error == ERROR_FILE_NOT_FOUND) { st->exists = false; return true; } zip_error_set(&ctx->error, ZIP_ER_READ, _zip_win32_error_to_errno(error)); return false; } st->exists = true; st->regular_file = false; if (file_attributes.dwFileAttributes != INVALID_FILE_ATTRIBUTES) { if ((file_attributes.dwFileAttributes & (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_DEVICE)) == 0) { if (file_attributes.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { WIN32_FIND_DATA find_data; /* Deduplication on Windows replaces files with reparse points; * accept them as regular files. */ if (file_ops->find_first_file(ctx->fname, &find_data) != INVALID_HANDLE_VALUE) { st->regular_file = (find_data.dwReserved0 == IO_REPARSE_TAG_DEDUP); } } else { st->regular_file = true; } } } if (!_zip_filetime_to_time_t(file_attributes.ftLastWriteTime, &st->mtime)) { zip_error_set(&ctx->error, ZIP_ER_READ, ERANGE); return false; } st->size = ((zip_uint64_t)file_attributes.nFileSizeHigh << 32) | file_attributes.nFileSizeLow; /* TODO: fill in ctx->attributes */ return true; } static char * _zip_win32_named_op_string_duplicate(zip_source_file_context_t *ctx, const char *string) { zip_win32_file_operations_t *file_ops = (zip_win32_file_operations_t *)ctx->ops_userdata; return file_ops->string_duplicate(string); } static zip_int64_t _zip_win32_named_op_write(zip_source_file_context_t *ctx, const void *data, zip_uint64_t len) { DWORD ret; if (!WriteFile((HANDLE)ctx->fout, data, (DWORD)len, &ret, NULL) || ret != len) { zip_error_set(&ctx->error, ZIP_ER_WRITE, _zip_win32_error_to_errno(GetLastError())); return -1; } return (zip_int64_t)ret; } static HANDLE win32_named_open(zip_source_file_context_t *ctx, const char *name, bool temporary, PSECURITY_ATTRIBUTES security_attributes) { zip_win32_file_operations_t *file_ops = (zip_win32_file_operations_t *)ctx->ops_userdata; DWORD access = GENERIC_READ; DWORD share_mode = FILE_SHARE_READ | FILE_SHARE_WRITE; DWORD creation_disposition = OPEN_EXISTING; DWORD file_attributes = FILE_ATTRIBUTE_NORMAL; HANDLE h; if (temporary) { access = GENERIC_READ | GENERIC_WRITE; share_mode = FILE_SHARE_READ; creation_disposition = CREATE_NEW; file_attributes = FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_TEMPORARY; } h = file_ops->create_file(name, access, share_mode, security_attributes, creation_disposition, file_attributes, NULL); if (h == INVALID_HANDLE_VALUE) { zip_error_set(&ctx->error, ZIP_ER_OPEN, _zip_win32_error_to_errno(GetLastError())); } return h; } ================================================ FILE: external/libzip/lib/zip_source_file_win32_utf16.c ================================================ /* zip_source_file_win32_utf16.c -- source for Windows file opened by UTF-16 name Copyright (C) 1999-2024 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "zip_source_file_win32.h" static char *utf16_allocate_tempname(const char *name, size_t extra_chars, size_t *lengthp); static HANDLE __stdcall utf16_create_file(const void *name, DWORD access, DWORD share_mode, PSECURITY_ATTRIBUTES security_attributes, DWORD creation_disposition, DWORD file_attributes, HANDLE template_file); static BOOL __stdcall utf16_delete_file(const void *name); static DWORD __stdcall utf16_get_file_attributes(const void *name); static BOOL __stdcall utf16_get_file_attributes_ex(const void *name, GET_FILEEX_INFO_LEVELS info_level, void *information); static void utf16_make_tempname(char *buf, size_t len, const char *name, zip_uint32_t i); static BOOL __stdcall utf16_move_file(const void *from, const void *to, DWORD flags); static BOOL __stdcall utf16_set_file_attributes(const void *name, DWORD attributes); static char *utf16_strdup(const char *string); static HANDLE __stdcall utf16_find_first_file(const void *name, void* data); /* clang-format off */ zip_win32_file_operations_t ops_utf16 = { utf16_allocate_tempname, utf16_create_file, utf16_delete_file, utf16_get_file_attributes, utf16_get_file_attributes_ex, utf16_make_tempname, utf16_move_file, utf16_set_file_attributes, utf16_strdup, utf16_find_first_file }; /* clang-format on */ ZIP_EXTERN zip_source_t * zip_source_win32w(zip_t *za, const wchar_t *fname, zip_uint64_t start, zip_int64_t len) { if (za == NULL) return NULL; return zip_source_win32w_create(fname, start, len, &za->error); } ZIP_EXTERN zip_source_t * zip_source_win32w_create(const wchar_t *fname, zip_uint64_t start, zip_int64_t length, zip_error_t *error) { if (fname == NULL || length < ZIP_LENGTH_UNCHECKED) { zip_error_set(error, ZIP_ER_INVAL, 0); return NULL; } return zip_source_file_common_new((const char *)fname, NULL, start, length, NULL, &_zip_source_file_win32_named_ops, &ops_utf16, error); } static char * utf16_allocate_tempname(const char *name, size_t extra_chars, size_t *lengthp) { *lengthp = wcslen((const wchar_t *)name) + extra_chars; return (char *)malloc(*lengthp * sizeof(wchar_t)); } static HANDLE __stdcall utf16_create_file(const void *name, DWORD access, DWORD share_mode, PSECURITY_ATTRIBUTES security_attributes, DWORD creation_disposition, DWORD file_attributes, HANDLE template_file) { #ifdef MS_UWP CREATEFILE2_EXTENDED_PARAMETERS extParams = {0}; extParams.dwFileAttributes = file_attributes; extParams.dwFileFlags = FILE_FLAG_RANDOM_ACCESS; extParams.dwSecurityQosFlags = SECURITY_ANONYMOUS; extParams.dwSize = sizeof(extParams); extParams.hTemplateFile = template_file; extParams.lpSecurityAttributes = security_attributes; return CreateFile2((const wchar_t *)name, access, share_mode, creation_disposition, &extParams); #else return CreateFileW((const wchar_t *)name, access, share_mode, security_attributes, creation_disposition, file_attributes, template_file); #endif } static BOOL __stdcall utf16_delete_file(const void *name) { return DeleteFileW((const wchar_t *)name); } static DWORD __stdcall utf16_get_file_attributes(const void *name) { return GetFileAttributesW((const wchar_t *)name); } static BOOL __stdcall utf16_get_file_attributes_ex(const void *name, GET_FILEEX_INFO_LEVELS info_level, void *information) { return GetFileAttributesExW((const wchar_t *)name, info_level, information); } static void utf16_make_tempname(char *buf, size_t len, const char *name, zip_uint32_t i) { _snwprintf_s((wchar_t *)buf, len, len, L"%s.%08x", (const wchar_t *)name, i); } static BOOL __stdcall utf16_move_file(const void *from, const void *to, DWORD flags) { return MoveFileExW((const wchar_t *)from, (const wchar_t *)to, flags); } static BOOL __stdcall utf16_set_file_attributes(const void *name, DWORD attributes) { return SetFileAttributesW((const wchar_t *)name, attributes); } static char * utf16_strdup(const char *string) { return (char *)_wcsdup((const wchar_t *)string); } static HANDLE __stdcall utf16_find_first_file(const void *name, void* data) { return FindFirstFileW((const wchar_t *)name, data); } ================================================ FILE: external/libzip/lib/zip_source_file_win32_utf8.c ================================================ /* zip_source_file_win32_ansi.c -- source for Windows file opened by UTF-8 name Copyright (C) 1999-2023 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "zip_source_file_win32.h" ZIP_EXTERN zip_source_t * zip_source_file(zip_t *za, const char *fname, zip_uint64_t start, zip_int64_t len) { if (za == NULL) { return NULL; } return zip_source_file_create(fname, start, len, &za->error); } ZIP_EXTERN zip_source_t * zip_source_file_create(const char *fname, zip_uint64_t start, zip_int64_t length, zip_error_t *error) { int size; wchar_t *wfname; zip_source_t *source; if (fname == NULL || length < ZIP_LENGTH_UNCHECKED) { zip_error_set(error, ZIP_ER_INVAL, 0); return NULL; } /* Convert fname from UTF-8 to Windows-friendly UTF-16. */ size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, fname, -1, NULL, 0); if (size == 0) { zip_error_set(error, ZIP_ER_INVAL, 0); return NULL; } if ((wfname = (wchar_t *)malloc(sizeof(wchar_t) * size)) == NULL) { zip_error_set(error, ZIP_ER_MEMORY, 0); return NULL; } MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, fname, -1, wfname, size); source = zip_source_win32w_create(wfname, start, length, error); free(wfname); return source; } ================================================ FILE: external/libzip/lib/zip_source_free.c ================================================ /* zip_source_free.c -- free zip data source Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include "zipint.h" ZIP_EXTERN void zip_source_free(zip_source_t *src) { if (src == NULL) return; if (src->refcount > 0) { src->refcount--; } if (src->refcount > 0) { return; } if (ZIP_SOURCE_IS_OPEN_READING(src)) { src->open_count = 1; /* force close */ zip_source_close(src); } if (ZIP_SOURCE_IS_OPEN_WRITING(src)) { zip_source_rollback_write(src); } if (src->source_archive && !src->source_closed) { _zip_deregister_source(src->source_archive, src); } (void)_zip_source_call(src, NULL, 0, ZIP_SOURCE_FREE); if (src->src) { zip_source_free(src->src); } free(src); } ================================================ FILE: external/libzip/lib/zip_source_function.c ================================================ /* zip_source_function.c -- create zip data source from callback function Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include "zipint.h" ZIP_EXTERN zip_source_t * zip_source_function(zip_t *za, zip_source_callback zcb, void *ud) { if (za == NULL) { return NULL; } return zip_source_function_create(zcb, ud, &za->error); } ZIP_EXTERN zip_source_t * zip_source_function_create(zip_source_callback zcb, void *ud, zip_error_t *error) { zip_source_t *zs; if ((zs = _zip_source_new(error)) == NULL) return NULL; zs->cb.f = zcb; zs->ud = ud; zs->supports = zcb(ud, NULL, 0, ZIP_SOURCE_SUPPORTS); if (zs->supports < 0) { zs->supports = ZIP_SOURCE_SUPPORTS_READABLE; } zs->supports |= zip_source_make_command_bitmap(ZIP_SOURCE_SUPPORTS, -1); return zs; } ZIP_EXTERN void zip_source_keep(zip_source_t *src) { src->refcount++; } zip_source_t * _zip_source_new(zip_error_t *error) { zip_source_t *src; if ((src = (zip_source_t *)malloc(sizeof(*src))) == NULL) { zip_error_set(error, ZIP_ER_MEMORY, 0); return NULL; } src->src = NULL; src->cb.f = NULL; src->ud = NULL; src->open_count = 0; src->write_state = ZIP_SOURCE_WRITE_CLOSED; src->source_closed = false; src->source_archive = NULL; src->refcount = 1; zip_error_init(&src->error); src->eof = false; src->had_read_error = false; src->bytes_read = 0; return src; } ================================================ FILE: external/libzip/lib/zip_source_get_dostime.c ================================================ /* zip_source_get_dostime.c -- get modification time in DOS format from source Copyright (C) 2024 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "zipint.h" /* Returns -1 on error, 0 on no dostime available, 1 for dostime returned */ int zip_source_get_dos_time(zip_source_t *src, zip_dostime_t *dos_time) { if (src->source_closed) { return -1; } if (dos_time == NULL) { zip_error_set(&src->error, ZIP_ER_INVAL, 0); return -1; } if (src->write_state == ZIP_SOURCE_WRITE_REMOVED) { zip_error_set(&src->error, ZIP_ER_READ, ENOENT); } if (zip_source_supports(src) & ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_GET_DOS_TIME)) { zip_int64_t n = _zip_source_call(src, dos_time, sizeof(*dos_time), ZIP_SOURCE_GET_DOS_TIME); if (n < 0) { return -1; } else if (n == 0) { return 0; } else if (n == sizeof(*dos_time)) { return 1; } else { zip_error_set(&src->error, ZIP_ER_INTERNAL, 0); return -1; } } else { return 0; } } ================================================ FILE: external/libzip/lib/zip_source_get_file_attributes.c ================================================ /* zip_source_get_file_attributes.c -- get attributes for file from source Copyright (C) 2020-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "zipint.h" ZIP_EXTERN void zip_file_attributes_init(zip_file_attributes_t *attributes) { attributes->valid = 0; attributes->version = 1; } int zip_source_get_file_attributes(zip_source_t *src, zip_file_attributes_t *attributes) { if (src->source_closed) { return -1; } if (attributes == NULL) { zip_error_set(&src->error, ZIP_ER_INVAL, 0); return -1; } zip_file_attributes_init(attributes); if (src->supports & ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_GET_FILE_ATTRIBUTES)) { if (_zip_source_call(src, attributes, sizeof(*attributes), ZIP_SOURCE_GET_FILE_ATTRIBUTES) < 0) { return -1; } } if (ZIP_SOURCE_IS_LAYERED(src)) { zip_file_attributes_t lower_attributes; zip_file_attributes_init(&lower_attributes); if (zip_source_get_file_attributes(src->src, &lower_attributes) < 0) { zip_error_set_from_source(&src->error, src->src); return -1; } if ((lower_attributes.valid & ZIP_FILE_ATTRIBUTES_HOST_SYSTEM) && (attributes->valid & ZIP_FILE_ATTRIBUTES_HOST_SYSTEM) == 0) { attributes->host_system = lower_attributes.host_system; attributes->valid |= ZIP_FILE_ATTRIBUTES_HOST_SYSTEM; } if ((lower_attributes.valid & ZIP_FILE_ATTRIBUTES_ASCII) && (attributes->valid & ZIP_FILE_ATTRIBUTES_ASCII) == 0) { attributes->ascii = lower_attributes.ascii; attributes->valid |= ZIP_FILE_ATTRIBUTES_ASCII; } if ((lower_attributes.valid & ZIP_FILE_ATTRIBUTES_VERSION_NEEDED)) { if (attributes->valid & ZIP_FILE_ATTRIBUTES_VERSION_NEEDED) { attributes->version_needed = ZIP_MAX(lower_attributes.version_needed, attributes->version_needed); } else { attributes->version_needed = lower_attributes.version_needed; attributes->valid |= ZIP_FILE_ATTRIBUTES_VERSION_NEEDED; } } if ((lower_attributes.valid & ZIP_FILE_ATTRIBUTES_EXTERNAL_FILE_ATTRIBUTES) && (attributes->valid & ZIP_FILE_ATTRIBUTES_EXTERNAL_FILE_ATTRIBUTES) == 0) { attributes->external_file_attributes = lower_attributes.external_file_attributes; attributes->valid |= ZIP_FILE_ATTRIBUTES_EXTERNAL_FILE_ATTRIBUTES; } if ((lower_attributes.valid & ZIP_FILE_ATTRIBUTES_GENERAL_PURPOSE_BIT_FLAGS)) { if (attributes->valid & ZIP_FILE_ATTRIBUTES_GENERAL_PURPOSE_BIT_FLAGS) { /* only take from lower level what is not defined at current level */ lower_attributes.general_purpose_bit_mask &= ~attributes->general_purpose_bit_mask; attributes->general_purpose_bit_flags |= lower_attributes.general_purpose_bit_flags & lower_attributes.general_purpose_bit_mask; attributes->general_purpose_bit_mask |= lower_attributes.general_purpose_bit_mask; } else { attributes->valid |= ZIP_FILE_ATTRIBUTES_GENERAL_PURPOSE_BIT_FLAGS; attributes->general_purpose_bit_flags = lower_attributes.general_purpose_bit_flags; attributes->general_purpose_bit_mask = lower_attributes.general_purpose_bit_mask; } } } return 0; } ================================================ FILE: external/libzip/lib/zip_source_is_deleted.c ================================================ /* zip_source_is_deleted.c -- was archive was removed? Copyright (C) 2014-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "zipint.h" ZIP_EXTERN int zip_source_is_deleted(zip_source_t *src) { return src->write_state == ZIP_SOURCE_WRITE_REMOVED; } ================================================ FILE: external/libzip/lib/zip_source_layered.c ================================================ /* zip_source_layered.c -- create layered source Copyright (C) 2009-2023 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include "zipint.h" zip_source_t * zip_source_layered(zip_t *za, zip_source_t *src, zip_source_layered_callback cb, void *ud) { if (za == NULL) return NULL; return zip_source_layered_create(src, cb, ud, &za->error); } zip_source_t * zip_source_layered_create(zip_source_t *src, zip_source_layered_callback cb, void *ud, zip_error_t *error) { zip_source_t *zs; zip_int64_t lower_supports, supports; lower_supports = zip_source_supports(src); supports = cb(src, ud, &lower_supports, sizeof(lower_supports), ZIP_SOURCE_SUPPORTS); if (supports < 0) { zip_error_set(error,ZIP_ER_INVAL, 0); /* Initialize in case cb doesn't return valid error. */ cb(src, ud, error, sizeof(*error), ZIP_SOURCE_ERROR); return NULL; } if ((zs = _zip_source_new(error)) == NULL) { return NULL; } zs->src = src; zs->cb.l = cb; zs->ud = ud; zs->supports = supports; /* Layered sources can't support writing, since we currently have no use case. If we want to revisit this, we have to define how the two sources interact. */ zs->supports &= ~(ZIP_SOURCE_SUPPORTS_WRITABLE & ~ZIP_SOURCE_SUPPORTS_SEEKABLE); return zs; } ================================================ FILE: external/libzip/lib/zip_source_open.c ================================================ /* zip_source_open.c -- open zip_source (prepare for reading) Copyright (C) 2009-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "zipint.h" ZIP_EXTERN int zip_source_open(zip_source_t *src) { if (src->source_closed) { return -1; } if (src->write_state == ZIP_SOURCE_WRITE_REMOVED) { zip_error_set(&src->error, ZIP_ER_DELETED, 0); return -1; } if (ZIP_SOURCE_IS_OPEN_READING(src)) { if ((zip_source_supports(src) & ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_SEEK)) == 0) { zip_error_set(&src->error, ZIP_ER_INUSE, 0); return -1; } } else { if (ZIP_SOURCE_IS_LAYERED(src)) { if (zip_source_open(src->src) < 0) { zip_error_set_from_source(&src->error, src->src); return -1; } } if (_zip_source_call(src, NULL, 0, ZIP_SOURCE_OPEN) < 0) { if (ZIP_SOURCE_IS_LAYERED(src)) { zip_source_close(src->src); } return -1; } } src->eof = false; src->had_read_error = false; _zip_error_clear(&src->error); src->bytes_read = 0; src->open_count++; return 0; } ================================================ FILE: external/libzip/lib/zip_source_pass_to_lower_layer.c ================================================ /* zip_source_pass_to_lower_layer.c -- pass command to lower layer Copyright (C) 2022-2024 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "zipint.h" zip_int64_t zip_source_pass_to_lower_layer(zip_source_t *src, void *data, zip_uint64_t length, zip_source_cmd_t command) { switch (command) { case ZIP_SOURCE_OPEN: case ZIP_SOURCE_CLOSE: case ZIP_SOURCE_FREE: case ZIP_SOURCE_GET_FILE_ATTRIBUTES: case ZIP_SOURCE_SUPPORTS_REOPEN: return 0; case ZIP_SOURCE_STAT: return sizeof(zip_stat_t); case ZIP_SOURCE_ACCEPT_EMPTY: case ZIP_SOURCE_ERROR: case ZIP_SOURCE_GET_DOS_TIME: case ZIP_SOURCE_READ: case ZIP_SOURCE_SEEK: case ZIP_SOURCE_TELL: return _zip_source_call(src, data, length, command); case ZIP_SOURCE_BEGIN_WRITE: case ZIP_SOURCE_BEGIN_WRITE_CLONING: case ZIP_SOURCE_COMMIT_WRITE: case ZIP_SOURCE_REMOVE: case ZIP_SOURCE_ROLLBACK_WRITE: case ZIP_SOURCE_SEEK_WRITE: case ZIP_SOURCE_TELL_WRITE: case ZIP_SOURCE_WRITE: zip_error_set(&src->error, ZIP_ER_OPNOTSUPP, 0); return -1; case ZIP_SOURCE_SUPPORTS: if (length < sizeof(zip_int64_t)) { zip_error_set(&src->error, ZIP_ER_INTERNAL, 0); return -1; } return *(zip_int64_t *)data; default: zip_error_set(&src->error, ZIP_ER_OPNOTSUPP, 0); return -1; } } ================================================ FILE: external/libzip/lib/zip_source_pkware_decode.c ================================================ /* zip_source_pkware_decode.c -- Traditional PKWARE decryption routines Copyright (C) 2009-2024 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include "zipint.h" struct trad_pkware { char *password; zip_pkware_keys_t keys; zip_error_t error; }; static int decrypt_header(zip_source_t *, struct trad_pkware *); static zip_int64_t pkware_decrypt(zip_source_t *, void *, void *, zip_uint64_t, zip_source_cmd_t); static struct trad_pkware *trad_pkware_new(const char *password, zip_error_t *error); static void trad_pkware_free(struct trad_pkware *); zip_source_t * zip_source_pkware_decode(zip_t *za, zip_source_t *src, zip_uint16_t em, int flags, const char *password) { struct trad_pkware *ctx; zip_source_t *s2; if (password == NULL || src == NULL || em != ZIP_EM_TRAD_PKWARE) { zip_error_set(&za->error, ZIP_ER_INVAL, 0); return NULL; } if (flags & ZIP_CODEC_ENCODE) { zip_error_set(&za->error, ZIP_ER_ENCRNOTSUPP, 0); return NULL; } if ((ctx = trad_pkware_new(password, &za->error)) == NULL) { return NULL; } if ((s2 = zip_source_layered(za, src, pkware_decrypt, ctx)) == NULL) { trad_pkware_free(ctx); return NULL; } return s2; } static int decrypt_header(zip_source_t *src, struct trad_pkware *ctx) { zip_uint8_t header[ZIP_CRYPTO_PKWARE_HEADERLEN]; zip_stat_t st; zip_dostime_t dostime; zip_int64_t n; if ((n = zip_source_read(src, header, ZIP_CRYPTO_PKWARE_HEADERLEN)) < 0) { zip_error_set_from_source(&ctx->error, src); return -1; } if (n != ZIP_CRYPTO_PKWARE_HEADERLEN) { zip_error_set(&ctx->error, ZIP_ER_EOF, 0); return -1; } _zip_pkware_decrypt(&ctx->keys, header, header, ZIP_CRYPTO_PKWARE_HEADERLEN); if (zip_source_stat(src, &st) < 0 || (st.valid & ZIP_STAT_CRC) == 0) { /* skip password validation */ return 0; } if (zip_source_get_dos_time(src, &dostime) <= 0) { if ((st.valid & ZIP_STAT_MTIME) == 0) { /* no date available, skip password validation */ return 0; } if (_zip_u2d_time(st.mtime, &dostime, &ctx->error) < 0) { return -1; } } /* password verification - two ways: - mtime - InfoZIP way, to avoid computing complete CRC before encrypting data - CRC - old PKWare way */ if (header[ZIP_CRYPTO_PKWARE_HEADERLEN - 1] == dostime.time >> 8 || header[ZIP_CRYPTO_PKWARE_HEADERLEN - 1] == st.crc >> 24) { return 0; } else { zip_error_set(&ctx->error, ZIP_ER_WRONGPASSWD, 0); return -1; } } static zip_int64_t pkware_decrypt(zip_source_t *src, void *ud, void *data, zip_uint64_t len, zip_source_cmd_t cmd) { struct trad_pkware *ctx; zip_int64_t n; ctx = (struct trad_pkware *)ud; switch (cmd) { case ZIP_SOURCE_OPEN: _zip_pkware_keys_reset(&ctx->keys); _zip_pkware_decrypt(&ctx->keys, NULL, (const zip_uint8_t *)ctx->password, strlen(ctx->password)); if (decrypt_header(src, ctx) < 0) { return -1; } return 0; case ZIP_SOURCE_READ: if ((n = zip_source_read(src, data, len)) < 0) { zip_error_set_from_source(&ctx->error, src); return -1; } _zip_pkware_decrypt(&ctx->keys, (zip_uint8_t *)data, (zip_uint8_t *)data, (zip_uint64_t)n); return n; case ZIP_SOURCE_CLOSE: return 0; case ZIP_SOURCE_STAT: { zip_stat_t *st; st = (zip_stat_t *)data; st->encryption_method = ZIP_EM_NONE; st->valid |= ZIP_STAT_ENCRYPTION_METHOD; if (st->valid & ZIP_STAT_COMP_SIZE) { st->comp_size -= ZIP_CRYPTO_PKWARE_HEADERLEN; } return 0; } case ZIP_SOURCE_SUPPORTS: return zip_source_make_command_bitmap(ZIP_SOURCE_OPEN, ZIP_SOURCE_READ, ZIP_SOURCE_CLOSE, ZIP_SOURCE_STAT, ZIP_SOURCE_ERROR, ZIP_SOURCE_FREE, ZIP_SOURCE_SUPPORTS_REOPEN, -1); case ZIP_SOURCE_ERROR: return zip_error_to_data(&ctx->error, data, len); case ZIP_SOURCE_FREE: trad_pkware_free(ctx); return 0; default: return zip_source_pass_to_lower_layer(src, data, len, cmd); } } static struct trad_pkware * trad_pkware_new(const char *password, zip_error_t *error) { struct trad_pkware *ctx; if ((ctx = (struct trad_pkware *)malloc(sizeof(*ctx))) == NULL) { zip_error_set(error, ZIP_ER_MEMORY, 0); return NULL; } if ((ctx->password = strdup(password)) == NULL) { zip_error_set(error, ZIP_ER_MEMORY, 0); free(ctx); return NULL; } zip_error_init(&ctx->error); return ctx; } static void trad_pkware_free(struct trad_pkware *ctx) { if (ctx == NULL) { return; } free(ctx->password); free(ctx); } ================================================ FILE: external/libzip/lib/zip_source_pkware_encode.c ================================================ /* zip_source_pkware_encode.c -- Traditional PKWARE encryption routines Copyright (C) 2009-2024 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include "zipint.h" struct trad_pkware { char *password; zip_pkware_keys_t keys; zip_buffer_t *buffer; bool eof; zip_dostime_t dostime; zip_error_t error; }; static int encrypt_header(zip_source_t *, struct trad_pkware *); static zip_int64_t pkware_encrypt(zip_source_t *, void *, void *, zip_uint64_t, zip_source_cmd_t); static void trad_pkware_free(struct trad_pkware *); static struct trad_pkware *trad_pkware_new(const char *password, zip_error_t *error); zip_source_t * zip_source_pkware_encode(zip_t *za, zip_source_t *src, zip_uint16_t em, int flags, const char *password) { struct trad_pkware *ctx; zip_source_t *s2; if (password == NULL || src == NULL || em != ZIP_EM_TRAD_PKWARE) { zip_error_set(&za->error, ZIP_ER_INVAL, 0); return NULL; } if (!(flags & ZIP_CODEC_ENCODE)) { zip_error_set(&za->error, ZIP_ER_ENCRNOTSUPP, 0); return NULL; } if ((ctx = trad_pkware_new(password, &za->error)) == NULL) { zip_error_set(&za->error, ZIP_ER_MEMORY, 0); return NULL; } if (zip_source_get_dos_time(src, &ctx->dostime) <= 0) { zip_stat_t st; if (zip_source_stat(src, &st) < 0) { zip_error_set_from_source(&za->error, src); trad_pkware_free(ctx); return NULL; } if (_zip_u2d_time((st.valid & ZIP_STAT_MTIME) ? st.mtime : time(NULL), &ctx->dostime, &za->error) < 0) { trad_pkware_free(ctx); return NULL; } } if ((s2 = zip_source_layered(za, src, pkware_encrypt, ctx)) == NULL) { trad_pkware_free(ctx); return NULL; } return s2; } static int encrypt_header(zip_source_t *src, struct trad_pkware *ctx) { zip_uint8_t *header; if ((ctx->buffer = _zip_buffer_new(NULL, ZIP_CRYPTO_PKWARE_HEADERLEN)) == NULL) { zip_error_set(&ctx->error, ZIP_ER_MEMORY, 0); return -1; } header = _zip_buffer_data(ctx->buffer); /* generate header from random bytes and mtime see appnote.iz, XIII. Decryption, Step 2, last paragraph */ if (!zip_secure_random(header, ZIP_CRYPTO_PKWARE_HEADERLEN - 1)) { zip_error_set(&ctx->error, ZIP_ER_INTERNAL, 0); _zip_buffer_free(ctx->buffer); ctx->buffer = NULL; return -1; } header[ZIP_CRYPTO_PKWARE_HEADERLEN - 1] = (zip_uint8_t)((ctx->dostime.time >> 8) & 0xff); _zip_pkware_encrypt(&ctx->keys, header, header, ZIP_CRYPTO_PKWARE_HEADERLEN); return 0; } static zip_int64_t pkware_encrypt(zip_source_t *src, void *ud, void *data, zip_uint64_t length, zip_source_cmd_t cmd) { struct trad_pkware *ctx; zip_int64_t n; zip_uint64_t buffer_n; ctx = (struct trad_pkware *)ud; switch (cmd) { case ZIP_SOURCE_OPEN: ctx->eof = false; /* initialize keys */ _zip_pkware_keys_reset(&ctx->keys); _zip_pkware_encrypt(&ctx->keys, NULL, (const zip_uint8_t *)ctx->password, strlen(ctx->password)); if (encrypt_header(src, ctx) < 0) { return -1; } return 0; case ZIP_SOURCE_READ: buffer_n = 0; if (ctx->buffer) { /* write header values to data */ buffer_n = _zip_buffer_read(ctx->buffer, data, length); data = (zip_uint8_t *)data + buffer_n; length -= buffer_n; if (_zip_buffer_eof(ctx->buffer)) { _zip_buffer_free(ctx->buffer); ctx->buffer = NULL; } } if (ctx->eof) { return (zip_int64_t)buffer_n; } if ((n = zip_source_read(src, data, length)) < 0) { zip_error_set_from_source(&ctx->error, src); return -1; } _zip_pkware_encrypt(&ctx->keys, (zip_uint8_t *)data, (zip_uint8_t *)data, (zip_uint64_t)n); if ((zip_uint64_t)n < length) { ctx->eof = true; } return (zip_int64_t)buffer_n + n; case ZIP_SOURCE_CLOSE: _zip_buffer_free(ctx->buffer); ctx->buffer = NULL; return 0; case ZIP_SOURCE_STAT: { zip_stat_t *st; st = (zip_stat_t *)data; st->encryption_method = ZIP_EM_TRAD_PKWARE; st->valid |= ZIP_STAT_ENCRYPTION_METHOD; if (st->valid & ZIP_STAT_COMP_SIZE) { st->comp_size += ZIP_CRYPTO_PKWARE_HEADERLEN; } return 0; } case ZIP_SOURCE_GET_FILE_ATTRIBUTES: { zip_file_attributes_t *attributes = (zip_file_attributes_t *)data; if (length < sizeof(*attributes)) { zip_error_set(&ctx->error, ZIP_ER_INVAL, 0); return -1; } attributes->valid |= ZIP_FILE_ATTRIBUTES_VERSION_NEEDED | ZIP_FILE_ATTRIBUTES_GENERAL_PURPOSE_BIT_FLAGS; attributes->version_needed = 20; attributes->general_purpose_bit_flags = ZIP_GPBF_DATA_DESCRIPTOR; attributes->general_purpose_bit_mask = ZIP_GPBF_DATA_DESCRIPTOR; return 0; } case ZIP_SOURCE_GET_DOS_TIME: if (length < sizeof(ctx->dostime)) { zip_error_set(&ctx->error, ZIP_ER_INVAL, 0); return -1; } (void)memcpy_s(data, sizeof(ctx->dostime), &ctx->dostime, sizeof(ctx->dostime)); return sizeof(ctx->dostime); case ZIP_SOURCE_SUPPORTS: return zip_source_make_command_bitmap(ZIP_SOURCE_OPEN, ZIP_SOURCE_READ, ZIP_SOURCE_CLOSE, ZIP_SOURCE_STAT, ZIP_SOURCE_ERROR, ZIP_SOURCE_FREE, ZIP_SOURCE_GET_FILE_ATTRIBUTES, ZIP_SOURCE_GET_DOS_TIME, -1); case ZIP_SOURCE_ERROR: return zip_error_to_data(&ctx->error, data, length); case ZIP_SOURCE_FREE: trad_pkware_free(ctx); return 0; default: return zip_source_pass_to_lower_layer(src, data, length, cmd); } } static struct trad_pkware * trad_pkware_new(const char *password, zip_error_t *error) { struct trad_pkware *ctx; if ((ctx = (struct trad_pkware *)malloc(sizeof(*ctx))) == NULL) { zip_error_set(error, ZIP_ER_MEMORY, 0); return NULL; } if ((ctx->password = strdup(password)) == NULL) { zip_error_set(error, ZIP_ER_MEMORY, 0); free(ctx); return NULL; } ctx->buffer = NULL; zip_error_init(&ctx->error); return ctx; } static void trad_pkware_free(struct trad_pkware *ctx) { if (ctx == NULL) { return; } free(ctx->password); _zip_buffer_free(ctx->buffer); zip_error_fini(&ctx->error); free(ctx); } ================================================ FILE: external/libzip/lib/zip_source_read.c ================================================ /* zip_source_read.c -- read data from zip_source Copyright (C) 2009-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "zipint.h" zip_int64_t zip_source_read(zip_source_t *src, void *data, zip_uint64_t len) { zip_uint64_t bytes_read; zip_int64_t n; if (src->source_closed) { return -1; } if (!ZIP_SOURCE_IS_OPEN_READING(src) || len > ZIP_INT64_MAX || (len > 0 && data == NULL)) { zip_error_set(&src->error, ZIP_ER_INVAL, 0); return -1; } if (src->had_read_error) { return -1; } if (_zip_source_eof(src)) { return 0; } if (len == 0) { return 0; } bytes_read = 0; while (bytes_read < len) { if ((n = _zip_source_call(src, (zip_uint8_t *)data + bytes_read, len - bytes_read, ZIP_SOURCE_READ)) < 0) { src->had_read_error = true; if (bytes_read == 0) { return -1; } else { return (zip_int64_t)bytes_read; } } if (n == 0) { src->eof = 1; break; } bytes_read += (zip_uint64_t)n; } if (src->bytes_read + bytes_read < src->bytes_read) { src->bytes_read = ZIP_UINT64_MAX; } else { src->bytes_read += bytes_read; } return (zip_int64_t)bytes_read; } bool _zip_source_eof(zip_source_t *src) { return src->eof; } ================================================ FILE: external/libzip/lib/zip_source_remove.c ================================================ /* zip_source_remove.c -- remove empty archive Copyright (C) 2014-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "zipint.h" int zip_source_remove(zip_source_t *src) { if (ZIP_SOURCE_IS_LAYERED(src)) { zip_error_set(&src->error, ZIP_ER_OPNOTSUPP, 0); return -1; } if (src->write_state == ZIP_SOURCE_WRITE_REMOVED) { return 0; } if (ZIP_SOURCE_IS_OPEN_READING(src)) { if (zip_source_close(src) < 0) { return -1; } } if (src->write_state != ZIP_SOURCE_WRITE_CLOSED) { zip_source_rollback_write(src); } if (_zip_source_call(src, NULL, 0, ZIP_SOURCE_REMOVE) < 0) { return -1; } src->write_state = ZIP_SOURCE_WRITE_REMOVED; return 0; } ================================================ FILE: external/libzip/lib/zip_source_rollback_write.c ================================================ /* zip_source_rollback_write.c -- discard changes Copyright (C) 2014-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "zipint.h" ZIP_EXTERN void zip_source_rollback_write(zip_source_t *src) { if (ZIP_SOURCE_IS_LAYERED(src)) { return; } if (src->write_state != ZIP_SOURCE_WRITE_OPEN && src->write_state != ZIP_SOURCE_WRITE_FAILED) { return; } _zip_source_call(src, NULL, 0, ZIP_SOURCE_ROLLBACK_WRITE); src->write_state = ZIP_SOURCE_WRITE_CLOSED; } ================================================ FILE: external/libzip/lib/zip_source_seek.c ================================================ /* zip_source_seek.c -- seek to offset Copyright (C) 2014-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "zipint.h" ZIP_EXTERN int zip_source_seek(zip_source_t *src, zip_int64_t offset, int whence) { zip_source_args_seek_t args; if (src->source_closed) { return -1; } if (!ZIP_SOURCE_IS_OPEN_READING(src) || (whence != SEEK_SET && whence != SEEK_CUR && whence != SEEK_END)) { zip_error_set(&src->error, ZIP_ER_INVAL, 0); return -1; } args.offset = offset; args.whence = whence; if (_zip_source_call(src, &args, sizeof(args), ZIP_SOURCE_SEEK) < 0) { return -1; } src->eof = 0; return 0; } zip_int64_t zip_source_seek_compute_offset(zip_uint64_t offset, zip_uint64_t length, void *data, zip_uint64_t data_length, zip_error_t *error) { zip_int64_t new_offset; zip_source_args_seek_t *args = ZIP_SOURCE_GET_ARGS(zip_source_args_seek_t, data, data_length, error); if (args == NULL) { return -1; } switch (args->whence) { case SEEK_CUR: new_offset = (zip_int64_t)offset + args->offset; break; case SEEK_END: new_offset = (zip_int64_t)length + args->offset; break; case SEEK_SET: new_offset = args->offset; break; default: zip_error_set(error, ZIP_ER_INVAL, 0); return -1; } if (new_offset < 0 || (zip_uint64_t)new_offset > length) { zip_error_set(error, ZIP_ER_INVAL, 0); return -1; } return new_offset; } ================================================ FILE: external/libzip/lib/zip_source_seek_write.c ================================================ /* zip_source_seek_write.c -- seek to offset for writing Copyright (C) 2014-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "zipint.h" ZIP_EXTERN int zip_source_seek_write(zip_source_t *src, zip_int64_t offset, int whence) { zip_source_args_seek_t args; if (ZIP_SOURCE_IS_LAYERED(src)) { zip_error_set(&src->error, ZIP_ER_OPNOTSUPP, 0); return -1; } if (!ZIP_SOURCE_IS_OPEN_WRITING(src) || (whence != SEEK_SET && whence != SEEK_CUR && whence != SEEK_END)) { zip_error_set(&src->error, ZIP_ER_INVAL, 0); return -1; } args.offset = offset; args.whence = whence; return (_zip_source_call(src, &args, sizeof(args), ZIP_SOURCE_SEEK_WRITE) < 0 ? -1 : 0); } ================================================ FILE: external/libzip/lib/zip_source_stat.c ================================================ /* zip_source_stat.c -- get meta information from zip_source Copyright (C) 2009-2023 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "zipint.h" ZIP_EXTERN int zip_source_stat(zip_source_t *src, zip_stat_t *st) { if (src->source_closed) { return -1; } if (st == NULL) { zip_error_set(&src->error, ZIP_ER_INVAL, 0); return -1; } if (src->write_state == ZIP_SOURCE_WRITE_REMOVED) { zip_error_set(&src->error, ZIP_ER_READ, ENOENT); } zip_stat_init(st); if (ZIP_SOURCE_IS_LAYERED(src)) { if (zip_source_stat(src->src, st) < 0) { zip_error_set_from_source(&src->error, src->src); return -1; } } if (_zip_source_call(src, st, sizeof(*st), ZIP_SOURCE_STAT) < 0) { return -1; } return 0; } ================================================ FILE: external/libzip/lib/zip_source_supports.c ================================================ /* zip_source_supports.c -- check for supported functions Copyright (C) 2014-2023 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include "zipint.h" zip_int64_t zip_source_supports(zip_source_t *src) { return src->supports; } bool zip_source_supports_reopen(zip_source_t *src) { return (zip_source_supports(src) & ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_SUPPORTS_REOPEN)) != 0; } ZIP_EXTERN zip_int64_t zip_source_make_command_bitmap(zip_source_cmd_t cmd0, ...) { zip_int64_t bitmap; va_list ap; bitmap = ZIP_SOURCE_MAKE_COMMAND_BITMASK(cmd0); va_start(ap, cmd0); for (;;) { int cmd = va_arg(ap, int); if (cmd < 0) { break; } bitmap |= ZIP_SOURCE_MAKE_COMMAND_BITMASK(cmd); } va_end(ap); return bitmap; } ZIP_EXTERN int zip_source_is_seekable(zip_source_t *src) { return ZIP_SOURCE_CHECK_SUPPORTED(zip_source_supports(src->src), ZIP_SOURCE_SEEK); } ================================================ FILE: external/libzip/lib/zip_source_tell.c ================================================ /* zip_source_tell.c -- report current offset Copyright (C) 2014-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "zipint.h" ZIP_EXTERN zip_int64_t zip_source_tell(zip_source_t *src) { if (src->source_closed) { return -1; } if (!ZIP_SOURCE_IS_OPEN_READING(src)) { zip_error_set(&src->error, ZIP_ER_INVAL, 0); return -1; } if ((src->supports & (ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_TELL) | ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_SEEK))) == 0) { if (src->bytes_read > ZIP_INT64_MAX) { zip_error_set(&src->error, ZIP_ER_TELL, EOVERFLOW); return -1; } return (zip_int64_t)src->bytes_read; } return _zip_source_call(src, NULL, 0, ZIP_SOURCE_TELL); } ================================================ FILE: external/libzip/lib/zip_source_tell_write.c ================================================ /* zip_source_tell_write.c -- report current offset for writing Copyright (C) 2014-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "zipint.h" ZIP_EXTERN zip_int64_t zip_source_tell_write(zip_source_t *src) { if (ZIP_SOURCE_IS_LAYERED(src)) { zip_error_set(&src->error, ZIP_ER_OPNOTSUPP, 0); return -1; } if (!ZIP_SOURCE_IS_OPEN_WRITING(src)) { zip_error_set(&src->error, ZIP_ER_INVAL, 0); return -1; } return _zip_source_call(src, NULL, 0, ZIP_SOURCE_TELL_WRITE); } ================================================ FILE: external/libzip/lib/zip_source_window.c ================================================ /* zip_source_window.c -- return part of lower source Copyright (C) 2012-2024 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include "zipint.h" struct window { zip_uint64_t start; /* where in file we start reading */ zip_uint64_t end; /* where in file we stop reading */ bool end_valid; /* whether end is set, otherwise read until EOF */ /* if not NULL, read file data for this file */ zip_t *source_archive; zip_uint64_t source_index; zip_uint64_t offset; /* offset in src for next read */ zip_stat_t stat; zip_uint64_t stat_invalid; zip_file_attributes_t attributes; zip_dostime_t dostime; bool dostime_valid; zip_error_t error; zip_int64_t supports; bool needs_seek; }; static zip_int64_t window_read(zip_source_t *, void *, void *, zip_uint64_t, zip_source_cmd_t); ZIP_EXTERN zip_source_t * zip_source_window_create(zip_source_t *src, zip_uint64_t start, zip_int64_t len, zip_error_t *error) { return _zip_source_window_new(src, start, len, NULL, 0, NULL, NULL, NULL, 0, false, error); } zip_source_t * _zip_source_window_new(zip_source_t *src, zip_uint64_t start, zip_int64_t length, zip_stat_t *st, zip_uint64_t st_invalid, zip_file_attributes_t *attributes, zip_dostime_t *dostime, zip_t *source_archive, zip_uint64_t source_index, bool take_ownership, zip_error_t *error) { zip_source_t* window_source; struct window *ctx; if (src == NULL || length < -1 || (source_archive == NULL && source_index != 0)) { zip_error_set(error, ZIP_ER_INVAL, 0); return NULL; } if (length >= 0) { if (start + (zip_uint64_t)length < start) { zip_error_set(error, ZIP_ER_INVAL, 0); return NULL; } } if ((ctx = (struct window *)malloc(sizeof(*ctx))) == NULL) { zip_error_set(error, ZIP_ER_MEMORY, 0); return NULL; } ctx->start = start; if (length == -1) { ctx->end_valid = false; } else { ctx->end = start + (zip_uint64_t)length; ctx->end_valid = true; } zip_stat_init(&ctx->stat); ctx->stat_invalid = st_invalid; if (attributes != NULL) { (void)memcpy_s(&ctx->attributes, sizeof(ctx->attributes), attributes, sizeof(ctx->attributes)); } else { zip_file_attributes_init(&ctx->attributes); } if (dostime != NULL) { ctx->dostime = *dostime; ctx->dostime_valid = true; } else { ctx->dostime_valid = false; } ctx->source_archive = source_archive; ctx->source_index = source_index; zip_error_init(&ctx->error); ctx->supports = (zip_source_supports(src) & (ZIP_SOURCE_SUPPORTS_SEEKABLE | ZIP_SOURCE_SUPPORTS_REOPEN)) | (zip_source_make_command_bitmap(ZIP_SOURCE_GET_FILE_ATTRIBUTES, ZIP_SOURCE_GET_DOS_TIME, ZIP_SOURCE_SUPPORTS, ZIP_SOURCE_TELL, ZIP_SOURCE_FREE, -1)); ctx->needs_seek = (ctx->supports & ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_SEEK)) ? true : false; if (st) { if (_zip_stat_merge(&ctx->stat, st, error) < 0) { free(ctx); return NULL; } } window_source = zip_source_layered_create(src, window_read, ctx, error); if (window_source != NULL && !take_ownership) { zip_source_keep(src); } return window_source; } int _zip_source_set_source_archive(zip_source_t *src, zip_t *za) { src->source_archive = za; return _zip_register_source(za, src); } /* called by zip_discard to avoid operating on file from closed archive */ void _zip_source_invalidate(zip_source_t *src) { src->source_closed = 1; if (zip_error_code_zip(&src->error) == ZIP_ER_OK) { zip_error_set(&src->error, ZIP_ER_ZIPCLOSED, 0); } } static zip_int64_t window_read(zip_source_t *src, void *_ctx, void *data, zip_uint64_t len, zip_source_cmd_t cmd) { struct window *ctx; zip_int64_t ret; zip_uint64_t n, i; ctx = (struct window *)_ctx; switch (cmd) { case ZIP_SOURCE_CLOSE: return 0; case ZIP_SOURCE_ERROR: return zip_error_to_data(&ctx->error, data, len); case ZIP_SOURCE_FREE: free(ctx); return 0; case ZIP_SOURCE_OPEN: if (ctx->source_archive) { zip_uint64_t offset; if ((offset = _zip_file_get_offset(ctx->source_archive, ctx->source_index, &ctx->error)) == 0) { return -1; } if (ctx->end + offset < ctx->end) { /* zip archive data claims end of data past zip64 limits */ zip_error_set(&ctx->error, ZIP_ER_INCONS, MAKE_DETAIL_WITH_INDEX(ZIP_ER_DETAIL_CDIR_ENTRY_INVALID, ctx->source_index)); return -1; } ctx->start += offset; ctx->end += offset; ctx->source_archive = NULL; } if (!ctx->needs_seek) { DEFINE_BYTE_ARRAY(b, BUFSIZE); if (!byte_array_init(b, BUFSIZE)) { zip_error_set(&ctx->error, ZIP_ER_MEMORY, 0); return -1; } for (n = 0; n < ctx->start; n += (zip_uint64_t)ret) { i = (ctx->start - n > BUFSIZE ? BUFSIZE : ctx->start - n); if ((ret = zip_source_read(src, b, i)) < 0) { zip_error_set_from_source(&ctx->error, src); byte_array_fini(b); return -1; } if (ret == 0) { zip_error_set(&ctx->error, ZIP_ER_EOF, 0); byte_array_fini(b); return -1; } } byte_array_fini(b); } ctx->offset = ctx->start; return 0; case ZIP_SOURCE_READ: if (ctx->end_valid && len > ctx->end - ctx->offset) { len = ctx->end - ctx->offset; } if (len == 0) { return 0; } if (ctx->needs_seek) { if (zip_source_seek(src, (zip_int64_t)ctx->offset, SEEK_SET) < 0) { zip_error_set_from_source(&ctx->error, src); return -1; } } if ((ret = zip_source_read(src, data, len)) < 0) { zip_error_set(&ctx->error, ZIP_ER_EOF, 0); return -1; } ctx->offset += (zip_uint64_t)ret; if (ret == 0) { if (ctx->end_valid && ctx->offset < ctx->end) { zip_error_set(&ctx->error, ZIP_ER_EOF, 0); return -1; } } return ret; case ZIP_SOURCE_SEEK: { zip_int64_t new_offset; if (!ctx->end_valid) { zip_source_args_seek_t *args = ZIP_SOURCE_GET_ARGS(zip_source_args_seek_t, data, len, &ctx->error); if (args == NULL) { return -1; } if (args->whence == SEEK_END) { if (zip_source_seek(src, args->offset, args->whence) < 0) { zip_error_set_from_source(&ctx->error, src); return -1; } new_offset = zip_source_tell(src); if (new_offset < 0) { zip_error_set_from_source(&ctx->error, src); return -1; } if ((zip_uint64_t)new_offset < ctx->start) { zip_error_set(&ctx->error, ZIP_ER_INVAL, 0); (void)zip_source_seek(src, (zip_int64_t)ctx->offset, SEEK_SET); return -1; } ctx->offset = (zip_uint64_t)new_offset; return 0; } } new_offset = zip_source_seek_compute_offset(ctx->offset - ctx->start, ctx->end - ctx->start, data, len, &ctx->error); if (new_offset < 0) { return -1; } ctx->offset = (zip_uint64_t)new_offset + ctx->start; return 0; } case ZIP_SOURCE_STAT: { zip_stat_t *st; st = (zip_stat_t *)data; if (_zip_stat_merge(st, &ctx->stat, &ctx->error) < 0) { return -1; } if (!(ctx->stat.valid & ZIP_STAT_SIZE)) { if (ctx->end_valid) { st->valid |= ZIP_STAT_SIZE; st->size = ctx->end - ctx->start; } else if (st->valid & ZIP_STAT_SIZE) { st->size -= ctx->start; } } st->valid &= ~ctx->stat_invalid; return 0; } case ZIP_SOURCE_GET_FILE_ATTRIBUTES: if (len < sizeof(ctx->attributes)) { zip_error_set(&ctx->error, ZIP_ER_INVAL, 0); return -1; } (void)memcpy_s(data, sizeof(ctx->attributes), &ctx->attributes, sizeof(ctx->attributes)); return sizeof(ctx->attributes); case ZIP_SOURCE_GET_DOS_TIME: if (len < sizeof(ctx->dostime)) { zip_error_set(&ctx->error, ZIP_ER_INVAL, 0); return -1; } if (ctx->dostime_valid) { (void)memcpy_s(data, sizeof(ctx->dostime), &ctx->dostime, sizeof(ctx->dostime)); return sizeof(ctx->dostime); } else { return 0; } case ZIP_SOURCE_SUPPORTS: return ctx->supports; case ZIP_SOURCE_TELL: return (zip_int64_t)(ctx->offset - ctx->start); default: return zip_source_pass_to_lower_layer(src, data, len, cmd); } } void _zip_deregister_source(zip_t *za, zip_source_t *src) { zip_uint64_t i; for (i = 0; i < za->nopen_source; i++) { if (za->open_source[i] == src) { za->open_source[i] = za->open_source[za->nopen_source - 1]; za->nopen_source--; break; } } } int _zip_register_source(zip_t *za, zip_source_t *src) { if (za->nopen_source + 1 >= za->nopen_source_alloc) { if (!ZIP_REALLOC(za->open_source, za->nopen_source_alloc, 10, &za->error)) { return -1; } } za->open_source[za->nopen_source++] = src; return 0; } ================================================ FILE: external/libzip/lib/zip_source_winzip_aes_decode.c ================================================ /* zip_source_winzip_aes_decode.c -- Winzip AES decryption routines Copyright (C) 2009-2023 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include "zipint.h" #include "zip_crypto.h" struct winzip_aes { char *password; zip_uint16_t encryption_method; zip_uint64_t data_length; zip_uint64_t current_position; zip_winzip_aes_t *aes_ctx; zip_error_t error; }; static int decrypt_header(zip_source_t *src, struct winzip_aes *ctx); static void winzip_aes_free(struct winzip_aes *); static zip_int64_t winzip_aes_decrypt(zip_source_t *src, void *ud, void *data, zip_uint64_t len, zip_source_cmd_t cmd); static struct winzip_aes *winzip_aes_new(zip_uint16_t encryption_method, const char *password, zip_error_t *error); zip_source_t * zip_source_winzip_aes_decode(zip_t *za, zip_source_t *src, zip_uint16_t encryption_method, int flags, const char *password) { zip_source_t *s2; zip_stat_t st; zip_uint64_t aux_length; struct winzip_aes *ctx; if ((encryption_method != ZIP_EM_AES_128 && encryption_method != ZIP_EM_AES_192 && encryption_method != ZIP_EM_AES_256) || password == NULL || src == NULL) { zip_error_set(&za->error, ZIP_ER_INVAL, 0); return NULL; } if (flags & ZIP_CODEC_ENCODE) { zip_error_set(&za->error, ZIP_ER_ENCRNOTSUPP, 0); return NULL; } if (zip_source_stat(src, &st) != 0) { zip_error_set_from_source(&za->error, src); return NULL; } aux_length = WINZIP_AES_PASSWORD_VERIFY_LENGTH + SALT_LENGTH(encryption_method) + HMAC_LENGTH; if ((st.valid & ZIP_STAT_COMP_SIZE) == 0 || st.comp_size < aux_length) { zip_error_set(&za->error, ZIP_ER_OPNOTSUPP, 0); return NULL; } if ((ctx = winzip_aes_new(encryption_method, password, &za->error)) == NULL) { return NULL; } ctx->data_length = st.comp_size - aux_length; if ((s2 = zip_source_layered(za, src, winzip_aes_decrypt, ctx)) == NULL) { winzip_aes_free(ctx); return NULL; } return s2; } static int decrypt_header(zip_source_t *src, struct winzip_aes *ctx) { zip_uint8_t header[WINZIP_AES_MAX_HEADER_LENGTH]; zip_uint8_t password_verification[WINZIP_AES_PASSWORD_VERIFY_LENGTH]; unsigned int headerlen; zip_int64_t n; headerlen = WINZIP_AES_PASSWORD_VERIFY_LENGTH + SALT_LENGTH(ctx->encryption_method); if ((n = zip_source_read(src, header, headerlen)) < 0) { zip_error_set_from_source(&ctx->error, src); return -1; } if (n != headerlen) { zip_error_set(&ctx->error, ZIP_ER_EOF, 0); return -1; } if ((ctx->aes_ctx = _zip_winzip_aes_new((zip_uint8_t *)ctx->password, strlen(ctx->password), header, ctx->encryption_method, password_verification, &ctx->error)) == NULL) { return -1; } if (memcmp(password_verification, header + SALT_LENGTH(ctx->encryption_method), WINZIP_AES_PASSWORD_VERIFY_LENGTH) != 0) { _zip_winzip_aes_free(ctx->aes_ctx); ctx->aes_ctx = NULL; zip_error_set(&ctx->error, ZIP_ER_WRONGPASSWD, 0); return -1; } return 0; } static bool verify_hmac(zip_source_t *src, struct winzip_aes *ctx) { unsigned char computed[ZIP_CRYPTO_SHA1_LENGTH], from_file[HMAC_LENGTH]; if (zip_source_read(src, from_file, HMAC_LENGTH) < HMAC_LENGTH) { zip_error_set_from_source(&ctx->error, src); return false; } if (!_zip_winzip_aes_finish(ctx->aes_ctx, computed)) { zip_error_set(&ctx->error, ZIP_ER_INTERNAL, 0); return false; } _zip_winzip_aes_free(ctx->aes_ctx); ctx->aes_ctx = NULL; if (memcmp(from_file, computed, HMAC_LENGTH) != 0) { zip_error_set(&ctx->error, ZIP_ER_CRC, 0); return false; } return true; } static zip_int64_t winzip_aes_decrypt(zip_source_t *src, void *ud, void *data, zip_uint64_t len, zip_source_cmd_t cmd) { struct winzip_aes *ctx; zip_int64_t n; ctx = (struct winzip_aes *)ud; switch (cmd) { case ZIP_SOURCE_OPEN: if (decrypt_header(src, ctx) < 0) { return -1; } ctx->current_position = 0; return 0; case ZIP_SOURCE_READ: if (len > ctx->data_length - ctx->current_position) { len = ctx->data_length - ctx->current_position; } if (len == 0) { if (!verify_hmac(src, ctx)) { return -1; } return 0; } if ((n = zip_source_read(src, data, len)) < 0) { zip_error_set_from_source(&ctx->error, src); return -1; } ctx->current_position += (zip_uint64_t)n; if (!_zip_winzip_aes_decrypt(ctx->aes_ctx, (zip_uint8_t *)data, (zip_uint64_t)n)) { zip_error_set(&ctx->error, ZIP_ER_INTERNAL, 0); return -1; } return n; case ZIP_SOURCE_CLOSE: return 0; case ZIP_SOURCE_STAT: { zip_stat_t *st; st = (zip_stat_t *)data; st->encryption_method = ZIP_EM_NONE; st->valid |= ZIP_STAT_ENCRYPTION_METHOD; if (st->valid & ZIP_STAT_COMP_SIZE) { st->comp_size -= 12 + SALT_LENGTH(ctx->encryption_method); } return 0; } case ZIP_SOURCE_SUPPORTS: return zip_source_make_command_bitmap(ZIP_SOURCE_OPEN, ZIP_SOURCE_READ, ZIP_SOURCE_CLOSE, ZIP_SOURCE_STAT, ZIP_SOURCE_ERROR, ZIP_SOURCE_FREE, ZIP_SOURCE_SUPPORTS_REOPEN, -1); case ZIP_SOURCE_ERROR: return zip_error_to_data(&ctx->error, data, len); case ZIP_SOURCE_FREE: winzip_aes_free(ctx); return 0; default: return zip_source_pass_to_lower_layer(src, data, len, cmd); } } static void winzip_aes_free(struct winzip_aes *ctx) { if (ctx == NULL) { return; } _zip_crypto_clear(ctx->password, strlen(ctx->password)); free(ctx->password); zip_error_fini(&ctx->error); _zip_winzip_aes_free(ctx->aes_ctx); free(ctx); } static struct winzip_aes * winzip_aes_new(zip_uint16_t encryption_method, const char *password, zip_error_t *error) { struct winzip_aes *ctx; if ((ctx = (struct winzip_aes *)malloc(sizeof(*ctx))) == NULL) { zip_error_set(error, ZIP_ER_MEMORY, 0); return NULL; } if ((ctx->password = strdup(password)) == NULL) { zip_error_set(error, ZIP_ER_MEMORY, 0); free(ctx); return NULL; } ctx->encryption_method = encryption_method; ctx->aes_ctx = NULL; zip_error_init(&ctx->error); return ctx; } ================================================ FILE: external/libzip/lib/zip_source_winzip_aes_encode.c ================================================ /* zip_source_winzip_aes_encode.c -- Winzip AES encryption routines Copyright (C) 2009-2023 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include "zipint.h" #include "zip_crypto.h" struct winzip_aes { char *password; zip_uint16_t encryption_method; zip_uint8_t data[ZIP_MAX(WINZIP_AES_MAX_HEADER_LENGTH, ZIP_CRYPTO_SHA1_LENGTH)]; zip_buffer_t *buffer; zip_winzip_aes_t *aes_ctx; bool eof; zip_error_t error; }; static int encrypt_header(zip_source_t *src, struct winzip_aes *ctx); static void winzip_aes_free(struct winzip_aes *); static zip_int64_t winzip_aes_encrypt(zip_source_t *src, void *ud, void *data, zip_uint64_t len, zip_source_cmd_t cmd); static struct winzip_aes *winzip_aes_new(zip_uint16_t encryption_method, const char *password, zip_error_t *error); zip_source_t * zip_source_winzip_aes_encode(zip_t *za, zip_source_t *src, zip_uint16_t encryption_method, int flags, const char *password) { zip_source_t *s2; struct winzip_aes *ctx; if ((encryption_method != ZIP_EM_AES_128 && encryption_method != ZIP_EM_AES_192 && encryption_method != ZIP_EM_AES_256) || password == NULL || src == NULL) { zip_error_set(&za->error, ZIP_ER_INVAL, 0); return NULL; } if ((ctx = winzip_aes_new(encryption_method, password, &za->error)) == NULL) { return NULL; } if ((s2 = zip_source_layered(za, src, winzip_aes_encrypt, ctx)) == NULL) { winzip_aes_free(ctx); return NULL; } return s2; } static int encrypt_header(zip_source_t *src, struct winzip_aes *ctx) { zip_uint16_t salt_length = SALT_LENGTH(ctx->encryption_method); if (!zip_secure_random(ctx->data, salt_length)) { zip_error_set(&ctx->error, ZIP_ER_INTERNAL, 0); return -1; } if ((ctx->aes_ctx = _zip_winzip_aes_new((zip_uint8_t *)ctx->password, strlen(ctx->password), ctx->data, ctx->encryption_method, ctx->data + salt_length, &ctx->error)) == NULL) { return -1; } if ((ctx->buffer = _zip_buffer_new(ctx->data, salt_length + WINZIP_AES_PASSWORD_VERIFY_LENGTH)) == NULL) { _zip_winzip_aes_free(ctx->aes_ctx); ctx->aes_ctx = NULL; zip_error_set(&ctx->error, ZIP_ER_MEMORY, 0); return -1; } return 0; } static zip_int64_t winzip_aes_encrypt(zip_source_t *src, void *ud, void *data, zip_uint64_t length, zip_source_cmd_t cmd) { struct winzip_aes *ctx; zip_int64_t ret; zip_uint64_t buffer_n; ctx = (struct winzip_aes *)ud; switch (cmd) { case ZIP_SOURCE_OPEN: ctx->eof = false; if (encrypt_header(src, ctx) < 0) { return -1; } return 0; case ZIP_SOURCE_READ: buffer_n = 0; if (ctx->buffer) { buffer_n = _zip_buffer_read(ctx->buffer, data, length); data = (zip_uint8_t *)data + buffer_n; length -= buffer_n; if (_zip_buffer_eof(ctx->buffer)) { _zip_buffer_free(ctx->buffer); ctx->buffer = NULL; } } if (ctx->eof) { return (zip_int64_t)buffer_n; } if ((ret = zip_source_read(src, data, length)) < 0) { zip_error_set_from_source(&ctx->error, src); return -1; } if (!_zip_winzip_aes_encrypt(ctx->aes_ctx, data, (zip_uint64_t)ret)) { zip_error_set(&ctx->error, ZIP_ER_INTERNAL, 0); /* TODO: return partial read? */ return -1; } if ((zip_uint64_t)ret < length) { ctx->eof = true; if (!_zip_winzip_aes_finish(ctx->aes_ctx, ctx->data)) { zip_error_set(&ctx->error, ZIP_ER_INTERNAL, 0); /* TODO: return partial read? */ return -1; } _zip_winzip_aes_free(ctx->aes_ctx); ctx->aes_ctx = NULL; if ((ctx->buffer = _zip_buffer_new(ctx->data, HMAC_LENGTH)) == NULL) { zip_error_set(&ctx->error, ZIP_ER_MEMORY, 0); /* TODO: return partial read? */ return -1; } buffer_n += _zip_buffer_read(ctx->buffer, (zip_uint8_t *)data + ret, length - (zip_uint64_t)ret); } return (zip_int64_t)(buffer_n + (zip_uint64_t)ret); case ZIP_SOURCE_CLOSE: return 0; case ZIP_SOURCE_STAT: { zip_stat_t *st; st = (zip_stat_t *)data; st->encryption_method = ctx->encryption_method; st->valid |= ZIP_STAT_ENCRYPTION_METHOD; if (st->valid & ZIP_STAT_COMP_SIZE) { st->comp_size += 12 + SALT_LENGTH(ctx->encryption_method); } return 0; } case ZIP_SOURCE_GET_FILE_ATTRIBUTES: { zip_file_attributes_t *attributes = (zip_file_attributes_t *)data; if (length < sizeof(*attributes)) { zip_error_set(&ctx->error, ZIP_ER_INVAL, 0); return -1; } attributes->valid |= ZIP_FILE_ATTRIBUTES_VERSION_NEEDED; attributes->version_needed = 51; return 0; } case ZIP_SOURCE_SUPPORTS: return zip_source_make_command_bitmap(ZIP_SOURCE_OPEN, ZIP_SOURCE_READ, ZIP_SOURCE_CLOSE, ZIP_SOURCE_STAT, ZIP_SOURCE_ERROR, ZIP_SOURCE_FREE, ZIP_SOURCE_GET_FILE_ATTRIBUTES, -1); case ZIP_SOURCE_ERROR: return zip_error_to_data(&ctx->error, data, length); case ZIP_SOURCE_FREE: winzip_aes_free(ctx); return 0; default: return zip_source_pass_to_lower_layer(src, data, length, cmd); } } static void winzip_aes_free(struct winzip_aes *ctx) { if (ctx == NULL) { return; } _zip_crypto_clear(ctx->password, strlen(ctx->password)); free(ctx->password); zip_error_fini(&ctx->error); _zip_buffer_free(ctx->buffer); _zip_winzip_aes_free(ctx->aes_ctx); free(ctx); } static struct winzip_aes * winzip_aes_new(zip_uint16_t encryption_method, const char *password, zip_error_t *error) { struct winzip_aes *ctx; if ((ctx = (struct winzip_aes *)malloc(sizeof(*ctx))) == NULL) { zip_error_set(error, ZIP_ER_MEMORY, 0); return NULL; } if ((ctx->password = strdup(password)) == NULL) { free(ctx); zip_error_set(error, ZIP_ER_MEMORY, 0); return NULL; } ctx->encryption_method = encryption_method; ctx->buffer = NULL; ctx->aes_ctx = NULL; zip_error_init(&ctx->error); ctx->eof = false; return ctx; } ================================================ FILE: external/libzip/lib/zip_source_write.c ================================================ /* zip_source_write.c -- start a new file for writing Copyright (C) 2014-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "zipint.h" ZIP_EXTERN zip_int64_t zip_source_write(zip_source_t *src, const void *data, zip_uint64_t length) { if (!ZIP_SOURCE_IS_OPEN_WRITING(src) || length > ZIP_INT64_MAX) { zip_error_set(&src->error, ZIP_ER_INVAL, 0); return -1; } return _zip_source_call(src, (void *)data, length, ZIP_SOURCE_WRITE); } ================================================ FILE: external/libzip/lib/zip_source_zip.c ================================================ /* zip_source_zip.c -- create data source from zip file Copyright (C) 1999-2023 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #define _ZIP_COMPILING_DEPRECATED #include "zipint.h" ZIP_EXTERN zip_source_t *zip_source_zip_create(zip_t *srcza, zip_uint64_t srcidx, zip_flags_t flags, zip_uint64_t start, zip_int64_t len, zip_error_t *error) { if (len < -1) { zip_error_set(error, ZIP_ER_INVAL, 0); return NULL; } if (len == 0) { len = -1; } if (start == 0 && len == -1) { flags |= ZIP_FL_COMPRESSED; } else { flags &= ~ZIP_FL_COMPRESSED; } return zip_source_zip_file_create(srcza, srcidx, flags, start, len, NULL, error); } ZIP_EXTERN zip_source_t *zip_source_zip(zip_t *za, zip_t *srcza, zip_uint64_t srcidx, zip_flags_t flags, zip_uint64_t start, zip_int64_t len) { return zip_source_zip_create(srcza, srcidx, flags, start, len, &za->error); } ================================================ FILE: external/libzip/lib/zip_source_zip_new.c ================================================ /* zip_source_zip_new.c -- prepare data structures for zip_fopen/zip_source_zip Copyright (C) 2012-2024 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include "zipint.h" static void _zip_file_attributes_from_dirent(zip_file_attributes_t *attributes, zip_dirent_t *de); ZIP_EXTERN zip_source_t *zip_source_zip_file(zip_t* za, zip_t *srcza, zip_uint64_t srcidx, zip_flags_t flags, zip_uint64_t start, zip_int64_t len, const char *password) { return zip_source_zip_file_create(srcza, srcidx, flags, start, len, password, &za->error); } ZIP_EXTERN zip_source_t *zip_source_zip_file_create(zip_t *srcza, zip_uint64_t srcidx, zip_flags_t flags, zip_uint64_t start, zip_int64_t len, const char *password, zip_error_t *error) { /* TODO: We need to make sure that the returned source is invalidated when srcza is closed. */ zip_source_t *src, *s2; zip_stat_t st; zip_file_attributes_t attributes; zip_dirent_t *de; bool partial_data, needs_crc, encrypted, needs_decrypt, compressed, needs_decompress, changed_data, have_size, have_comp_size; zip_flags_t stat_flags; zip_int64_t data_len; bool take_ownership = false; bool empty_data = false; if (srcza == NULL || srcidx >= srcza->nentry || len < -1) { zip_error_set(error, ZIP_ER_INVAL, 0); return NULL; } if (flags & ZIP_FL_ENCRYPTED) { flags |= ZIP_FL_COMPRESSED; } changed_data = false; if ((flags & ZIP_FL_UNCHANGED) == 0) { zip_entry_t *entry = srcza->entry + srcidx; if (ZIP_ENTRY_DATA_CHANGED(entry)) { if ((flags & ZIP_FL_COMPRESSED) || !zip_source_supports_reopen(entry->source)) { zip_error_set(error, ZIP_ER_CHANGED, 0); return NULL; } changed_data = true; } else if (entry->deleted) { zip_error_set(error, ZIP_ER_CHANGED, 0); return NULL; } } stat_flags = flags; if (!changed_data) { stat_flags |= ZIP_FL_UNCHANGED; } if (zip_stat_index(srcza, srcidx, stat_flags, &st) < 0) { zip_error_set(error, ZIP_ER_INTERNAL, 0); return NULL; } if ((start > 0 || len >= 0) && (flags & ZIP_FL_COMPRESSED)) { zip_error_set(error, ZIP_ER_INVAL, 0); return NULL; } have_size = (st.valid & ZIP_STAT_SIZE) != 0; /* overflow or past end of file */ if (len >= 0 && ((start > 0 && start + len < start) || (have_size && start + len > st.size))) { zip_error_set(error, ZIP_ER_INVAL, 0); return NULL; } if (len == -1) { if (have_size) { if (st.size - start > ZIP_INT64_MAX) { zip_error_set(error, ZIP_ER_INVAL, 0); return NULL; } data_len = (zip_int64_t)(st.size - start); } else { data_len = -1; } } else { data_len = len; } if (have_size) { partial_data = (zip_uint64_t)(data_len) < st.size; } else { partial_data = true; } encrypted = (st.valid & ZIP_STAT_ENCRYPTION_METHOD) && (st.encryption_method != ZIP_EM_NONE); needs_decrypt = ((flags & ZIP_FL_ENCRYPTED) == 0) && encrypted; compressed = (st.valid & ZIP_STAT_COMP_METHOD) && (st.comp_method != ZIP_CM_STORE); needs_decompress = ((flags & ZIP_FL_COMPRESSED) == 0) && compressed; /* when reading the whole file, check for CRC errors */ needs_crc = ((flags & ZIP_FL_COMPRESSED) == 0 || !compressed) && !partial_data && (st.valid & ZIP_STAT_CRC) != 0; if (needs_decrypt) { if (password == NULL) { password = srcza->default_password; } if (password == NULL) { zip_error_set(error, ZIP_ER_NOPASSWD, 0); return NULL; } } if ((de = _zip_get_dirent(srcza, srcidx, flags, error)) == NULL) { return NULL; } _zip_file_attributes_from_dirent(&attributes, de); have_comp_size = (st.valid & ZIP_STAT_COMP_SIZE) != 0; if (needs_decrypt || needs_decompress) { empty_data = (have_comp_size && st.comp_size == 0); } else { empty_data = (have_size && st.size == 0); } if (empty_data) { src = zip_source_buffer_with_attributes_create(NULL, 0, 0, &attributes, error); } else { src = NULL; } /* If we created source buffer above, we want the window source to take ownership of it. */ take_ownership = src != NULL; /* if we created a buffer source above, then treat it as if reading the changed data - that way we don't need add another special case to the code below that wraps it in the window source */ changed_data = changed_data || (src != NULL); if (partial_data && !needs_decrypt && !needs_decompress) { struct zip_stat st2; zip_t *source_archive; zip_uint64_t source_index; if (changed_data) { if (src == NULL) { src = srcza->entry[srcidx].source; } source_archive = NULL; source_index = 0; } else { src = srcza->src; source_archive = srcza; source_index = srcidx; } st2.comp_method = ZIP_CM_STORE; st2.valid = ZIP_STAT_COMP_METHOD; if (data_len >= 0) { st2.size = (zip_uint64_t)data_len; st2.comp_size = (zip_uint64_t)data_len; st2.valid |= ZIP_STAT_SIZE | ZIP_STAT_COMP_SIZE; } if (st.valid & ZIP_STAT_MTIME) { st2.mtime = st.mtime; st2.valid |= ZIP_STAT_MTIME; } if ((src = _zip_source_window_new(src, start, data_len, &st2, ZIP_STAT_NAME, &attributes, &de->last_mod, source_archive, source_index, take_ownership, error)) == NULL) { return NULL; } } /* here we restrict src to file data, so no point in doing it for source that already represents only the file data */ else if (!changed_data) { /* this branch is executed only for archive sources; we know that stat data come from the archive too, so it's safe to assume that st has a comp_size specified */ if (st.comp_size > ZIP_INT64_MAX) { zip_error_set(error, ZIP_ER_INVAL, 0); return NULL; } /* despite the fact that we want the whole data file, we still wrap the source into a window source to add st and attributes and to have a source that positions the read offset properly before each read for multiple zip_file_t referring to the same underlying source */ if ((src = _zip_source_window_new(srcza->src, 0, (zip_int64_t)st.comp_size, &st, ZIP_STAT_NAME, &attributes, &de->last_mod, srcza, srcidx, take_ownership, error)) == NULL) { return NULL; } } else { /* this branch gets executed when reading the whole changed data file or when "reading" from a zero-sized source buffer that we created above */ if (src == NULL) { src = srcza->entry[srcidx].source; } /* despite the fact that we want the whole data file, we still wrap the source into a window source to add st and attributes and to have a source that positions the read offset properly before each read for multiple zip_file_t referring to the same underlying source */ if ((src = _zip_source_window_new(src, 0, data_len, &st, ZIP_STAT_NAME, &attributes, &de->last_mod, NULL, 0, take_ownership, error)) == NULL) { return NULL; } } /* In all cases, src is a window source and therefore is owned by this function. */ if (_zip_source_set_source_archive(src, srcza) < 0) { zip_source_free(src); return NULL; } /* creating a layered source calls zip_keep() on the lower layer, so we free it */ if (needs_decrypt) { zip_encryption_implementation enc_impl; if ((enc_impl = _zip_get_encryption_implementation(st.encryption_method, ZIP_CODEC_DECODE)) == NULL) { zip_source_free(src); zip_error_set(error, ZIP_ER_ENCRNOTSUPP, 0); return NULL; } s2 = enc_impl(srcza, src, st.encryption_method, 0, password); if (s2 == NULL) { zip_source_free(src); return NULL; } src = s2; } if (needs_decompress) { s2 = zip_source_decompress(srcza, src, st.comp_method); if (s2 == NULL) { zip_source_free(src); return NULL; } src = s2; } if (needs_crc) { s2 = zip_source_crc_create(src, 1, error); if (s2 == NULL) { zip_source_free(src); return NULL; } src = s2; } if (partial_data && (needs_decrypt || needs_decompress)) { zip_stat_t st2; zip_stat_init(&st2); if (data_len >= 0) { st2.valid = ZIP_STAT_SIZE; st2.size = (zip_uint64_t)data_len; } s2 = _zip_source_window_new(src, start, data_len, &st2, ZIP_STAT_NAME, NULL, NULL, NULL, 0, true, error); if (s2 == NULL) { zip_source_free(src); return NULL; } src = s2; } return src; } static void _zip_file_attributes_from_dirent(zip_file_attributes_t *attributes, zip_dirent_t *de) { zip_file_attributes_init(attributes); attributes->valid = ZIP_FILE_ATTRIBUTES_ASCII | ZIP_FILE_ATTRIBUTES_HOST_SYSTEM | ZIP_FILE_ATTRIBUTES_EXTERNAL_FILE_ATTRIBUTES | ZIP_FILE_ATTRIBUTES_GENERAL_PURPOSE_BIT_FLAGS; attributes->ascii = de->int_attrib & 1; attributes->host_system = de->version_madeby >> 8; attributes->external_file_attributes = de->ext_attrib; attributes->general_purpose_bit_flags = de->bitflags; attributes->general_purpose_bit_mask = ZIP_FILE_ATTRIBUTES_GENERAL_PURPOSE_BIT_FLAGS_ALLOWED_MASK; } ================================================ FILE: external/libzip/lib/zip_stat.c ================================================ /* zip_stat.c -- get information about file by name Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "zipint.h" ZIP_EXTERN int zip_stat(zip_t *za, const char *fname, zip_flags_t flags, zip_stat_t *st) { zip_int64_t idx; if ((idx = zip_name_locate(za, fname, flags)) < 0) return -1; return zip_stat_index(za, (zip_uint64_t)idx, flags, st); } ================================================ FILE: external/libzip/lib/zip_stat_index.c ================================================ /* zip_stat_index.c -- get information about file by index Copyright (C) 1999-2024 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "zipint.h" ZIP_EXTERN int zip_stat_index(zip_t *za, zip_uint64_t index, zip_flags_t flags, zip_stat_t *st) { const char *name; zip_dirent_t *de; zip_entry_t *entry; if ((de = _zip_get_dirent(za, index, flags, NULL)) == NULL) { return -1; } if ((name = zip_get_name(za, index, flags)) == NULL) { return -1; } entry = za->entry + index; if ((flags & ZIP_FL_UNCHANGED) == 0 && ZIP_ENTRY_DATA_CHANGED(za->entry + index)) { if (zip_source_stat(entry->source, st) < 0) { zip_error_set(&za->error, ZIP_ER_CHANGED, 0); return -1; } if (ZIP_CM_IS_DEFAULT(de->comp_method)) { if (!(st->valid & ZIP_STAT_COMP_METHOD) || st->comp_method == ZIP_CM_STORE) { st->valid &= ~(ZIP_STAT_COMP_SIZE|ZIP_STAT_COMP_METHOD); } } else { if ((st->valid & ZIP_STAT_COMP_METHOD) && st->comp_method != de->comp_method) { st->valid &= ~ZIP_STAT_COMP_SIZE; } st->valid |= ZIP_STAT_COMP_METHOD; st->comp_method = de->comp_method; } if (((st->valid & (ZIP_STAT_COMP_METHOD|ZIP_STAT_SIZE)) == (ZIP_STAT_COMP_METHOD|ZIP_STAT_SIZE)) && st->comp_method == ZIP_CM_STORE) { st->valid |= ZIP_STAT_COMP_SIZE; st->comp_size = st->size; } if (entry->changes != NULL && entry->changes->changed & ZIP_DIRENT_LAST_MOD) { st->mtime = zip_dirent_get_last_mod_mtime(de); st->valid |= ZIP_STAT_MTIME; } } else { zip_stat_init(st); st->crc = de->crc; st->size = de->uncomp_size; st->mtime = zip_dirent_get_last_mod_mtime(de); st->comp_size = de->comp_size; st->comp_method = (zip_uint16_t)de->comp_method; st->encryption_method = de->encryption_method; st->valid = (de->crc_valid ? ZIP_STAT_CRC : 0) | ZIP_STAT_SIZE | ZIP_STAT_MTIME | ZIP_STAT_COMP_SIZE | ZIP_STAT_COMP_METHOD | ZIP_STAT_ENCRYPTION_METHOD; if (entry->changes != NULL && entry->changes->changed & ZIP_DIRENT_COMP_METHOD) { st->valid &= ~ZIP_STAT_COMP_SIZE; } } if ((za->ch_flags & ZIP_AFL_WANT_TORRENTZIP) && (flags & ZIP_FL_UNCHANGED) == 0) { if (za->torrent_mtime == 0) { zip_dostime_t dostime = {0xbc00, 0x2198}; za->torrent_mtime = _zip_d2u_time(&dostime); } st->comp_method = ZIP_CM_DEFLATE; st->mtime = za->torrent_mtime; st->valid |= ZIP_STAT_MTIME | ZIP_STAT_COMP_METHOD; st->valid &= ~ZIP_STAT_COMP_SIZE; } st->index = index; st->name = name; st->valid |= ZIP_STAT_INDEX | ZIP_STAT_NAME; return 0; } ================================================ FILE: external/libzip/lib/zip_stat_init.c ================================================ /* zip_stat_init.c -- initialize struct zip_stat. Copyright (C) 2006-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include "zipint.h" ZIP_EXTERN void zip_stat_init(zip_stat_t *st) { st->valid = 0; st->name = NULL; st->index = ZIP_UINT64_MAX; st->crc = 0; st->mtime = (time_t)-1; st->size = 0; st->comp_size = 0; st->comp_method = ZIP_CM_STORE; st->encryption_method = ZIP_EM_NONE; } int _zip_stat_merge(zip_stat_t *dst, const zip_stat_t *src, zip_error_t *error) { /* name is not merged, since zip_stat_t doesn't own it, and src may not be valid as long as dst */ if (src->valid & ZIP_STAT_INDEX) { dst->index = src->index; } if (src->valid & ZIP_STAT_SIZE) { dst->size = src->size; } if (src->valid & ZIP_STAT_COMP_SIZE) { dst->comp_size = src->comp_size; } if (src->valid & ZIP_STAT_MTIME) { dst->mtime = src->mtime; } if (src->valid & ZIP_STAT_CRC) { dst->crc = src->crc; } if (src->valid & ZIP_STAT_COMP_METHOD) { dst->comp_method = src->comp_method; } if (src->valid & ZIP_STAT_ENCRYPTION_METHOD) { dst->encryption_method = src->encryption_method; } if (src->valid & ZIP_STAT_FLAGS) { dst->flags = src->flags; } dst->valid |= src->valid; return 0; } ================================================ FILE: external/libzip/lib/zip_strerror.c ================================================ /* zip_sterror.c -- get string representation of zip error Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "zipint.h" ZIP_EXTERN const char * zip_strerror(zip_t *za) { return zip_error_strerror(&za->error); } ================================================ FILE: external/libzip/lib/zip_string.c ================================================ /* zip_string.c -- string handling (with encoding) Copyright (C) 2012-2024 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include "zipint.h" zip_uint32_t _zip_string_crc32(const zip_string_t *s) { zip_uint32_t crc; crc = (zip_uint32_t)crc32(0L, Z_NULL, 0); if (s != NULL) crc = (zip_uint32_t)crc32(crc, s->raw, s->length); return crc; } int _zip_string_equal(const zip_string_t *a, const zip_string_t *b) { if (a == NULL || b == NULL) return a == b; if (a->length != b->length) return 0; /* TODO: encoding */ return (memcmp(a->raw, b->raw, a->length) == 0); } void _zip_string_free(zip_string_t *s) { if (s == NULL) return; free(s->raw); free(s->converted); free(s); } const zip_uint8_t * _zip_string_get(zip_string_t *string, zip_uint32_t *lenp, zip_flags_t flags, zip_error_t *error) { static const zip_uint8_t empty[1] = ""; if (string == NULL) { if (lenp) *lenp = 0; return empty; } if ((flags & ZIP_FL_ENC_RAW) == 0) { /* start guessing */ if (string->encoding == ZIP_ENCODING_UNKNOWN) { /* guess encoding, sets string->encoding */ (void)_zip_guess_encoding(string, ZIP_ENCODING_UNKNOWN); } if (((flags & ZIP_FL_ENC_STRICT) && string->encoding != ZIP_ENCODING_ASCII && string->encoding != ZIP_ENCODING_UTF8_KNOWN) || (string->encoding == ZIP_ENCODING_CP437)) { if (string->converted == NULL) { if ((string->converted = _zip_cp437_to_utf8(string->raw, string->length, &string->converted_length, error)) == NULL) return NULL; } if (lenp) *lenp = string->converted_length; return string->converted; } } if (lenp) *lenp = string->length; return string->raw; } bool _zip_string_is_ascii(const zip_string_t *string) { if (string->encoding != ZIP_ENCODING_ASCII) { zip_uint16_t i; for (i = 0; i < string->length; i++) { if (string->raw[i] & 0x80) { return false; } } } return true; } zip_uint16_t _zip_string_length(const zip_string_t *s) { if (s == NULL) return 0; return s->length; } zip_string_t * _zip_string_new(const zip_uint8_t *raw, zip_uint16_t length, zip_flags_t flags, zip_error_t *error) { zip_string_t *s; zip_encoding_type_t expected_encoding; if (length == 0) return NULL; switch (flags & ZIP_FL_ENCODING_ALL) { case ZIP_FL_ENC_GUESS: expected_encoding = ZIP_ENCODING_UNKNOWN; break; case ZIP_FL_ENC_UTF_8: expected_encoding = ZIP_ENCODING_UTF8_KNOWN; break; case ZIP_FL_ENC_CP437: expected_encoding = ZIP_ENCODING_CP437; break; default: zip_error_set(error, ZIP_ER_INVAL, 0); return NULL; } if ((s = (zip_string_t *)malloc(sizeof(*s))) == NULL) { zip_error_set(error, ZIP_ER_MEMORY, 0); return NULL; } if ((s->raw = (zip_uint8_t *)malloc((size_t)length + 1)) == NULL) { free(s); return NULL; } (void)memcpy_s(s->raw, length + 1, raw, length); s->raw[length] = '\0'; s->length = length; s->encoding = ZIP_ENCODING_UNKNOWN; s->converted = NULL; s->converted_length = 0; if (expected_encoding != ZIP_ENCODING_UNKNOWN) { if (_zip_guess_encoding(s, expected_encoding) == ZIP_ENCODING_ERROR) { _zip_string_free(s); zip_error_set(error, ZIP_ER_INVAL, 0); return NULL; } } return s; } int _zip_string_write(zip_t *za, const zip_string_t *s) { if (s == NULL) return 0; return _zip_write(za, s->raw, s->length); } ================================================ FILE: external/libzip/lib/zip_unchange.c ================================================ /* zip_unchange.c -- undo changes to file in zip archive Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include "zipint.h" ZIP_EXTERN int zip_unchange(zip_t *za, zip_uint64_t idx) { return _zip_unchange(za, idx, 0); } int _zip_unchange(zip_t *za, zip_uint64_t idx, int allow_duplicates) { zip_int64_t i; bool renamed; if (idx >= za->nentry) { zip_error_set(&za->error, ZIP_ER_INVAL, 0); return -1; } renamed = za->entry[idx].changes && (za->entry[idx].changes->changed & ZIP_DIRENT_FILENAME); if (!allow_duplicates && (renamed || za->entry[idx].deleted)) { const char *orig_name = NULL; const char *changed_name = NULL; if (za->entry[idx].orig != NULL) { if ((orig_name = _zip_get_name(za, idx, ZIP_FL_UNCHANGED, &za->error)) == NULL) { return -1; } i = _zip_name_locate(za, orig_name, 0, NULL); if (i >= 0 && (zip_uint64_t)i != idx) { zip_error_set(&za->error, ZIP_ER_EXISTS, 0); return -1; } } if (renamed) { if ((changed_name = _zip_get_name(za, idx, 0, &za->error)) == NULL) { return -1; } } if (orig_name) { if (_zip_hash_add(za->names, (const zip_uint8_t *)orig_name, idx, 0, &za->error) == false) { return -1; } } if (changed_name) { if (_zip_hash_delete(za->names, (const zip_uint8_t *)changed_name, &za->error) == false) { _zip_hash_delete(za->names, (const zip_uint8_t *)orig_name, NULL); return -1; } } } _zip_dirent_free(za->entry[idx].changes); za->entry[idx].changes = NULL; _zip_unchange_data(za->entry + idx); return 0; } ================================================ FILE: external/libzip/lib/zip_unchange_all.c ================================================ /* zip_unchange.c -- undo changes to all files in zip archive Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "zipint.h" ZIP_EXTERN int zip_unchange_all(zip_t *za) { int ret; zip_uint64_t i; if (!_zip_hash_revert(za->names, &za->error)) { return -1; } ret = 0; for (i = 0; i < za->nentry; i++) ret |= _zip_unchange(za, i, 1); ret |= zip_unchange_archive(za); return ret; } ================================================ FILE: external/libzip/lib/zip_unchange_archive.c ================================================ /* zip_unchange_archive.c -- undo global changes to ZIP archive Copyright (C) 2006-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include "zipint.h" ZIP_EXTERN int zip_unchange_archive(zip_t *za) { if (za->comment_changed) { _zip_string_free(za->comment_changes); za->comment_changes = NULL; za->comment_changed = 0; } za->ch_flags = za->flags; return 0; } ================================================ FILE: external/libzip/lib/zip_unchange_data.c ================================================ /* zip_unchange_data.c -- undo helper function Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "zipint.h" void _zip_unchange_data(zip_entry_t *ze) { if (ze->source) { zip_source_free(ze->source); ze->source = NULL; } if (ze->changes != NULL && (ze->changes->changed & ZIP_DIRENT_COMP_METHOD) && ze->changes->comp_method == ZIP_CM_REPLACED_DEFAULT) { ze->changes->changed &= ~ZIP_DIRENT_COMP_METHOD; if (ze->changes->changed == 0) { _zip_dirent_free(ze->changes); ze->changes = NULL; } } ze->deleted = 0; } ================================================ FILE: external/libzip/lib/zip_utf-8.c ================================================ /* zip_utf-8.c -- UTF-8 support functions for libzip Copyright (C) 2011-2024 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "zipint.h" #include static const zip_uint16_t _cp437_to_unicode[256] = { /* 0x00 - 0x0F */ 0x0000, 0x263A, 0x263B, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022, 0x25D8, 0x25CB, 0x25D9, 0x2642, 0x2640, 0x266A, 0x266B, 0x263C, /* 0x10 - 0x1F */ 0x25BA, 0x25C4, 0x2195, 0x203C, 0x00B6, 0x00A7, 0x25AC, 0x21A8, 0x2191, 0x2193, 0x2192, 0x2190, 0x221F, 0x2194, 0x25B2, 0x25BC, /* 0x20 - 0x2F */ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, /* 0x30 - 0x3F */ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, /* 0x40 - 0x4F */ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, /* 0x50 - 0x5F */ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, /* 0x60 - 0x6F */ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, /* 0x70 - 0x7F */ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x2302, /* 0x80 - 0x8F */ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5, /* 0x90 - 0x9F */ 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192, /* 0xA0 - 0xAF */ 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, /* 0xB0 - 0xBF */ 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, /* 0xC0 - 0xCF */ 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, /* 0xD0 - 0xDF */ 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, /* 0xE0 - 0xEF */ 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229, /* 0xF0 - 0xFF */ 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0}; #define UTF_8_LEN_2_MASK 0xe0 #define UTF_8_LEN_2_MATCH 0xc0 #define UTF_8_LEN_3_MASK 0xf0 #define UTF_8_LEN_3_MATCH 0xe0 #define UTF_8_LEN_4_MASK 0xf8 #define UTF_8_LEN_4_MATCH 0xf0 #define UTF_8_CONTINUE_MASK 0xc0 #define UTF_8_CONTINUE_MATCH 0x80 zip_encoding_type_t _zip_guess_encoding(zip_string_t *str, zip_encoding_type_t expected_encoding) { zip_encoding_type_t enc; const zip_uint8_t *name; zip_uint32_t i, j, ulen; bool can_be_ascii = true; bool can_be_utf8 = true; bool has_control_characters = false; if (str == NULL) { return ZIP_ENCODING_ASCII; } name = str->raw; if (str->encoding != ZIP_ENCODING_UNKNOWN) { return str->encoding; } for (i = 0; i < str->length; i++) { if (name[i] < 128) { if (name[i] < 32 && name[i] != '\r' && name[i] != '\n' && name[i] != '\t') { has_control_characters = true; } continue; } can_be_ascii = false; if ((name[i] & UTF_8_LEN_2_MASK) == UTF_8_LEN_2_MATCH) { ulen = 1; } else if ((name[i] & UTF_8_LEN_3_MASK) == UTF_8_LEN_3_MATCH) { ulen = 2; } else if ((name[i] & UTF_8_LEN_4_MASK) == UTF_8_LEN_4_MATCH) { ulen = 3; } else { can_be_utf8 = false; break; } if (i + ulen >= str->length) { can_be_utf8 = false; break; } for (j = 1; j <= ulen; j++) { if ((name[i + j] & UTF_8_CONTINUE_MASK) != UTF_8_CONTINUE_MATCH) { can_be_utf8 = false; goto done; } } i += ulen; } done: enc = ZIP_ENCODING_CP437; switch (expected_encoding) { case ZIP_ENCODING_UTF8_KNOWN: case ZIP_ENCODING_UTF8_GUESSED: if (can_be_utf8) { enc = ZIP_ENCODING_UTF8_KNOWN; } else { enc = ZIP_ENCODING_ERROR; } break; case ZIP_ENCODING_ASCII: if (can_be_ascii && !has_control_characters) { enc = ZIP_ENCODING_ASCII; } else { enc = ZIP_ENCODING_ERROR; } break; case ZIP_ENCODING_CP437: enc = ZIP_ENCODING_CP437; break; case ZIP_ENCODING_UNKNOWN: if (can_be_ascii && !has_control_characters) { /* only bytes from 0x20-0x7F */ enc = ZIP_ENCODING_ASCII; } else if (can_be_ascii && has_control_characters) { /* only bytes from 0x00-0x7F */ enc = ZIP_ENCODING_CP437; } else if (can_be_utf8) { /* contains bytes from 0x80-0xFF and is valid UTF-8 */ enc = ZIP_ENCODING_UTF8_GUESSED; } else { /* fallback */ enc = ZIP_ENCODING_CP437; } break; case ZIP_ENCODING_ERROR: /* invalid, shouldn't happen */ enc = ZIP_ENCODING_ERROR; break; } str->encoding = enc; return enc; } static zip_uint32_t _zip_unicode_to_utf8_len(zip_uint32_t codepoint) { if (codepoint < 0x0080) { return 1; } if (codepoint < 0x0800) { return 2; } if (codepoint < 0x10000) { return 3; } return 4; } static zip_uint32_t _zip_unicode_to_utf8(zip_uint32_t codepoint, zip_uint8_t *buf) { if (codepoint < 0x0080) { buf[0] = codepoint & 0xff; return 1; } if (codepoint < 0x0800) { buf[0] = (zip_uint8_t)(UTF_8_LEN_2_MATCH | ((codepoint >> 6) & 0x1f)); buf[1] = (zip_uint8_t)(UTF_8_CONTINUE_MATCH | (codepoint & 0x3f)); return 2; } if (codepoint < 0x10000) { buf[0] = (zip_uint8_t)(UTF_8_LEN_3_MATCH | ((codepoint >> 12) & 0x0f)); buf[1] = (zip_uint8_t)(UTF_8_CONTINUE_MATCH | ((codepoint >> 6) & 0x3f)); buf[2] = (zip_uint8_t)(UTF_8_CONTINUE_MATCH | (codepoint & 0x3f)); return 3; } buf[0] = (zip_uint8_t)(UTF_8_LEN_4_MATCH | ((codepoint >> 18) & 0x07)); buf[1] = (zip_uint8_t)(UTF_8_CONTINUE_MATCH | ((codepoint >> 12) & 0x3f)); buf[2] = (zip_uint8_t)(UTF_8_CONTINUE_MATCH | ((codepoint >> 6) & 0x3f)); buf[3] = (zip_uint8_t)(UTF_8_CONTINUE_MATCH | (codepoint & 0x3f)); return 4; } zip_uint8_t * _zip_cp437_to_utf8(const zip_uint8_t *const _cp437buf, zip_uint32_t len, zip_uint32_t *utf8_lenp, zip_error_t *error) { zip_uint8_t *cp437buf = (zip_uint8_t *)_cp437buf; zip_uint8_t *utf8buf; zip_uint32_t buflen, i, offset; if (len == 0) { if (utf8_lenp) { *utf8_lenp = 0; } return NULL; } buflen = 1; for (i = 0; i < len; i++) { buflen += _zip_unicode_to_utf8_len(_cp437_to_unicode[cp437buf[i]]); } if ((utf8buf = (zip_uint8_t *)malloc(buflen)) == NULL) { zip_error_set(error, ZIP_ER_MEMORY, 0); return NULL; } offset = 0; for (i = 0; i < len; i++) { offset += _zip_unicode_to_utf8(_cp437_to_unicode[cp437buf[i]], utf8buf + offset); } utf8buf[buflen - 1] = 0; if (utf8_lenp) { *utf8_lenp = buflen - 1; } return utf8buf; } ================================================ FILE: external/libzip/lib/zip_winzip_aes.c ================================================ /* zip_winzip_aes.c -- Winzip AES de/encryption backend routines Copyright (C) 2017-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "zipint.h" #include "zip_crypto.h" #include #include #define MAX_KEY_LENGTH 256 #define PBKDF2_ITERATIONS 1000 struct _zip_winzip_aes { _zip_crypto_aes_t *aes; _zip_crypto_hmac_t *hmac; zip_uint8_t counter[ZIP_CRYPTO_AES_BLOCK_LENGTH]; zip_uint8_t pad[ZIP_CRYPTO_AES_BLOCK_LENGTH]; int pad_offset; }; static bool aes_crypt(zip_winzip_aes_t *ctx, zip_uint8_t *data, zip_uint64_t length) { zip_uint64_t i, j; for (i = 0; i < length; i++) { if (ctx->pad_offset == AES_BLOCK_SIZE) { for (j = 0; j < 8; j++) { ctx->counter[j]++; if (ctx->counter[j] != 0) { break; } } if (!_zip_crypto_aes_encrypt_block(ctx->aes, ctx->counter, ctx->pad)) { return false; } ctx->pad_offset = 0; } data[i] ^= ctx->pad[ctx->pad_offset++]; } return true; } zip_winzip_aes_t * _zip_winzip_aes_new(const zip_uint8_t *password, zip_uint64_t password_length, const zip_uint8_t *salt, zip_uint16_t encryption_method, zip_uint8_t *password_verify, zip_error_t *error) { zip_winzip_aes_t *ctx; zip_uint8_t buffer[2 * (MAX_KEY_LENGTH / 8) + WINZIP_AES_PASSWORD_VERIFY_LENGTH]; zip_uint16_t key_size = 0; /* in bits */ zip_uint16_t key_length; /* in bytes */ switch (encryption_method) { case ZIP_EM_AES_128: key_size = 128; break; case ZIP_EM_AES_192: key_size = 192; break; case ZIP_EM_AES_256: key_size = 256; break; } if (key_size == 0 || salt == NULL || password == NULL || password_length == 0) { zip_error_set(error, ZIP_ER_INVAL, 0); return NULL; } key_length = key_size / 8; if ((ctx = (zip_winzip_aes_t *)malloc(sizeof(*ctx))) == NULL) { zip_error_set(error, ZIP_ER_MEMORY, 0); return NULL; } memset(ctx->counter, 0, sizeof(ctx->counter)); ctx->pad_offset = ZIP_CRYPTO_AES_BLOCK_LENGTH; if (!_zip_crypto_pbkdf2(password, password_length, salt, key_length / 2, PBKDF2_ITERATIONS, buffer, 2 * key_length + WINZIP_AES_PASSWORD_VERIFY_LENGTH)) { free(ctx); return NULL; } if ((ctx->aes = _zip_crypto_aes_new(buffer, key_size, error)) == NULL) { _zip_crypto_clear(ctx, sizeof(*ctx)); free(ctx); return NULL; } if ((ctx->hmac = _zip_crypto_hmac_new(buffer + key_length, key_length, error)) == NULL) { _zip_crypto_aes_free(ctx->aes); free(ctx); return NULL; } if (password_verify) { (void)memcpy_s(password_verify, WINZIP_AES_PASSWORD_VERIFY_LENGTH, buffer + (2 * key_size / 8), WINZIP_AES_PASSWORD_VERIFY_LENGTH); } return ctx; } bool _zip_winzip_aes_encrypt(zip_winzip_aes_t *ctx, zip_uint8_t *data, zip_uint64_t length) { return aes_crypt(ctx, data, length) && _zip_crypto_hmac(ctx->hmac, data, length); } bool _zip_winzip_aes_decrypt(zip_winzip_aes_t *ctx, zip_uint8_t *data, zip_uint64_t length) { return _zip_crypto_hmac(ctx->hmac, data, length) && aes_crypt(ctx, data, length); } bool _zip_winzip_aes_finish(zip_winzip_aes_t *ctx, zip_uint8_t *hmac) { return _zip_crypto_hmac_output(ctx->hmac, hmac); } void _zip_winzip_aes_free(zip_winzip_aes_t *ctx) { if (ctx == NULL) { return; } _zip_crypto_aes_free(ctx->aes); _zip_crypto_hmac_free(ctx->hmac); free(ctx); } ================================================ FILE: external/libzip/lib/zipint.h ================================================ #ifndef _HAD_ZIPINT_H #define _HAD_ZIPINT_H /* zipint.h -- internal declarations. Copyright (C) 1999-2024 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #include "compat.h" #ifdef ZIP_ALLOCATE_BUFFER #include #endif #ifdef _ZIP_COMPILING_DEPRECATED #define ZIP_DEPRECATED(x) #else #define ZIP_DISABLE_DEPRECATED #endif #include "zip.h" #define CENTRAL_MAGIC "PK\1\2" #define LOCAL_MAGIC "PK\3\4" #define EOCD_MAGIC "PK\5\6" #define DATADES_MAGIC "PK\7\10" #define EOCD64LOC_MAGIC "PK\6\7" #define EOCD64_MAGIC "PK\6\6" #define MAGIC_LEN 4 #define CDENTRYSIZE 46u #define LENTRYSIZE 30 #define MAXCOMLEN 65536 #define MAXEXTLEN 65536 #define EOCDLEN 22 #define EOCD64LOCLEN 20 #define EOCD64LEN 56 #define CDBUFSIZE (MAXCOMLEN + EOCDLEN + EOCD64LOCLEN) #define BUFSIZE 8192 #define EFZIP64SIZE 28 #define EF_WINZIP_AES_SIZE 7 #define MAX_DATA_DESCRIPTOR_LENGTH 24 #define TORRENTZIP_SIGNATURE "TORRENTZIPPED-" #define TORRENTZIP_SIGNATURE_LENGTH 14 #define TORRENTZIP_CRC_LENGTH 8 #define TORRENTZIP_MEM_LEVEL 8 #define TORRENTZIP_COMPRESSION_FLAGS ZIP_UINT16_MAX #define ZIP_CRYPTO_PKWARE_HEADERLEN 12 #define ZIP_CM_REPLACED_DEFAULT (-2) #define ZIP_CM_WINZIP_AES 99 /* Winzip AES encrypted */ #define WINZIP_AES_PASSWORD_VERIFY_LENGTH 2 #define WINZIP_AES_MAX_HEADER_LENGTH (16 + WINZIP_AES_PASSWORD_VERIFY_LENGTH) #define AES_BLOCK_SIZE 16 #define HMAC_LENGTH 10 #define SALT_LENGTH(method) ((method) == ZIP_EM_AES_128 ? 8 : ((method) == ZIP_EM_AES_192 ? 12 : 16)) #define ZIP_CM_IS_DEFAULT(x) ((x) == ZIP_CM_DEFAULT || (x) == ZIP_CM_REPLACED_DEFAULT) #define ZIP_CM_ACTUAL(x) ((zip_uint16_t)(ZIP_CM_IS_DEFAULT(x) ? ZIP_CM_DEFLATE : (x))) #define ZIP_EF_UTF_8_COMMENT 0x6375 #define ZIP_EF_UTF_8_NAME 0x7075 #define ZIP_EF_WINZIP_AES 0x9901 #define ZIP_EF_ZIP64 0x0001 #define ZIP_EF_IS_INTERNAL(id) ((id) == ZIP_EF_UTF_8_COMMENT || (id) == ZIP_EF_UTF_8_NAME || (id) == ZIP_EF_WINZIP_AES || (id) == ZIP_EF_ZIP64) /* according to unzip-6.0's zipinfo.c, this corresponds to a regular file with rw permissions for everyone */ #define ZIP_EXT_ATTRIB_DEFAULT (0100666u << 16) /* according to unzip-6.0's zipinfo.c, this corresponds to a directory with rwx permissions for everyone */ #define ZIP_EXT_ATTRIB_DEFAULT_DIR (0040777u << 16) /* Allowed: Encryption specific bits, data descriptor, compression specific, UTF-8 filename */ #define ZIP_FILE_ATTRIBUTES_GENERAL_PURPOSE_BIT_FLAGS_ALLOWED_MASK 0x083e #define ZIP_MAX(a, b) ((a) > (b) ? (a) : (b)) #define ZIP_MIN(a, b) ((a) < (b) ? (a) : (b)) #define ZIP_REALLOC(memory, alloced_elements, additional_elements, error) zip_realloc((void **)&memory, &alloced_elements, sizeof(*memory), additional_elements, error) /* This section contains API that won't materialize like this. It's placed in the internal section, pending cleanup. */ /* flags for compression and encryption sources */ #define ZIP_CODEC_DECODE 0 /* decompress/decrypt (encode flag not set) */ #define ZIP_CODEC_ENCODE 1 /* compress/encrypt */ typedef zip_source_t *(*zip_encryption_implementation)(zip_t *, zip_source_t *, zip_uint16_t, int, const char *); zip_encryption_implementation _zip_get_encryption_implementation(zip_uint16_t method, int operation); /* clang-format off */ enum zip_compression_status { ZIP_COMPRESSION_OK, ZIP_COMPRESSION_END, ZIP_COMPRESSION_ERROR, ZIP_COMPRESSION_NEED_DATA }; /* clang-format on */ typedef enum zip_compression_status zip_compression_status_t; struct zip_compression_algorithm { /* Return maximum compressed size for uncompressed data of given size. */ zip_uint64_t (*maximum_compressed_size)(zip_uint64_t uncompressed_size); /* called once to create new context */ void *(*allocate)(zip_uint16_t method, zip_uint32_t compression_flags, zip_error_t *error); /* called once to free context */ void (*deallocate)(void *ctx); /* get compression specific general purpose bitflags */ zip_uint16_t (*general_purpose_bit_flags)(void *ctx); /* minimum version needed when using this algorithm */ zip_uint8_t version_needed; /* start processing */ bool (*start)(void *ctx, zip_stat_t *st, zip_file_attributes_t *attributes); /* stop processing */ bool (*end)(void *ctx); /* provide new input data, remains valid until next call to input or end */ bool (*input)(void *ctx, zip_uint8_t *data, zip_uint64_t length); /* all input data has been provided */ bool (*end_of_input)(void *ctx); /* process input data, writing to data, which has room for length bytes, update length to number of bytes written */ zip_compression_status_t (*process)(void *ctx, zip_uint8_t *data, zip_uint64_t *length); }; typedef struct zip_compression_algorithm zip_compression_algorithm_t; extern zip_compression_algorithm_t zip_algorithm_bzip2_compress; extern zip_compression_algorithm_t zip_algorithm_bzip2_decompress; extern zip_compression_algorithm_t zip_algorithm_deflate_compress; extern zip_compression_algorithm_t zip_algorithm_deflate_decompress; extern zip_compression_algorithm_t zip_algorithm_xz_compress; extern zip_compression_algorithm_t zip_algorithm_xz_decompress; extern zip_compression_algorithm_t zip_algorithm_zstd_compress; extern zip_compression_algorithm_t zip_algorithm_zstd_decompress; zip_compression_algorithm_t *_zip_get_compression_algorithm(zip_int32_t method, bool compress); /* This API is not final yet, but we need it internally, so it's private for now. */ const zip_uint8_t *zip_get_extra_field_by_id(zip_t *, int, int, zip_uint16_t, int, zip_uint16_t *); /* This section contains API that is of limited use until support for user-supplied compression/encryption implementation is finished. Thus we will keep it private for now. */ zip_source_t *zip_source_compress(zip_t *za, zip_source_t *src, zip_int32_t cm, zip_uint32_t compression_flags); zip_source_t *zip_source_crc_create(zip_source_t *, int, zip_error_t *error); zip_source_t *zip_source_decompress(zip_t *za, zip_source_t *src, zip_int32_t cm); zip_source_t *zip_source_pkware_decode(zip_t *, zip_source_t *, zip_uint16_t, int, const char *); zip_source_t *zip_source_pkware_encode(zip_t *, zip_source_t *, zip_uint16_t, int, const char *); int zip_source_remove(zip_source_t *); zip_int64_t zip_source_supports(zip_source_t *src); bool zip_source_supports_reopen(zip_source_t *src); zip_source_t *zip_source_winzip_aes_decode(zip_t *, zip_source_t *, zip_uint16_t, int, const char *); zip_source_t *zip_source_winzip_aes_encode(zip_t *, zip_source_t *, zip_uint16_t, int, const char *); zip_source_t *zip_source_buffer_with_attributes(zip_t *za, const void *data, zip_uint64_t len, int freep, zip_file_attributes_t *attributes); zip_source_t *zip_source_buffer_with_attributes_create(const void *data, zip_uint64_t len, int freep, zip_file_attributes_t *attributes, zip_error_t *error); /* error source for layered sources */ enum zip_les { ZIP_LES_NONE, ZIP_LES_UPPER, ZIP_LES_LOWER, ZIP_LES_INVAL }; #define ZIP_DETAIL_ET_GLOBAL 0 #define ZIP_DETAIL_ET_ENTRY 1 struct _zip_err_info { int type; const char *description; }; extern const struct _zip_err_info _zip_err_str[]; extern const int _zip_err_str_count; extern const struct _zip_err_info _zip_err_details[]; extern const int _zip_err_details_count; /* macros for libzip-internal errors */ #define MAX_DETAIL_INDEX 0x7fffff #define MAKE_DETAIL_WITH_INDEX(error, index) ((((index) > MAX_DETAIL_INDEX) ? MAX_DETAIL_INDEX : (int)(index)) << 8 | (error)) #define GET_INDEX_FROM_DETAIL(error) (((error) >> 8) & MAX_DETAIL_INDEX) #define GET_ERROR_FROM_DETAIL(error) ((error) & 0xff) #define ADD_INDEX_TO_DETAIL(error, index) MAKE_DETAIL_WITH_INDEX(GET_ERROR_FROM_DETAIL(error), (index)) /* error code for libzip-internal errors */ #define ZIP_ER_DETAIL_NO_DETAIL 0 /* G no detail */ #define ZIP_ER_DETAIL_CDIR_OVERLAPS_EOCD 1 /* G central directory overlaps EOCD, or there is space between them */ #define ZIP_ER_DETAIL_COMMENT_LENGTH_INVALID 2 /* G archive comment length incorrect */ #define ZIP_ER_DETAIL_CDIR_LENGTH_INVALID 3 /* G central directory length invalid */ #define ZIP_ER_DETAIL_CDIR_ENTRY_INVALID 4 /* E central header invalid */ #define ZIP_ER_DETAIL_CDIR_WRONG_ENTRIES_COUNT 5 /* G central directory count of entries is incorrect */ #define ZIP_ER_DETAIL_ENTRY_HEADER_MISMATCH 6 /* E local and central headers do not match */ #define ZIP_ER_DETAIL_EOCD_LENGTH_INVALID 7 /* G wrong EOCD length */ #define ZIP_ER_DETAIL_EOCD64_OVERLAPS_EOCD 8 /* G EOCD64 overlaps EOCD, or there is space between them */ #define ZIP_ER_DETAIL_EOCD64_WRONG_MAGIC 9 /* G EOCD64 magic incorrect */ #define ZIP_ER_DETAIL_EOCD64_MISMATCH 10 /* G EOCD64 and EOCD do not match */ #define ZIP_ER_DETAIL_CDIR_INVALID 11 /* G invalid value in central directory */ #define ZIP_ER_DETAIL_VARIABLE_SIZE_OVERFLOW 12 /* E variable size fields overflow header */ #define ZIP_ER_DETAIL_INVALID_UTF8_IN_FILENAME 13 /* E invalid UTF-8 in filename */ #define ZIP_ER_DETAIL_INVALID_UTF8_IN_COMMENT 14 /* E invalid UTF-8 in comment */ #define ZIP_ER_DETAIL_INVALID_ZIP64_EF 15 /* E invalid Zip64 extra field */ #define ZIP_ER_DETAIL_INVALID_WINZIPAES_EF 16 /* E invalid WinZip AES extra field */ #define ZIP_ER_DETAIL_EF_TRAILING_GARBAGE 17 /* E garbage at end of extra fields */ #define ZIP_ER_DETAIL_INVALID_EF_LENGTH 18 /* E extra field length is invalid */ #define ZIP_ER_DETAIL_INVALID_FILE_LENGTH 19 /* E file length in header doesn't match actual file length */ #define ZIP_ER_DETAIL_STORED_SIZE_MISMATCH 20 /* E compressed and uncompressed sizes don't match for stored file */ #define ZIP_ER_DETAIL_DATA_DESCRIPTOR_MISMATCH 21 /* E local header and data descriptor do not match */ #define ZIP_ER_DETAIL_EOCD64_LOCATOR_MISMATCH 22 /* G EOCD64 and EOCD64 locator do not match */ #define ZIP_ER_DETAIL_UTF8_FILENAME_MISMATCH 23 /* E UTF-8 filename is ASCII and doesn't match filename */ #define ZIP_ER_DETAIL_UTF8_COMMENT_MISMATCH 24 /* E UTF-8 comment is ASCII and doesn't match comment */ #define ZIP_ER_DETAIL_COMPRESSED_DATA_TRAILING_GARBAGE 25 /* G garbage at end of compressed data */ /* directory entry: general purpose bit flags */ #define ZIP_GPBF_ENCRYPTED 0x0001u /* is encrypted */ #define ZIP_GPBF_DATA_DESCRIPTOR 0x0008u /* crc/size after file data */ #define ZIP_GPBF_STRONG_ENCRYPTION 0x0040u /* uses strong encryption */ #define ZIP_GPBF_ENCODING_UTF_8 0x0800u /* file name encoding is UTF-8 */ /* extra fields */ #define ZIP_EF_LOCAL ZIP_FL_LOCAL /* include in local header */ #define ZIP_EF_CENTRAL ZIP_FL_CENTRAL /* include in central directory */ #define ZIP_EF_BOTH (ZIP_EF_LOCAL | ZIP_EF_CENTRAL) /* include in both */ #define ZIP_FL_FORCE_ZIP64 1024 /* force zip64 extra field (_zip_dirent_write) */ #define ZIP_FL_ENCODING_ALL (ZIP_FL_ENC_GUESS | ZIP_FL_ENC_CP437 | ZIP_FL_ENC_UTF_8) /* encoding type */ enum zip_encoding_type { ZIP_ENCODING_UNKNOWN, /* not yet analyzed */ ZIP_ENCODING_ASCII, /* plain ASCII */ ZIP_ENCODING_UTF8_KNOWN, /* is UTF-8 */ ZIP_ENCODING_UTF8_GUESSED, /* possibly UTF-8 */ ZIP_ENCODING_CP437, /* Code Page 437 */ ZIP_ENCODING_ERROR /* should be UTF-8 but isn't */ }; typedef enum zip_encoding_type zip_encoding_type_t; struct zip_hash; struct zip_progress; typedef struct zip_cdir zip_cdir_t; typedef struct zip_dostime zip_dostime_t; typedef struct zip_dirent zip_dirent_t; typedef struct zip_entry zip_entry_t; typedef struct zip_extra_field zip_extra_field_t; typedef struct zip_string zip_string_t; typedef struct zip_buffer zip_buffer_t; typedef struct zip_hash zip_hash_t; typedef struct zip_progress zip_progress_t; /* zip archive, part of API */ struct zip { zip_source_t *src; /* data source for archive */ unsigned int open_flags; /* flags passed to zip_open */ zip_error_t error; /* error information */ unsigned int flags; /* archive global flags */ unsigned int ch_flags; /* changed archive global flags */ char *default_password; /* password used when no other supplied */ zip_string_t *comment_orig; /* archive comment */ zip_string_t *comment_changes; /* changed archive comment */ bool comment_changed; /* whether archive comment was changed */ zip_uint64_t nentry; /* number of entries */ zip_uint64_t nentry_alloc; /* number of entries allocated */ zip_entry_t *entry; /* entries */ zip_uint64_t nopen_source; /* number of open sources using archive */ zip_uint64_t nopen_source_alloc; /* number of sources allocated */ zip_source_t **open_source; /* open sources using archive */ zip_hash_t *names; /* hash table for name lookup */ zip_progress_t *progress; /* progress callback for zip_close() */ zip_uint32_t* write_crc; /* have _zip_write() compute CRC */ time_t torrent_mtime; }; /* file in zip archive, part of API */ struct zip_file { zip_error_t error; /* error information */ zip_source_t *src; /* data source */ }; /* zip archive directory entry (central or local) */ #define ZIP_DIRENT_COMP_METHOD 0x0001u #define ZIP_DIRENT_FILENAME 0x0002u #define ZIP_DIRENT_COMMENT 0x0004u #define ZIP_DIRENT_EXTRA_FIELD 0x0008u #define ZIP_DIRENT_ATTRIBUTES 0x0010u #define ZIP_DIRENT_LAST_MOD 0x0020u #define ZIP_DIRENT_ENCRYPTION_METHOD 0x0040u #define ZIP_DIRENT_PASSWORD 0x0080u #define ZIP_DIRENT_ALL ZIP_UINT32_MAX struct zip_dostime { zip_uint16_t time; zip_uint16_t date; }; struct zip_dirent { zip_uint32_t changed; bool local_extra_fields_read; /* whether we already read in local header extra fields */ bool cloned; /* whether this instance is cloned, and thus shares non-changed strings */ bool crc_valid; /* if CRC is valid (sometimes not for encrypted archives) */ bool last_mod_mtime_valid; zip_uint16_t version_madeby; /* (c) version of creator */ zip_uint16_t version_needed; /* (cl) version needed to extract */ zip_uint16_t bitflags; /* (cl) general purpose bit flag */ zip_int32_t comp_method; /* (cl) compression method used (uint16 and ZIP_CM_DEFAULT (-1)) */ zip_dostime_t last_mod; /* (cl) time of last modification */ zip_uint32_t crc; /* (cl) CRC-32 of uncompressed data */ zip_uint64_t comp_size; /* (cl) size of compressed data */ zip_uint64_t uncomp_size; /* (cl) size of uncompressed data */ zip_string_t *filename; /* (cl) file name (NUL-terminated) */ zip_extra_field_t *extra_fields; /* (cl) extra fields, parsed */ zip_string_t *comment; /* (c) file comment */ zip_uint32_t disk_number; /* (c) disk number start */ zip_uint16_t int_attrib; /* (c) internal file attributes */ zip_uint32_t ext_attrib; /* (c) external file attributes */ zip_uint64_t offset; /* (c) offset of local header */ zip_uint32_t compression_level; /* level of compression to use (never valid in orig) */ zip_uint16_t encryption_method; /* encryption method, computed from other fields */ char *password; /* file specific encryption password */ time_t last_mod_mtime; /* cached last_mod in Unix time format */ }; /* zip archive central directory */ struct zip_cdir { zip_entry_t *entry; /* directory entries */ zip_uint64_t nentry; /* number of entries */ zip_uint64_t nentry_alloc; /* number of entries allocated */ zip_uint32_t this_disk; zip_uint32_t eocd_disk; zip_uint64_t disk_entries; /* number of entries on this disk */ zip_uint64_t num_entries; /* number of entries on all disks */ zip_uint64_t size; /* size of central directory */ zip_uint64_t offset; /* offset of central directory in file */ zip_uint64_t eocd_offset; /* offset of EOCD in file */ zip_string_t *comment; /* zip archive comment */ bool is_zip64; /* central directory in zip64 format */ }; struct zip_extra_field { zip_extra_field_t *next; zip_flags_t flags; /* in local/central header */ zip_uint16_t id; /* header id */ zip_uint16_t size; /* data size */ zip_uint8_t *data; }; enum zip_source_write_state { ZIP_SOURCE_WRITE_CLOSED, /* write is not in progress */ ZIP_SOURCE_WRITE_OPEN, /* write is in progress */ ZIP_SOURCE_WRITE_FAILED, /* commit failed, only rollback allowed */ ZIP_SOURCE_WRITE_REMOVED /* file was removed */ }; typedef enum zip_source_write_state zip_source_write_state_t; struct zip_source { zip_source_t *src; union { zip_source_callback f; zip_source_layered_callback l; } cb; void *ud; zip_error_t error; zip_int64_t supports; /* supported commands */ unsigned int open_count; /* number of times source was opened (directly or as lower layer) */ zip_source_write_state_t write_state; /* whether source is open for writing */ bool source_closed; /* set if source archive is closed */ zip_t *source_archive; /* zip archive we're reading from, NULL if not from archive */ unsigned int refcount; bool eof; /* EOF reached */ bool had_read_error; /* a previous ZIP_SOURCE_READ reported an error */ zip_uint64_t bytes_read; /* for sources that don't support ZIP_SOURCE_TELL. */ }; #define ZIP_SOURCE_IS_OPEN_READING(src) ((src)->open_count > 0) #define ZIP_SOURCE_IS_OPEN_WRITING(src) ((src)->write_state == ZIP_SOURCE_WRITE_OPEN) #define ZIP_SOURCE_IS_LAYERED(src) ((src)->src != NULL) /* entry in zip archive directory */ struct zip_entry { zip_dirent_t *orig; zip_dirent_t *changes; zip_source_t *source; bool deleted; }; /* file or archive comment, or filename */ struct zip_string { zip_uint8_t *raw; /* raw string */ zip_uint16_t length; /* length of raw string */ enum zip_encoding_type encoding; /* autorecognized encoding */ zip_uint8_t *converted; /* autoconverted string */ zip_uint32_t converted_length; /* length of converted */ }; /* byte array */ /* For performance, we usually keep 8k byte arrays on the stack. However, there are (embedded) systems with a stack size of 12k; for those, use malloc()/free() */ #ifdef ZIP_ALLOCATE_BUFFER #define DEFINE_BYTE_ARRAY(buf, size) zip_uint8_t *buf #define byte_array_init(buf, size) (((buf) = (zip_uint8_t *)malloc(size)) != NULL) #define byte_array_fini(buf) (free(buf)) #else #define DEFINE_BYTE_ARRAY(buf, size) zip_uint8_t buf[size] #define byte_array_init(buf, size) (1) #define byte_array_fini(buf) ((void)0) #endif /* bounds checked access to memory buffer */ struct zip_buffer { bool ok; bool free_data; zip_uint8_t *data; zip_uint64_t size; zip_uint64_t offset; }; /* which files to write in which order */ struct zip_filelist { zip_uint64_t idx; const char *name; }; typedef struct zip_filelist zip_filelist_t; struct _zip_winzip_aes; typedef struct _zip_winzip_aes zip_winzip_aes_t; struct _zip_pkware_keys { zip_uint32_t key[3]; }; typedef struct _zip_pkware_keys zip_pkware_keys_t; #define ZIP_MAX(a, b) ((a) > (b) ? (a) : (b)) #define ZIP_MIN(a, b) ((a) < (b) ? (a) : (b)) #define ZIP_ENTRY_CHANGED(e, f) ((e)->changes && ((e)->changes->changed & (f))) #define ZIP_ENTRY_DATA_CHANGED(x) ((x)->source != NULL) #define ZIP_ENTRY_HAS_CHANGES(e) (ZIP_ENTRY_DATA_CHANGED(e) || (e)->deleted || ZIP_ENTRY_CHANGED((e), ZIP_DIRENT_ALL)) #define ZIP_IS_RDONLY(za) ((za)->ch_flags & ZIP_AFL_RDONLY) #define ZIP_IS_TORRENTZIP(za) ((za)->flags & ZIP_AFL_IS_TORRENTZIP) #define ZIP_WANT_TORRENTZIP(za) ((za)->ch_flags & ZIP_AFL_WANT_TORRENTZIP) #ifdef HAVE_EXPLICIT_MEMSET #define _zip_crypto_clear(b, l) explicit_memset((b), 0, (l)) #else #ifdef HAVE_EXPLICIT_BZERO #define _zip_crypto_clear(b, l) explicit_bzero((b), (l)) #else #include #define _zip_crypto_clear(b, l) memset((b), 0, (l)) #endif #endif zip_int64_t _zip_add_entry(zip_t *); zip_uint8_t *_zip_buffer_data(zip_buffer_t *buffer); bool _zip_buffer_eof(zip_buffer_t *buffer); void _zip_buffer_free(zip_buffer_t *buffer); zip_uint8_t *_zip_buffer_get(zip_buffer_t *buffer, zip_uint64_t length); zip_uint16_t _zip_buffer_get_16(zip_buffer_t *buffer); zip_uint32_t _zip_buffer_get_32(zip_buffer_t *buffer); zip_uint64_t _zip_buffer_get_64(zip_buffer_t *buffer); zip_uint8_t _zip_buffer_get_8(zip_buffer_t *buffer); zip_uint64_t _zip_buffer_left(zip_buffer_t *buffer); zip_buffer_t *_zip_buffer_new(zip_uint8_t *data, zip_uint64_t size); zip_buffer_t *_zip_buffer_new_from_source(zip_source_t *src, zip_uint64_t size, zip_uint8_t *buf, zip_error_t *error); zip_uint64_t _zip_buffer_offset(zip_buffer_t *buffer); bool _zip_buffer_ok(zip_buffer_t *buffer); zip_uint8_t *_zip_buffer_peek(zip_buffer_t *buffer, zip_uint64_t length); int _zip_buffer_put(zip_buffer_t *buffer, const void *src, size_t length); int _zip_buffer_put_16(zip_buffer_t *buffer, zip_uint16_t i); int _zip_buffer_put_32(zip_buffer_t *buffer, zip_uint32_t i); int _zip_buffer_put_64(zip_buffer_t *buffer, zip_uint64_t i); int _zip_buffer_put_8(zip_buffer_t *buffer, zip_uint8_t i); zip_uint64_t _zip_buffer_read(zip_buffer_t *buffer, zip_uint8_t *data, zip_uint64_t length); int _zip_buffer_skip(zip_buffer_t *buffer, zip_uint64_t length); int _zip_buffer_set_offset(zip_buffer_t *buffer, zip_uint64_t offset); zip_uint64_t _zip_buffer_size(zip_buffer_t *buffer); void _zip_cdir_free(zip_cdir_t *); bool _zip_cdir_grow(zip_cdir_t *cd, zip_uint64_t additional_entries, zip_error_t *error); zip_cdir_t *_zip_cdir_new(zip_error_t *); zip_int64_t _zip_cdir_write(zip_t *za, const zip_filelist_t *filelist, zip_uint64_t survivors); time_t _zip_d2u_time(const zip_dostime_t*); void _zip_deregister_source(zip_t *za, zip_source_t *src); bool _zip_dirent_apply_attributes(zip_dirent_t *, zip_file_attributes_t *, bool); int zip_dirent_check_consistency(zip_dirent_t *dirent); zip_dirent_t *_zip_dirent_clone(const zip_dirent_t *); void _zip_dirent_free(zip_dirent_t *); void _zip_dirent_finalize(zip_dirent_t *); time_t zip_dirent_get_last_mod_mtime(zip_dirent_t *de); void _zip_dirent_init(zip_dirent_t *); bool _zip_dirent_merge(zip_dirent_t *de, zip_dirent_t *de_orig, bool replacing_data, zip_error_t *error); bool _zip_dirent_needs_zip64(const zip_dirent_t *, zip_flags_t); zip_dirent_t *_zip_dirent_new(void); bool zip_dirent_process_ef_zip64(zip_dirent_t * zde, const zip_uint8_t * ef, zip_uint64_t got_len, bool local, zip_error_t * error); zip_int64_t _zip_dirent_read(zip_dirent_t *zde, zip_source_t *src, zip_buffer_t *buffer, bool local, zip_uint64_t central_compressed_size, bool check_consistency, zip_error_t *error); void _zip_dirent_set_version_needed(zip_dirent_t *de, bool force_zip64); void zip_dirent_torrentzip_normalize(zip_dirent_t *de); zip_int32_t _zip_dirent_size(zip_source_t *src, zip_uint16_t, zip_error_t *); int _zip_dirent_write(zip_t *za, zip_dirent_t *dirent, zip_flags_t flags); zip_extra_field_t *_zip_ef_clone(const zip_extra_field_t *, zip_error_t *); zip_extra_field_t *_zip_ef_delete_by_id(zip_extra_field_t *, zip_uint16_t, zip_uint16_t, zip_flags_t); void _zip_ef_free(zip_extra_field_t *); const zip_uint8_t *_zip_ef_get_by_id(const zip_extra_field_t *, zip_uint16_t *, zip_uint16_t, zip_uint16_t, zip_flags_t, zip_error_t *); zip_extra_field_t *_zip_ef_merge(zip_extra_field_t *, zip_extra_field_t *); zip_extra_field_t *_zip_ef_new(zip_uint16_t, zip_uint16_t, const zip_uint8_t *, zip_flags_t); bool _zip_ef_parse(const zip_uint8_t *, zip_uint16_t, zip_flags_t, zip_extra_field_t **, zip_error_t *); zip_extra_field_t *_zip_ef_remove_internal(zip_extra_field_t *); zip_uint16_t _zip_ef_size(const zip_extra_field_t *, zip_flags_t); int _zip_ef_write(zip_t *za, const zip_extra_field_t *ef, zip_flags_t flags); void _zip_entry_finalize(zip_entry_t *); void _zip_entry_init(zip_entry_t *); void _zip_error_clear(zip_error_t *); void _zip_error_get(const zip_error_t *, int *, int *); void _zip_error_copy(zip_error_t *dst, const zip_error_t *src); const zip_uint8_t *_zip_extract_extra_field_by_id(zip_error_t *, zip_uint16_t, int, const zip_uint8_t *, zip_uint16_t, zip_uint16_t *); int _zip_file_extra_field_prepare_for_change(zip_t *, zip_uint64_t); int _zip_file_fillbuf(void *, size_t, zip_file_t *); zip_uint64_t _zip_file_get_end(const zip_t *za, zip_uint64_t index, zip_error_t *error); zip_uint64_t _zip_file_get_offset(const zip_t *, zip_uint64_t, zip_error_t *); zip_dirent_t *_zip_get_dirent(zip_t *, zip_uint64_t, zip_flags_t, zip_error_t *); enum zip_encoding_type _zip_guess_encoding(zip_string_t *, enum zip_encoding_type); zip_uint8_t *_zip_cp437_to_utf8(const zip_uint8_t *const, zip_uint32_t, zip_uint32_t *, zip_error_t *); bool _zip_hash_add(zip_hash_t *hash, const zip_uint8_t *name, zip_uint64_t index, zip_flags_t flags, zip_error_t *error); bool _zip_hash_delete(zip_hash_t *hash, const zip_uint8_t *key, zip_error_t *error); void _zip_hash_free(zip_hash_t *hash); zip_int64_t _zip_hash_lookup(zip_hash_t *hash, const zip_uint8_t *name, zip_flags_t flags, zip_error_t *error); zip_hash_t *_zip_hash_new(zip_error_t *error); bool _zip_hash_reserve_capacity(zip_hash_t *hash, zip_uint64_t capacity, zip_error_t *error); bool _zip_hash_revert(zip_hash_t *hash, zip_error_t *error); int _zip_mkstempm(char *path, int mode, bool create_file); zip_t *_zip_open(zip_source_t *, unsigned int, zip_error_t *); void _zip_progress_end(zip_progress_t *progress); void _zip_progress_free(zip_progress_t *progress); int _zip_progress_start(zip_progress_t *progress); int _zip_progress_subrange(zip_progress_t *progress, double start, double end); int _zip_progress_update(zip_progress_t *progress, double value); bool zip_realloc(void **memory, zip_uint64_t *alloced_elements, zip_uint64_t element_size, zip_uint64_t additional_elements, zip_error_t *error); /* this symbol is extern so it can be overridden for regression testing */ ZIP_EXTERN bool zip_secure_random(zip_uint8_t *buffer, zip_uint16_t length); zip_uint32_t zip_random_uint32(void); int _zip_read(zip_source_t *src, zip_uint8_t *data, zip_uint64_t length, zip_error_t *error); int _zip_read_at_offset(zip_source_t *src, zip_uint64_t offset, unsigned char *b, size_t length, zip_error_t *error); zip_uint8_t *_zip_read_data(zip_buffer_t *buffer, zip_source_t *src, size_t length, bool nulp, zip_error_t *error); int _zip_read_local_ef(zip_t *, zip_uint64_t); zip_string_t *_zip_read_string(zip_buffer_t *buffer, zip_source_t *src, zip_uint16_t length, bool nulp, zip_error_t *error); int _zip_register_source(zip_t *za, zip_source_t *src); void _zip_set_open_error(int *zep, const zip_error_t *err, int ze); bool zip_source_accept_empty(zip_source_t *src); zip_int64_t _zip_source_call(zip_source_t *src, void *data, zip_uint64_t length, zip_source_cmd_t command); bool _zip_source_eof(zip_source_t *); int zip_source_get_dos_time(zip_source_t *src, zip_dostime_t *dos_time); zip_source_t *_zip_source_file_or_p(const char *, FILE *, zip_uint64_t, zip_int64_t, const zip_stat_t *, zip_error_t *error); bool _zip_source_had_error(zip_source_t *); void _zip_source_invalidate(zip_source_t *src); zip_source_t *_zip_source_new(zip_error_t *error); int _zip_source_set_source_archive(zip_source_t *, zip_t *); zip_source_t *_zip_source_window_new(zip_source_t *src, zip_uint64_t start, zip_int64_t length, zip_stat_t *st, zip_uint64_t st_invalid, zip_file_attributes_t *attributes, zip_dostime_t *dostime, zip_t *source_archive, zip_uint64_t source_index, bool take_ownership, zip_error_t *error); int _zip_stat_merge(zip_stat_t *dst, const zip_stat_t *src, zip_error_t *error); int _zip_string_equal(const zip_string_t *a, const zip_string_t *b); void _zip_string_free(zip_string_t *string); zip_uint32_t _zip_string_crc32(const zip_string_t *string); const zip_uint8_t *_zip_string_get(zip_string_t *string, zip_uint32_t *lenp, zip_flags_t flags, zip_error_t *error); bool _zip_string_is_ascii(const zip_string_t *string); zip_uint16_t _zip_string_length(const zip_string_t *string); zip_string_t *_zip_string_new(const zip_uint8_t *raw, zip_uint16_t length, zip_flags_t flags, zip_error_t *error); int _zip_string_write(zip_t *za, const zip_string_t *string); bool _zip_winzip_aes_decrypt(zip_winzip_aes_t *ctx, zip_uint8_t *data, zip_uint64_t length); bool _zip_winzip_aes_encrypt(zip_winzip_aes_t *ctx, zip_uint8_t *data, zip_uint64_t length); bool _zip_winzip_aes_finish(zip_winzip_aes_t *ctx, zip_uint8_t *hmac); void _zip_winzip_aes_free(zip_winzip_aes_t *ctx); zip_winzip_aes_t *_zip_winzip_aes_new(const zip_uint8_t *password, zip_uint64_t password_length, const zip_uint8_t *salt, zip_uint16_t key_size, zip_uint8_t *password_verify, zip_error_t *error); void _zip_pkware_encrypt(zip_pkware_keys_t *keys, zip_uint8_t *out, const zip_uint8_t *in, zip_uint64_t len); void _zip_pkware_decrypt(zip_pkware_keys_t *keys, zip_uint8_t *out, const zip_uint8_t *in, zip_uint64_t len); zip_pkware_keys_t *_zip_pkware_keys_new(zip_error_t *error); void _zip_pkware_keys_free(zip_pkware_keys_t *keys); void _zip_pkware_keys_reset(zip_pkware_keys_t *keys); int _zip_changed(const zip_t *, zip_uint64_t *); const char *_zip_get_name(zip_t *, zip_uint64_t, zip_flags_t, zip_error_t *); int _zip_local_header_read(zip_t *, int); void *_zip_memdup(const void *, size_t, zip_error_t *); zip_int64_t _zip_name_locate(zip_t *, const char *, zip_flags_t, zip_error_t *); zip_t *_zip_new(zip_error_t *); zip_int64_t _zip_file_replace(zip_t *, zip_uint64_t, const char *, zip_source_t *, zip_flags_t); int _zip_set_name(zip_t *, zip_uint64_t, const char *, zip_flags_t); int _zip_u2d_time(time_t, zip_dostime_t *, zip_error_t *); int _zip_unchange(zip_t *, zip_uint64_t, int); void _zip_unchange_data(zip_entry_t *); int _zip_write(zip_t *za, const void *data, zip_uint64_t length); #endif /* _HAD_ZIPINT_H */ ================================================ FILE: external/libzip/libzip-config.cmake.in ================================================ @PACKAGE_INIT@ # We need to supply transitive dependencies if this config is for a static library set(IS_SHARED @BUILD_SHARED_LIBS@) if (NOT IS_SHARED) include(CMakeFindDependencyMacro) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_LIST_DIR}/modules") set(ENABLE_BZIP2 @BZIP2_FOUND@) set(ENABLE_LZMA @LIBLZMA_FOUND@) set(ENABLE_ZSTD @ZSTD_FOUND@) set(ENABLE_GNUTLS @GNUTLS_FOUND@) set(ENABLE_MBEDTLS @MBEDTLS_FOUND@) set(ENABLE_OPENSSL @OPENSSL_FOUND@) find_dependency(ZLIB 1.1.2) if(ENABLE_BZIP2) find_dependency(BZip2) endif() if(ENABLE_LZMA) find_dependency(LibLZMA 5.2) endif() if(ENABLE_ZSTD) find_dependency(zstd 1.3.6) endif() if(ENABLE_GNUTLS) find_dependency(Nettle 3.0) find_dependency(GnuTLS) endif() if(ENABLE_MBEDTLS) find_dependency(MbedTLS 1.0) endif() if(ENABLE_OPENSSL) find_dependency(OpenSSL) endif() endif() # Provide all our library targets to users. include("${CMAKE_CURRENT_LIST_DIR}/libzip-targets.cmake") check_required_components(libzip) ================================================ FILE: external/libzip/libzip.pc.in ================================================ prefix=@CMAKE_INSTALL_PREFIX@ exec_prefix=${prefix} bindir=@bindir@ libdir=@libdir@ includedir=@includedir@ zipcmp=${bindir}/zipcmp Name: libzip Description: library for handling zip archives Version: @PROJECT_VERSION@ Libs: @PKG_CONFIG_RPATH@ -L${libdir} -lzip Libs.private: @LIBS@ Cflags: -I${includedir} ================================================ FILE: external/libzip/man/CMakeLists.txt ================================================ set(MAN_PAGES ZIP_SOURCE_GET_ARGS.3 libzip.3 zip.5 zip_add.3 zip_add_dir.3 zip_close.3 zip_compression_method_supported.3 zip_delete.3 zip_dir_add.3 zip_discard.3 zip_encryption_method_supported.3 zip_error.5 zip_error_clear.3 zip_error_code_system.3 zip_error_code_zip.3 zip_error_fini.3 zip_error_get.3 zip_error_get_sys_type.3 zip_error_init.3 zip_error_set.3 zip_error_set_from_source.3 zip_error_strerror.3 zip_error_system_type.3 zip_error_to_data.3 zip_error_to_str.3 zip_errors.3 zip_fclose.3 zip_fdopen.3 zip_file.5 zip_file_add.3 zip_file_attributes_init.3 zip_file_extra_field_delete.3 zip_file_extra_field_get.3 zip_file_extra_field_set.3 zip_file_extra_fields_count.3 zip_file_get_comment.3 zip_file_get_error.3 zip_file_get_external_attributes.3 zip_file_rename.3 zip_file_set_comment.3 zip_file_set_encryption.3 zip_file_set_external_attributes.3 zip_file_set_mtime.3 zip_file_strerror.3 zip_fopen.3 zip_fopen_encrypted.3 zip_fread.3 zip_fseek.3 zip_ftell.3 zip_get_archive_comment.3 zip_get_archive_flag.3 zip_get_error.3 zip_get_file_comment.3 zip_get_name.3 zip_get_num_entries.3 zip_get_num_files.3 zip_libzip_version.3 zip_name_locate.3 zip_open.3 zip_register_cancel_callback_with_state.3 zip_register_progress_callback.3 zip_register_progress_callback_with_state.3 zip_rename.3 zip_set_archive_comment.3 zip_set_archive_flag.3 zip_set_default_password.3 zip_set_file_comment.3 zip_set_file_compression.3 zip_source.5 zip_source_begin_write.3 zip_source_buffer.3 zip_source_buffer_fragment.3 zip_source_close.3 zip_source_commit_write.3 zip_source_error.3 zip_source_file.3 zip_source_filep.3 zip_source_free.3 zip_source_function.3 zip_source_is_deleted.3 zip_source_is_seekable.3 zip_source_layered.3 zip_source_keep.3 zip_source_make_command_bitmap.3 zip_source_open.3 zip_source_read.3 zip_source_rollback_write.3 zip_source_seek.3 zip_source_seek_compute_offset.3 zip_source_seek_write.3 zip_source_stat.3 zip_source_tell.3 zip_source_tell_write.3 zip_source_win32a.3 zip_source_win32handle.3 zip_source_win32w.3 zip_source_window_create.3 zip_source_write.3 zip_source_zip.3 zip_source_zip_file.3 zip_stat.3 zip_stat_init.3 zip_unchange.3 zip_unchange_all.3 zip_unchange_archive.3 zipcmp.1 zipmerge.1 ziptool.1 ) foreach(MAN_PAGE ${MAN_PAGES}) string(REGEX REPLACE "[1-9]$" "${DOCUMENTATION_FORMAT}" SOURCE_FILE ${MAN_PAGE}) if(LIBZIP_DO_INSTALL) if (DOCUMENTATION_FORMAT MATCHES "html") install(FILES ${PROJECT_BINARY_DIR}/man/${MAN_PAGE} DESTINATION ${CMAKE_INSTALL_DOCDIR}/${PROJECT_NAME} RENAME ${SOURCE_FILE}) else() string(REGEX REPLACE ".*(.)$" "man\\1" SUBDIR ${MAN_PAGE}) install(FILES ${PROJECT_BINARY_DIR}/man/${MAN_PAGE} DESTINATION ${CMAKE_INSTALL_MANDIR}/${SUBDIR}) endif() endif() # configure_file does not find out about updates to the sources, and it does not provide a target #configure_file(${SOURCE_FILE} ${MAN_PAGE} COPYONLY) add_custom_command(OUTPUT ${MAN_PAGE} DEPENDS ${SOURCE_FILE} COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/${SOURCE_FILE} ${CMAKE_CURRENT_BINARY_DIR}/${MAN_PAGE} COMMENT "Preparing ${MAN_PAGE}" ) string(REGEX REPLACE "[1-9]$" "html" HTML_FILE ${MAN_PAGE}) string(REGEX REPLACE "[1-9]$" "man" MAN_FILE ${MAN_PAGE}) string(REGEX REPLACE "[1-9]$" "mdoc" MDOC_FILE ${MAN_PAGE}) # html re-generation add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${HTML_FILE} DEPENDS ${MDOC_FILE} COMMAND ${CMAKE_COMMAND} -DIN=${CMAKE_CURRENT_SOURCE_DIR}/${MDOC_FILE} -DOUT=${CMAKE_CURRENT_BINARY_DIR}/${HTML_FILE} -P ${CMAKE_CURRENT_SOURCE_DIR}/update-html.cmake COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_BINARY_DIR}/${HTML_FILE} ${CMAKE_CURRENT_SOURCE_DIR}/${HTML_FILE} ) list(APPEND UPDATEHTML ${CMAKE_CURRENT_BINARY_DIR}/${HTML_FILE}) # man re-generation add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${MAN_FILE} DEPENDS ${MDOC_FILE} COMMAND ${CMAKE_COMMAND} -DIN=${CMAKE_CURRENT_SOURCE_DIR}/${MDOC_FILE} -DOUT=${CMAKE_CURRENT_BINARY_DIR}/${MAN_FILE} -P ${CMAKE_CURRENT_SOURCE_DIR}/update-man.cmake COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_BINARY_DIR}/${MAN_FILE} ${CMAKE_CURRENT_SOURCE_DIR}/${MAN_FILE} ) list(APPEND UPDATEMAN ${CMAKE_CURRENT_BINARY_DIR}/${MAN_FILE}) endforeach() add_custom_target(man ALL DEPENDS ${MAN_PAGES}) add_custom_target(update-man DEPENDS ${UPDATEMAN}) add_custom_target(update-html DEPENDS ${UPDATEHTML}) file(STRINGS links MANPAGE_LINKS) foreach(LINKS_LINE ${MANPAGE_LINKS}) if(${LINKS_LINE} MATCHES "(.*) (.*)") set(SOURCE ${CMAKE_MATCH_1}) set(TARGET ${CMAKE_MATCH_2}) if(LIBZIP_DO_INSTALL) if (DOCUMENTATION_FORMAT MATCHES "html") INSTALL(FILES ${PROJECT_BINARY_DIR}/man/${SOURCE}.3 DESTINATION ${CMAKE_INSTALL_DOCDIR}/${PROJECT_NAME} RENAME ${TARGET}.html) else() INSTALL(FILES ${PROJECT_BINARY_DIR}/man/${SOURCE}.3 DESTINATION ${CMAKE_INSTALL_MANDIR}/man3 RENAME ${TARGET}.3) endif() endif() endif() endforeach() add_custom_target(update_zip_errors COMMAND sh ${PROJECT_SOURCE_DIR}/man/make_zip_errors.sh ${CMAKE_SOURCE_DIR}/lib/zip.h ${PROJECT_SOURCE_DIR}/man/zip_errors.mdoc DEPENDS ${CMAKE_SOURCE_DIR}/lib/zip.h ${PROJECT_SOURCE_DIR}/man/zip_errors.mdoc ) ================================================ FILE: external/libzip/man/ZIP_SOURCE_GET_ARGS.html ================================================ ================================================ FILE: external/libzip/man/ZIP_SOURCE_GET_ARGS.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" ZIP_SOURCE_GET_ARGS -- validate and cast arguments to source callback .\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_SOURCE_GET_ARGS" "3" "December 18, 2017" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBZIP_SOURCE_GET_ARGS\fR \- validate and cast arguments to source callback .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fItype *\fR .br .PD 0 .HP 4n \fBZIP_SOURCE_GET_ARGS\fR(\fItype\fR, \fIvoid\ *data\fR, \fIzip_uint64_t\ len\fR, \fIzip_error_t\ *error\fR); .PD .SH "DESCRIPTION" The \fBZIP_SOURCE_GET_ARGS\fR() macro casts \fIdata\fR to a pointer to \fItype\fR. .SH "RETURN VALUES" On success, \fBZIP_SOURCE_GET_ARGS\fR() returns \fIdata\fR. In case of error, it returns \fRNULL\fR and sets \fIerror\fR. .SH "ERRORS" \fBZIP_SOURCE_GET_ARGS\fR() fails if: .TP 19n [\fRZIP_ER_INVAL\fR] \fIlen\fR is less than the size of \fItype\fR .SH "SEE ALSO" libzip(3), zip_source_function(3) .SH "HISTORY" \fBZIP_SOURCE_GET_ARGS\fR() was added in libzip 1.0. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/ZIP_SOURCE_GET_ARGS.mdoc ================================================ .\" ZIP_SOURCE_GET_ARGS -- validate and cast arguments to source callback .\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd December 18, 2017 .Dt ZIP_SOURCE_GET_ARGS 3 .Os .Sh NAME .Nm ZIP_SOURCE_GET_ARGS .Nd validate and cast arguments to source callback .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft type * .Fn ZIP_SOURCE_GET_ARGS "type" "void *data" "zip_uint64_t len" "zip_error_t *error" .Sh DESCRIPTION The .Fn ZIP_SOURCE_GET_ARGS macro casts .Ar data to a pointer to .Ar type . .Sh RETURN VALUES On success, .Fn ZIP_SOURCE_GET_ARGS returns .Ar data . In case of error, it returns .Dv NULL and sets .Ar error . .Sh ERRORS .Fn ZIP_SOURCE_GET_ARGS fails if: .Bl -tag -width Er .It Bq Er ZIP_ER_INVAL .Ar len is less than the size of .Ar type .El .Sh SEE ALSO .Xr libzip 3 , .Xr zip_source_function 3 .Sh HISTORY .Fn ZIP_SOURCE_GET_ARGS was added in libzip 1.0. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/handle_links ================================================ #!/usr/bin/env perl use strict; my $operation = shift @ARGV; if ($operation !~ m/^(install|uninstall)$/) { print STDERR "$0: unknown operation $operation\n"; exit(1); } my %options = (); for my $arg (@ARGV) { if ($arg =~ m/([^=]*)=(.*)/) { $options{$1} = $2; } else { print STDERR "$0: can't parse option [$arg]\n"; exit(1); } } for my $option (qw(command directory extension file)) { unless (defined($options{$option})) { print STDERR "$0: required variable $option not provided\n"; exit(1); } } my $fh; unless (open $fh, '<', $options{file}) { print STDERR "$0: can't open links file '$options{file}': $!"; exit(1); } my @cmd = split /\s+/, $options{command}; while (my $line = <$fh>) { chomp $line; my @args = split /\s+/, $line; process(@args); } sub process { my ($source, @destinations) = @_; my @args = (@cmd); if ($operation eq 'install') { push @args, "$options{directory}/$source.$options{extension}"; } for my $destination (@destinations) { push @args, "$options{directory}/$destination.$options{extension}"; run_command(@args); pop @args; } } sub run_command { print (join ' ', @_); print "\n"; my $ret = system(@_); if ($ret != 0) { print STDERR "$0: command failed: $?\n"; exit(1); } return 1; } ================================================ FILE: external/libzip/man/libzip.html ================================================ ================================================ FILE: external/libzip/man/libzip.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" libzip.mdoc -- general overview of available functions .\" Copyright (C) 2005-2024 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "LIBZIP" "3" "May 5, 2025" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBlibzip\fR \- library for manipulating zip archives .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .SH "DESCRIPTION" \fBlibzip\fR is a library for reading, creating, and modifying zip archives. .PP The main design criteria for \fBlibzip\fR were: .PD 0 .TP 4n \fB\(bu\fR Maintain a stable API without breaking backwards compatibility. .TP 4n \fB\(bu\fR Do not create corrupt files, even in case of errors. .TP 4n \fB\(bu\fR Do not delete data. .TP 4n \fB\(bu\fR Be efficient. .PD .PP For this reason, when modifying zip archives, \fBlibzip\fR writes to a temporary file and replaces the original zip archive atomically. .SH "GENERAL NOTES" When adding files to an archive, the file data is only read when the new archive is written. Therefore all files added must remain valid until the archive is closed with zip_close(3) or zip_discard(3). .PP Unless explicitly documented, functions should not be passed \fRNULL\fR pointers as arguments. .SH "DATA TYPES" These data types correspond to central concepts in \fBlibzip\fR. Most of them are private, meaning you can't allocate them or access their members directly. This allows extending the structures in the future without breaking compatibility. .SS "zip_t" This type represents an opened archive. See zip(5). .SS "zip_file_t" This type represents a file from an archive that has been opened for reading. See zip_file(5). .SS "zip_source_t" This type represents a source (or destination) of data. It is used in \fBlibzip\fR for providing data when adding or replacing files, accessing data from a file inside an archive, and the data for the archive as a whole. See zip_source(5). .SS "zip_error_t" This type represents information about an error. Its type can be checked against pre-defined constants and it can be converted to a human readable string. See zip_error(5). .SH "FILE NAMES" .SS "Encoding" Names of files in the host file system are expected in UTF-8 encoding. On Windows, variants for ASCII and UTF-16 are also available. .PP Names of files inside archives are by default expected in UTF-8 encoding. Other encodings can be requested by using the flags \fRZIP_FL_ENC_CP437\fR and \fRZIP_FL_ENC_RAW\fR. .PP For details see the relevant man pages. .SS "Directory Separator" The zip format requires the use of forward slash (\(oq/\(cq) as directory separator. Since backslash (\(oq\e\(cq) can be part of a valid file name on Unix systems, \fBlibzip\fR does not automatically convert them, even on Windows. It is the responsibility of the programmer to ensure that all directory separators are passed as forward slashes to \fBlibzip\fR. .SH "THREAD SAFETY" In general, different zip archives opened by \fBlibzip\fR are independent of each other and can be used by parallel-running threads without locking. If you want to use an archive from multiple threads, you have to synchronize access to it yourself. If you use an archive as a source for zip_file_add(3) or zip_file_replace(3), access to the target archive must be synchronized with access to the source archive as well. .SH "READING ZIP ARCHIVES" .SS "Open Archive" .TP 4n \fB\(bu\fR zip_open(3) .PD 0 .TP 4n \fB\(bu\fR zip_open_from_source(3) .TP 4n \fB\(bu\fR zip_fdopen(3) .PD .SS "Get Archive Attributes" .TP 4n \fB\(bu\fR zip_get_archive_comment(3) .PD 0 .TP 4n \fB\(bu\fR zip_get_archive_flag(3) .TP 4n \fB\(bu\fR zip_get_num_entries(3) .PD .SS "Find Files" .TP 4n \fB\(bu\fR zip_name_locate(3) .SS "Read Files" .TP 4n \fB\(bu\fR zip_fopen(3) .PD 0 .TP 4n \fB\(bu\fR zip_fopen_encrypted(3) .TP 4n \fB\(bu\fR zip_fopen_index(3) .TP 4n \fB\(bu\fR zip_fopen_index_encrypted(3) .TP 4n \fB\(bu\fR zip_fread(3) .TP 4n \fB\(bu\fR zip_file_is_seekable(3) .TP 4n \fB\(bu\fR zip_fseek(3) (uncompressed files only) .TP 4n \fB\(bu\fR zip_ftell(3) .TP 4n \fB\(bu\fR zip_fclose(3) .PD .SS "Close Archive" .TP 4n \fB\(bu\fR zip_close(3) .SS "Get File Attributes" .TP 4n \fB\(bu\fR zip_stat(3) .PD 0 .TP 4n \fB\(bu\fR zip_file_get_comment(3) .TP 4n \fB\(bu\fR zip_file_get_external_attributes(3) .TP 4n \fB\(bu\fR zip_get_name(3) .PD .SS "Miscellaneous" .TP 4n \fB\(bu\fR zip_compression_method_supported(3) .PD 0 .TP 4n \fB\(bu\fR zip_encryption_method_supported(3) .TP 4n \fB\(bu\fR zip_set_default_password(3) .PD .SH "CREATING/MODIFYING ZIP ARCHIVES" .SS "Create/Open Archive" .TP 4n \fB\(bu\fR zip_open(3) .SS "Add/Change Files and Directories" .TP 4n \fB\(bu\fR zip_dir_add(3) .PD 0 .TP 4n \fB\(bu\fR zip_file_add(3) .TP 4n \fB\(bu\fR zip_file_replace(3) .TP 4n \fB\(bu\fR zip_file_set_comment(3) .TP 4n \fB\(bu\fR zip_file_set_dostime(3) .TP 4n \fB\(bu\fR zip_file_set_external_attributes(3) .TP 4n \fB\(bu\fR zip_file_set_encryption(3) .TP 4n \fB\(bu\fR zip_file_set_mtime(3) .TP 4n \fB\(bu\fR zip_set_file_compression(3) .TP 4n \fB\(bu\fR zip_source_buffer(3) .TP 4n \fB\(bu\fR zip_source_file(3) .TP 4n \fB\(bu\fR zip_source_filep(3) .TP 4n \fB\(bu\fR zip_source_zip(3) .PD .SS "Rename Files" .TP 4n \fB\(bu\fR zip_rename(3) .SS "Delete Files" .TP 4n \fB\(bu\fR zip_delete(3) .SS "Revert Changes" .TP 4n \fB\(bu\fR zip_unchange(3) .PD 0 .TP 4n \fB\(bu\fR zip_unchange_all(3) .TP 4n \fB\(bu\fR zip_unchange_archive(3) .PD .SS "Read/Modify Extra Fields" .TP 4n \fB\(bu\fR zip_file_extra_field_delete(3) .PD 0 .TP 4n \fB\(bu\fR zip_file_extra_field_delete_by_id(3) .TP 4n \fB\(bu\fR zip_file_extra_field_get(3) .TP 4n \fB\(bu\fR zip_file_extra_field_get_by_id(3) .TP 4n \fB\(bu\fR zip_file_extra_field_set(3) .TP 4n \fB\(bu\fR zip_file_extra_fields_count(3) .TP 4n \fB\(bu\fR zip_file_extra_fields_count_by_id(3) .PD .SS "Close Archive (Writing)" .TP 4n \fB\(bu\fR zip_close(3) .PD 0 .TP 4n \fB\(bu\fR zip_discard(3) .PD .SS "Miscellaneous (Writing)" .TP 4n \fB\(bu\fR zip_file_attributes_init(3) .PD 0 .TP 4n \fB\(bu\fR zip_libzip_version(3) .TP 4n \fB\(bu\fR zip_register_cancel_callback_with_state(3) .TP 4n \fB\(bu\fR zip_register_progress_callback_with_state(3) .TP 4n \fB\(bu\fR zip_set_archive_comment(3) .TP 4n \fB\(bu\fR zip_set_archive_flag(3) .TP 4n \fB\(bu\fR zip_source(5) .PD .SH "SOURCES" .SS "Create Source" .TP 4n \fB\(bu\fR zip_source_buffer(3) .PD 0 .TP 4n \fB\(bu\fR zip_source_file(3) .TP 4n \fB\(bu\fR zip_source_filep(3) .TP 4n \fB\(bu\fR zip_source_function(3) .TP 4n \fB\(bu\fR zip_source_layered(3) .TP 4n \fB\(bu\fR zip_source_zip(3) .PD .SS "Using Source" .TP 4n \fB\(bu\fR zip_file_add(3) .PD 0 .TP 4n \fB\(bu\fR zip_file_replace(3) .TP 4n \fB\(bu\fR zip_open_from_source(3) .PD .SS "Implementing Source" .TP 4n \fB\(bu\fR zip_source_pass_to_lower_layer(3) .SS "Source Life Cycle" .TP 4n \fB\(bu\fR zip_source_free(3) .PD 0 .TP 4n \fB\(bu\fR zip_source_keep(3) .PD .SH "ERROR HANDLING" .TP 4n \fB\(bu\fR zip_error_strerror(3) .PD 0 .TP 4n \fB\(bu\fR zip_strerror(3) .TP 4n \fB\(bu\fR zip_file_strerror(3) .TP 4n \fB\(bu\fR zip_file_get_error(3) .TP 4n \fB\(bu\fR zip_get_error(3) .TP 4n \fB\(bu\fR zip_error_init_with_code(3) .TP 4n \fB\(bu\fR zip_error_set(3) .TP 4n \fB\(bu\fR zip_error_set_from_source(3) .TP 4n \fB\(bu\fR zip_error_system_type(3) .TP 4n \fB\(bu\fR zip_errors(3) .PD .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/libzip.mdoc ================================================ .\" libzip.mdoc -- general overview of available functions .\" Copyright (C) 2005-2024 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd May 5, 2025 .Dt LIBZIP 3 .Os .Sh NAME .Nm libzip .Nd library for manipulating zip archives .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Sh DESCRIPTION .Nm is a library for reading, creating, and modifying zip archives. .Pp The main design criteria for .Nm were: .Bl -bullet -compact .It Maintain a stable API without breaking backwards compatibility. .It Do not create corrupt files, even in case of errors. .It Do not delete data. .It Be efficient. .El .Pp For this reason, when modifying zip archives, .Nm writes to a temporary file and replaces the original zip archive atomically. .Sh GENERAL NOTES When adding files to an archive, the file data is only read when the new archive is written. Therefore all files added must remain valid until the archive is closed with .Xr zip_close 3 or .Xr zip_discard 3 . .Pp Unless explicitly documented, functions should not be passed .Dv NULL pointers as arguments. .Sh DATA TYPES These data types correspond to central concepts in .Nm . Most of them are private, meaning you can't allocate them or access their members directly. This allows extending the structures in the future without breaking compatibility. .Ss zip_t This type represents an opened archive. See .Xr zip 5 . .Ss zip_file_t This type represents a file from an archive that has been opened for reading. See .Xr zip_file 5 . .Ss zip_source_t This type represents a source (or destination) of data. It is used in .Nm for providing data when adding or replacing files, accessing data from a file inside an archive, and the data for the archive as a whole. See .Xr zip_source 5 . .Ss zip_error_t This type represents information about an error. Its type can be checked against pre-defined constants and it can be converted to a human readable string. See .Xr zip_error 5 . .Sh FILE NAMES .Ss Encoding Names of files in the host file system are expected in UTF-8 encoding. On Windows, variants for ASCII and UTF-16 are also available. .Pp Names of files inside archives are by default expected in UTF-8 encoding. Other encodings can be requested by using the flags .Dv ZIP_FL_ENC_CP437 and .Dv ZIP_FL_ENC_RAW . .Pp For details see the relevant man pages. .Ss Directory Separator The zip format requires the use of forward slash .Pq Sq / as directory separator. Since backslash .Pq Sq \e can be part of a valid file name on Unix systems, .Nm does not automatically convert them, even on Windows. It is the responsibility of the programmer to ensure that all directory separators are passed as forward slashes to .Nm . .Sh THREAD SAFETY In general, different zip archives opened by .Nm are independent of each other and can be used by parallel-running threads without locking. If you want to use an archive from multiple threads, you have to synchronize access to it yourself. If you use an archive as a source for .Xr zip_file_add 3 or .Xr zip_file_replace 3 , access to the target archive must be synchronized with access to the source archive as well. .Sh READING ZIP ARCHIVES .Ss Open Archive .Bl -bullet -compact .It .Xr zip_open 3 .It .Xr zip_open_from_source 3 .It .Xr zip_fdopen 3 .El .Ss Get Archive Attributes .Bl -bullet -compact .It .Xr zip_get_archive_comment 3 .It .Xr zip_get_archive_flag 3 .It .Xr zip_get_num_entries 3 .El .Ss Find Files .Bl -bullet -compact .It .Xr zip_name_locate 3 .El .Ss Read Files .Bl -bullet -compact .It .Xr zip_fopen 3 .It .Xr zip_fopen_encrypted 3 .It .Xr zip_fopen_index 3 .It .Xr zip_fopen_index_encrypted 3 .It .Xr zip_fread 3 .It .Xr zip_file_is_seekable 3 .It .Xr zip_fseek 3 (uncompressed files only) .It .Xr zip_ftell 3 .It .Xr zip_fclose 3 .El .Ss Close Archive .Bl -bullet -compact .It .Xr zip_close 3 .El .Ss Get File Attributes .Bl -bullet -compact .It .Xr zip_stat 3 .It .Xr zip_file_get_comment 3 .It .Xr zip_file_get_external_attributes 3 .It .Xr zip_get_name 3 .El .Ss Miscellaneous .Bl -bullet -compact .It .Xr zip_compression_method_supported 3 .It .Xr zip_encryption_method_supported 3 .It .Xr zip_set_default_password 3 .El .Sh CREATING/MODIFYING ZIP ARCHIVES .Ss Create/Open Archive .Bl -bullet -compact .It .Xr zip_open 3 .El .Ss Add/Change Files and Directories .Bl -bullet -compact .It .Xr zip_dir_add 3 .It .Xr zip_file_add 3 .It .Xr zip_file_replace 3 .It .Xr zip_file_set_comment 3 .It .Xr zip_file_set_dostime 3 .It .Xr zip_file_set_external_attributes 3 .It .Xr zip_file_set_encryption 3 .It .Xr zip_file_set_mtime 3 .It .Xr zip_set_file_compression 3 .It .Xr zip_source_buffer 3 .It .Xr zip_source_file 3 .It .Xr zip_source_filep 3 .It .Xr zip_source_zip 3 .El .Ss Rename Files .Bl -bullet -compact .It .Xr zip_rename 3 .El .Ss Delete Files .Bl -bullet -compact .It .Xr zip_delete 3 .El .Ss Revert Changes .Bl -bullet -compact .It .Xr zip_unchange 3 .It .Xr zip_unchange_all 3 .It .Xr zip_unchange_archive 3 .El .Ss Read/Modify Extra Fields .Bl -bullet -compact .It .Xr zip_file_extra_field_delete 3 .It .Xr zip_file_extra_field_delete_by_id 3 .It .Xr zip_file_extra_field_get 3 .It .Xr zip_file_extra_field_get_by_id 3 .It .Xr zip_file_extra_field_set 3 .It .Xr zip_file_extra_fields_count 3 .It .Xr zip_file_extra_fields_count_by_id 3 .El .Ss Close Archive (Writing) .Bl -bullet -compact .It .Xr zip_close 3 .It .Xr zip_discard 3 .El .Ss Miscellaneous (Writing) .Bl -bullet -compact .It .Xr zip_file_attributes_init 3 .It .Xr zip_libzip_version 3 .It .Xr zip_register_cancel_callback_with_state 3 .It .Xr zip_register_progress_callback_with_state 3 .It .Xr zip_set_archive_comment 3 .It .Xr zip_set_archive_flag 3 .It .Xr zip_source 5 .El .Sh SOURCES .Ss Create Source .Bl -bullet -compact .It .Xr zip_source_buffer 3 .It .Xr zip_source_file 3 .It .Xr zip_source_filep 3 .It .Xr zip_source_function 3 .It .Xr zip_source_layered 3 .It .Xr zip_source_zip 3 .El .Ss Using Source .Bl -bullet -compact .It .Xr zip_file_add 3 .It .Xr zip_file_replace 3 .It .Xr zip_open_from_source 3 .El .Ss Implementing Source .Bl -bullet -compact .It .Xr zip_source_pass_to_lower_layer 3 .El .Ss Source Life Cycle .Bl -bullet -compact .It .Xr zip_source_free 3 .It .Xr zip_source_keep 3 .El .Sh ERROR HANDLING .Bl -bullet -compact .It .Xr zip_error_strerror 3 .It .Xr zip_strerror 3 .It .Xr zip_file_strerror 3 .It .Xr zip_file_get_error 3 .It .Xr zip_get_error 3 .It .Xr zip_error_init_with_code 3 .It .Xr zip_error_set 3 .It .Xr zip_error_set_from_source 3 .It .Xr zip_error_system_type 3 .It .Xr zip_errors 3 .El .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/links ================================================ zip_add zip_replace zip_error_clear zip_file_error_clear zip_error_get zip_file_error_get zip_error_init zip_error_init_with_code zip_file_add zip_file_replace zip_file_extra_field_delete zip_file_extra_field_delete_by_id zip_file_extra_field_get zip_file_extra_field_get_by_id zip_file_extra_fields_count zip_file_extra_fields_count_by_id zip_file_set_mtime zip_file_set_dostime zip_file_strerror zip_strerror zip_fopen zip_fopen_index zip_fopen_encrypted zip_fopen_index_encrypted zip_fseek zip_file_is_seekable zip_open zip_open_from_source zip_source_begin_write zip_source_begin_write_cloning zip_source_buffer zip_source_buffer_create zip_source_buffer_fragment zip_source_buffer_fragment_create zip_source_file zip_source_file_create zip_source_filep zip_source_filep_create zip_source_function zip_source_function_create zip_source_layered zip_source_layered_create zip_source_win32a zip_source_win32a_create zip_source_win32handle zip_source_win32handle_create zip_source_win32w zip_source_win32w_create zip_source_zip zip_source_zip_create zip_source_zip_file zip_source_zip_file_create zip_stat zip_stat_index ================================================ FILE: external/libzip/man/update-html.cmake ================================================ # expect variables IN and OUT EXECUTE_PROCESS(COMMAND mandoc -T html -Oman=%N.html,style=../nih-man.css ${IN} OUTPUT_VARIABLE HTML) SET(LINKBASE "http://pubs.opengroup.org/onlinepubs/9699919799/functions/") STRING(REGEX REPLACE "()" "\\1${LINKBASE}\\2\\3" HTML "${HTML}") STRING(REGEX REPLACE "${LINKBASE}(libzip|zip)" "\\1" HTML "${HTML}") STRING(REGEX REPLACE "NetBSD [0-9.]*" "NiH" HTML "${HTML}") FILE(WRITE ${OUT}.new "${HTML}") CONFIGURE_FILE(${OUT}.new ${OUT} COPYONLY) FILE(REMOVE ${OUT}.new) ================================================ FILE: external/libzip/man/update-man.cmake ================================================ # expect variables IN and OUT EXECUTE_PROCESS(COMMAND mandoc -T man ${IN} OUTPUT_VARIABLE MAN) STRING(REGEX REPLACE "(NetBSD|macOS) [0-9.]*" "NiH" MAN "${MAN}") FILE(WRITE ${OUT}.new "${MAN}") CONFIGURE_FILE(${OUT}.new ${OUT} COPYONLY) FILE(REMOVE ${OUT}.new) ================================================ FILE: external/libzip/man/zip.html ================================================ ================================================ FILE: external/libzip/man/zip.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip.mdoc -- description of zip_t .\" Copyright (C) 2025 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP" "5" "May 5, 2025" "NiH" "File Formats Manual" .nh .if n .ad l .SH "NAME" \fBzip\fR \- zip archive structure .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIzip_t *archive\fR; .SH "DESCRIPTION" A \fBzip\fR represents an open zip archive and is used for all functions accessing and modifying archives. .PP It is created with zip_open(3), zip_open_from_source(3), or zip_fdopen(3). .PP It is closed with zip_close(3) (keeping changes) or zip_discard(3) (discarding changes). .PP All objects representing parts of an archive (like \fIzip_file_t\fR) are only valid while the archive remains open. .SH "SEE ALSO" libzip(3), zip_close(3), zip_discard(3), zip_fopen(3), zip_open(3), zip_open_from_source(3) .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip.mdoc ================================================ .\" zip.mdoc -- description of zip_t .\" Copyright (C) 2025 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd May 5, 2025 .Dt ZIP 5 .Os .Sh NAME .Nm zip .Nd zip archive structure .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Vt zip_t *archive ; .Sh DESCRIPTION A .Nm represents an open zip archive and is used for all functions accessing and modifying archives. .Pp It is created with .Xr zip_open 3 , .Xr zip_open_from_source 3 , or .Xr zip_fdopen 3 . .Pp It is closed with .Xr zip_close 3 (keeping changes) or .Xr zip_discard 3 (discarding changes). .Pp All objects representing parts of an archive (like .Vt zip_file_t ) are only valid while the archive remains open. .Sh SEE ALSO .Xr libzip 3 , .Xr zip_close 3 , .Xr zip_discard 3 , .Xr zip_fopen 3 , .Xr zip_open 3 , .Xr zip_open_from_source 3 .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_add.html ================================================ ================================================ FILE: external/libzip/man/zip_add.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_add.mdoc -- add files to zip archive .\" Copyright (C) 2004-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_ADD" "3" "December 18, 2017" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_add\fR, \fBzip_replace\fR \- add file to zip archive or replace file in zip archive (obsolete interface) .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIzip_int64_t\fR .br .PD 0 .HP 4n \fBzip_add\fR(\fIzip_t\ *archive\fR, \fIconst\ char\ *name\fR, \fIzip_source_t\ *source\fR); .PD .PP \fIint\fR .br .PD 0 .HP 4n \fBzip_replace\fR(\fIzip_t\ *archive\fR, \fIzip_uint64_t\ index\fR, \fIzip_source_t\ *source\fR); .PD .SH "DESCRIPTION" The function \fBzip_add\fR() is the obsolete version of zip_file_add(3). It is the same as calling zip_file_add(3) with an empty \fIflags\fR argument. Similarly, the \fBzip_replace\fR() function is the obsolete version of zip_file_replace(3). It is the same as calling zip_file_replace(3) with an empty \fIflags\fR argument. .SH "SEE ALSO" libzip(3), zip_file_add(3), zip_file_replace(3) .SH "HISTORY" \fBzip_add\fR() was added in libzip 0.6. In libzip 0.10 the return type was changed from \fIint\fR to \fIzip_int64_t\fR. It was deprecated in libzip 0.11, use \fBzip_file_add\fR() instead. .PP \fBzip_replace\fR() was added in libzip 0.6. In libzip 0.10 the type of \fIindex\fR was changed from \fIint\fR to \fIzip_uint64_t\fR. It was deprecated in libzip 0.11, use \fBzip_file_replace\fR() instead. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_add.mdoc ================================================ .\" zip_add.mdoc -- add files to zip archive .\" Copyright (C) 2004-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd December 18, 2017 .Dt ZIP_ADD 3 .Os .Sh NAME .Nm zip_add , .Nm zip_replace .Nd add file to zip archive or replace file in zip archive (obsolete interface) .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft zip_int64_t .Fn zip_add "zip_t *archive" "const char *name" "zip_source_t *source" .Ft int .Fn zip_replace "zip_t *archive" "zip_uint64_t index" "zip_source_t *source" .Sh DESCRIPTION The function .Fn zip_add is the obsolete version of .Xr zip_file_add 3 . It is the same as calling .Xr zip_file_add 3 with an empty .Ar flags argument. Similarly, the .Fn zip_replace function is the obsolete version of .Xr zip_file_replace 3 . It is the same as calling .Xr zip_file_replace 3 with an empty .Ar flags argument. .Sh SEE ALSO .Xr libzip 3 , .Xr zip_file_add 3 , .Xr zip_file_replace 3 .Sh HISTORY .Fn zip_add was added in libzip 0.6. In libzip 0.10 the return type was changed from .Vt int to .Vt zip_int64_t . It was deprecated in libzip 0.11, use .Fn zip_file_add instead. .Pp .Fn zip_replace was added in libzip 0.6. In libzip 0.10 the type of .Ar index was changed from .Vt int to .Vt zip_uint64_t . It was deprecated in libzip 0.11, use .Fn zip_file_replace instead. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_add_dir.html ================================================ ================================================ FILE: external/libzip/man/zip_add_dir.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_add_dir.mdoc -- add directory to zip archive .\" Copyright (C) 2006-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_ADD_DIR" "3" "December 18, 2017" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_add_dir\fR \- add directory to zip archive (obsolete interface) .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIzip_int64_t\fR .br .PD 0 .HP 4n \fBzip_add_dir\fR(\fIzip_t\ *archive\fR, \fIconst\ char\ *name\fR); .PD .SH "DESCRIPTION" The function \fBzip_add_dir\fR() is the obsolete version of zip_dir_add(3). It is the same as calling zip_dir_add(3) with an empty flags argument. .SH "SEE ALSO" libzip(3), zip_dir_add(3) .SH "HISTORY" \fBzip_add_dir\fR() was added in libzip 0.8. In libzip 0.10 the return type was changed from \fIint\fR to \fIzip_int64_t\fR. It was deprecated in libzip 0.11, use \fBzip_dir_add\fR() instead. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_add_dir.mdoc ================================================ .\" zip_add_dir.mdoc -- add directory to zip archive .\" Copyright (C) 2006-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd December 18, 2017 .Dt ZIP_ADD_DIR 3 .Os .Sh NAME .Nm zip_add_dir .Nd add directory to zip archive (obsolete interface) .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft zip_int64_t .Fn zip_add_dir "zip_t *archive" "const char *name" .Sh DESCRIPTION The function .Fn zip_add_dir is the obsolete version of .Xr zip_dir_add 3 . It is the same as calling .Xr zip_dir_add 3 with an empty flags argument. .Sh SEE ALSO .Xr libzip 3 , .Xr zip_dir_add 3 .Sh HISTORY .Fn zip_add_dir was added in libzip 0.8. In libzip 0.10 the return type was changed from .Vt int to .Vt zip_int64_t . It was deprecated in libzip 0.11, use .Fn zip_dir_add instead. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_close.html ================================================ ================================================ FILE: external/libzip/man/zip_close.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_close.mdoc -- close zip archive .\" Copyright (C) 2003-2022 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_CLOSE" "3" "January 23, 2023" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_close\fR \- close zip archive .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIint\fR .br .PD 0 .HP 4n \fBzip_close\fR(\fIzip_t\ *archive\fR); .PD .SH "DESCRIPTION" The \fBzip_close\fR() function writes any changes made to \fIarchive\fR to disk. If \fIarchive\fR contains no files, the file is completely removed (no empty archive is written), unless the archive flag \fRZIP_AFL_CREATE_OR_KEEP_FILE_FOR_EMPTY_ARCHIVE\fR is set. If successful, \fIarchive\fR is freed. Otherwise \fIarchive\fR is left unchanged and must still be freed. .PP To close and free a zip archive without saving changes, use zip_discard(3). .PP Progress updates for GUIs can be implemented using zip_register_progress_callback_with_state(3). Cancelling the write of an archive during \fBzip_close\fR can be implemented using zip_register_cancel_callback_with_state(3). .SH "RETURN VALUES" Upon successful completion 0 is returned. Otherwise, \-1 is returned and the error code in \fIarchive\fR is set to indicate the error. .SH "ERRORS" \fBzip_close\fR() will fail if: .TP 19n [\fRZIP_ER_EOF\fR] Unexpected end-of-file found while reading from a file. .TP 19n [\fRZIP_ER_INTERNAL\fR] The callback function of an added or replaced file returned an error but failed to report which. .TP 19n [\fRZIP_ER_INVAL\fR] The \fIpath\fR argument is \fRNULL\fR. .TP 19n [\fRZIP_ER_MEMORY\fR] Required memory could not be allocated. .TP 19n [\fRZIP_ER_NOZIP\fR] File is not a zip archive. .TP 19n [\fRZIP_ER_READ\fR] A file read failed. .TP 19n [\fRZIP_ER_RENAME\fR] A temporary file could not be renamed to its final name. .TP 19n [\fRZIP_ER_SEEK\fR] A file seek failed. .TP 19n [\fRZIP_ER_TMPOPEN\fR] A temporary file could not be created. .TP 19n [\fRZIP_ER_WRITE\fR] A file write failed. .TP 19n [\fRZIP_ER_ZLIB\fR] An error occurred while (de)compressing a stream with zlib(3). .PD 0 .PP Additionally, any errors returned by the callback function for added or replaced files will be passed back. .PD .SH "SEE ALSO" libzip(3), zip_discard(3), zip_fdopen(3), zip_get_error(3), zip_open(3), zip_register_cancel_callback_with_state(3), zip_register_progress_callback_with_state(3), zip_set_archive_flag(3), zip_strerror(3) .SH "HISTORY" \fBzip_close\fR() was added in libzip 0.6. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> .SH "CAVEATS" Please note that all indices, zip_stat(3) information and other data about the archive is invalid after \fBzip_close\fR. When you open the same file again, it will be a completely new \fIzip_t\fR structure. ================================================ FILE: external/libzip/man/zip_close.mdoc ================================================ .\" zip_close.mdoc -- close zip archive .\" Copyright (C) 2003-2022 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd January 23, 2023 .Dt ZIP_CLOSE 3 .Os .Sh NAME .Nm zip_close .Nd close zip archive .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft int .Fn zip_close "zip_t *archive" .Sh DESCRIPTION The .Fn zip_close function writes any changes made to .Ar archive to disk. If .Ar archive contains no files, the file is completely removed (no empty archive is written), unless the archive flag .Dv ZIP_AFL_CREATE_OR_KEEP_FILE_FOR_EMPTY_ARCHIVE is set. If successful, .Ar archive is freed. Otherwise .Ar archive is left unchanged and must still be freed. .Pp To close and free a zip archive without saving changes, use .Xr zip_discard 3 . .Pp Progress updates for GUIs can be implemented using .Xr zip_register_progress_callback_with_state 3 . Cancelling the write of an archive during .Nm can be implemented using .Xr zip_register_cancel_callback_with_state 3 . .Sh RETURN VALUES Upon successful completion 0 is returned. Otherwise, \-1 is returned and the error code in .Ar archive is set to indicate the error. .Sh ERRORS .Fn zip_close will fail if: .Bl -tag -width Er .It Bq Er ZIP_ER_EOF Unexpected end-of-file found while reading from a file. .It Bq Er ZIP_ER_INTERNAL The callback function of an added or replaced file returned an error but failed to report which. .It Bq Er ZIP_ER_INVAL The .Ar path argument is .Dv NULL . .It Bq Er ZIP_ER_MEMORY Required memory could not be allocated. .It Bq Er ZIP_ER_NOZIP File is not a zip archive. .It Bq Er ZIP_ER_READ A file read failed. .It Bq Er ZIP_ER_RENAME A temporary file could not be renamed to its final name. .It Bq Er ZIP_ER_SEEK A file seek failed. .It Bq Er ZIP_ER_TMPOPEN A temporary file could not be created. .It Bq Er ZIP_ER_WRITE A file write failed. .It Bq Er ZIP_ER_ZLIB An error occurred while (de)compressing a stream with .Xr zlib 3 . .El Additionally, any errors returned by the callback function for added or replaced files will be passed back. .Sh SEE ALSO .Xr libzip 3 , .Xr zip_discard 3 , .Xr zip_fdopen 3 , .Xr zip_get_error 3 , .Xr zip_open 3 , .Xr zip_register_cancel_callback_with_state 3 , .Xr zip_register_progress_callback_with_state 3 , .Xr zip_set_archive_flag 3 , .Xr zip_strerror 3 .Sh HISTORY .Fn zip_close was added in libzip 0.6. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at .Sh CAVEATS Please note that all indices, .Xr zip_stat 3 information and other data about the archive is invalid after .Nm . When you open the same file again, it will be a completely new .Vt zip_t structure. ================================================ FILE: external/libzip/man/zip_compression_method_supported.html ================================================ ================================================ FILE: external/libzip/man/zip_compression_method_supported.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_compression_method_supported.mdoc -- return if compression method is supported .\" Copyright (C) 2020 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP files. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_COMPRESSION_METHOD_SUPPORTED" "3" "April 2, 2020" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_compression_method_supported\fR \- return if a compression method is supported .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIint\fR .br .PD 0 .HP 4n \fBzip_compression_method_supported\fR(\fIzip_int32_t\ method\fR, \fIint\ compress\fR); .PD .SH "DESCRIPTION" The \fBzip_compression_method_supported\fR() returns if the compression method \fImethod\fR is supported for compression (if \fIcompress\fR is zero) or decompression (otherwise). .SH "RETURN VALUES" Returns 1 if the method is supported, 0 otherwise. .SH "SEE ALSO" libzip(3), zip_encryption_method_supported(3), zip_set_file_compression(3) .SH "HISTORY" \fBzip_compression_method_supported\fR() was added in libzip 1.7.0. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_compression_method_supported.mdoc ================================================ .\" zip_compression_method_supported.mdoc -- return if compression method is supported .\" Copyright (C) 2020 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP files. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd April 2, 2020 .Dt ZIP_COMPRESSION_METHOD_SUPPORTED 3 .Os .Sh NAME .Nm zip_compression_method_supported .Nd return if a compression method is supported .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft int .Fn zip_compression_method_supported "zip_int32_t method" "int compress" .Sh DESCRIPTION The .Fn zip_compression_method_supported returns if the compression method .Ar method is supported for compression (if .Ar compress is zero) or decompression (otherwise). .Sh RETURN VALUES Returns 1 if the method is supported, 0 otherwise. .Sh SEE ALSO .Xr libzip 3 , .Xr zip_encryption_method_supported 3 , .Xr zip_set_file_compression 3 .Sh HISTORY .Fn zip_compression_method_supported was added in libzip 1.7.0. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_delete.html ================================================ ================================================ FILE: external/libzip/man/zip_delete.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_delete.mdoc -- delete files from zip archive .\" Copyright (C) 2003-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_DELETE" "3" "December 18, 2017" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_delete\fR \- delete file from zip archive .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIint\fR .br .PD 0 .HP 4n \fBzip_delete\fR(\fIzip_t\ *archive\fR, \fIzip_uint64_t\ index\fR); .PD .SH "DESCRIPTION" The file at position \fIindex\fR in the zip archive \fIarchive\fR is marked as deleted. .SH "RETURN VALUES" Upon successful completion 0 is returned. Otherwise, \-1 is returned and the error code in \fIarchive\fR is set to indicate the error. .SH "ERRORS" \fBzip_delete\fR() fails if: .TP 19n [\fRZIP_ER_INVAL\fR] \fIindex\fR is not a valid file index in \fIarchive\fR. .SH "SEE ALSO" libzip(3), zip_unchange(3) .SH "HISTORY" \fBzip_delete\fR() was added in libzip 0.6. In libzip 0.10 the type of \fIindex\fR was changed from \fIint\fR to \fIzip_uint64_t\fR. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_delete.mdoc ================================================ .\" zip_delete.mdoc -- delete files from zip archive .\" Copyright (C) 2003-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd December 18, 2017 .Dt ZIP_DELETE 3 .Os .Sh NAME .Nm zip_delete .Nd delete file from zip archive .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft int .Fn zip_delete "zip_t *archive" "zip_uint64_t index" .Sh DESCRIPTION The file at position .Ar index in the zip archive .Ar archive is marked as deleted. .Sh RETURN VALUES Upon successful completion 0 is returned. Otherwise, \-1 is returned and the error code in .Ar archive is set to indicate the error. .Sh ERRORS .Fn zip_delete fails if: .Bl -tag -width Er .It Bq Er ZIP_ER_INVAL .Ar index is not a valid file index in .Ar archive . .El .Sh SEE ALSO .Xr libzip 3 , .Xr zip_unchange 3 .Sh HISTORY .Fn zip_delete was added in libzip 0.6. In libzip 0.10 the type of .Ar index was changed from .Vt int to .Vt zip_uint64_t . .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_dir_add.html ================================================ ================================================ FILE: external/libzip/man/zip_dir_add.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_dir_add.mdoc -- add directory to zip archive .\" Copyright (C) 2006-2020 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_DIR_ADD" "3" "September 20, 2020" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_dir_add\fR \- add directory to zip archive .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIzip_int64_t\fR .br .PD 0 .HP 4n \fBzip_dir_add\fR(\fIzip_t\ *archive\fR, \fIconst\ char\ *name\fR, \fIzip_flags_t\ flags\fR); .PD .SH "DESCRIPTION" The function \fBzip_dir_add\fR() adds a directory to a zip archive. The argument \fIarchive\fR specifies the zip archive to which the directory should be added. \fIname\fR is the directory's name in the zip archive. .PP This function adds an entry to the archive. It does not check whether a directory with that name exists in the file system, nor does it add its contents if it does. The \fIflags\fR argument can be any of: .TP 22n \fRZIP_FL_ENC_GUESS\fR Guess encoding of \fIname\fR (default). (Only CP-437 and UTF-8 are recognized.) .TP 22n \fRZIP_FL_ENC_UTF_8\fR Interpret \fIname\fR as UTF-8. .TP 22n \fRZIP_FL_ENC_CP437\fR Interpret \fIname\fR as code page 437 (CP-437). .SH "RETURN VALUES" Upon successful completion, the index of the new entry in the archive is returned. Otherwise, \-1 is returned and the error code in \fIarchive\fR is set to indicate the error. .SH "ERRORS" \fBzip_dir_add\fR() fails if: .TP 19n [\fRZIP_ER_EXISTS\fR] There is already an entry called \fIname\fR in the archive. .TP 19n [\fRZIP_ER_INVAL\fR] \fIarchive\fR or \fIname\fR are \fRNULL\fR, or invalid UTF-8 encoded file names. .TP 19n [\fRZIP_ER_MEMORY\fR] Required memory could not be allocated. .SH "SEE ALSO" libzip(3), zip_file_add(3) .SH "HISTORY" \fBzip_dir_add\fR() was added in libzip 0.11. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_dir_add.mdoc ================================================ .\" zip_dir_add.mdoc -- add directory to zip archive .\" Copyright (C) 2006-2020 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd September 20, 2020 .Dt ZIP_DIR_ADD 3 .Os .Sh NAME .Nm zip_dir_add .Nd add directory to zip archive .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft zip_int64_t .Fn zip_dir_add "zip_t *archive" "const char *name" "zip_flags_t flags" .Sh DESCRIPTION The function .Fn zip_dir_add adds a directory to a zip archive. The argument .Ar archive specifies the zip archive to which the directory should be added. .Ar name is the directory's name in the zip archive. .Pp This function adds an entry to the archive. It does not check whether a directory with that name exists in the file system, nor does it add its contents if it does. The .Ar flags argument can be any of: .Bl -tag -width XZIPXFLXENCXSTRICTXX .It Dv ZIP_FL_ENC_GUESS Guess encoding of .Ar name (default). (Only CP-437 and UTF-8 are recognized.) .It Dv ZIP_FL_ENC_UTF_8 Interpret .Ar name as UTF-8. .It Dv ZIP_FL_ENC_CP437 Interpret .Ar name as code page 437 (CP-437). .El .Sh RETURN VALUES Upon successful completion, the index of the new entry in the archive is returned. Otherwise, \-1 is returned and the error code in .Ar archive is set to indicate the error. .Sh ERRORS .Fn zip_dir_add fails if: .Bl -tag -width Er .It Bq Er ZIP_ER_EXISTS There is already an entry called .Ar name in the archive. .It Bq Er ZIP_ER_INVAL .Ar archive or .Ar name are .Dv NULL , or invalid UTF-8 encoded file names. .It Bq Er ZIP_ER_MEMORY Required memory could not be allocated. .El .Sh SEE ALSO .Xr libzip 3 , .Xr zip_file_add 3 .Sh HISTORY .Fn zip_dir_add was added in libzip 0.11. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_discard.html ================================================ ================================================ FILE: external/libzip/man/zip_discard.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_discard.mdoc -- close zip archive and discard changes .\" Copyright (C) 2012-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_DISCARD" "3" "December 18, 2017" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_discard\fR \- close zip archive and discard changes .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIvoid\fR .br .PD 0 .HP 4n \fBzip_discard\fR(\fIzip_t\ *archive\fR); .PD .SH "DESCRIPTION" The \fBzip_discard\fR() function closes \fIarchive\fR and frees the memory allocated for it. Any changes to the archive are not written to disk and discarded. .SH "SEE ALSO" libzip(3), zip_close(3) .SH "HISTORY" \fBzip_discard\fR() was added in libzip 0.11. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_discard.mdoc ================================================ .\" zip_discard.mdoc -- close zip archive and discard changes .\" Copyright (C) 2012-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd December 18, 2017 .Dt ZIP_DISCARD 3 .Os .Sh NAME .Nm zip_discard .Nd close zip archive and discard changes .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft void .Fn zip_discard "zip_t *archive" .Sh DESCRIPTION The .Fn zip_discard function closes .Ar archive and frees the memory allocated for it. Any changes to the archive are not written to disk and discarded. .Sh SEE ALSO .Xr libzip 3 , .Xr zip_close 3 .Sh HISTORY .Fn zip_discard was added in libzip 0.11. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_encryption_method_supported.html ================================================ ================================================ FILE: external/libzip/man/zip_encryption_method_supported.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_encryption_method_supported.mdoc -- return if encryption method is supported .\" Copyright (C) 2020 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP files. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_ENCRYPTION_METHOD_SUPPORTED" "3" "April 2, 2020" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_encryption_method_supported\fR \- return if an encryption method is supported .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIint\fR .br .PD 0 .HP 4n \fBzip_encryption_method_supported\fR(\fIzip_int16_t\ method\fR, \fIint\ encrypt\fR); .PD .SH "DESCRIPTION" The \fBzip_encryption_method_supported\fR() returns if the encryption method \fImethod\fR is supported for encryption (if \fIencrypt\fR is zero) or decryption (otherwise). .SH "RETURN VALUES" Returns 1 if the method is supported, 0 otherwise. .SH "SEE ALSO" libzip(3), zip_compression_method_supported(3), zip_file_set_encryption(3) .SH "HISTORY" \fBzip_encryption_method_supported\fR() was added in libzip 1.7.0. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_encryption_method_supported.mdoc ================================================ .\" zip_encryption_method_supported.mdoc -- return if encryption method is supported .\" Copyright (C) 2020 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP files. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd April 2, 2020 .Dt ZIP_ENCRYPTION_METHOD_SUPPORTED 3 .Os .Sh NAME .Nm zip_encryption_method_supported .Nd return if an encryption method is supported .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft int .Fn zip_encryption_method_supported "zip_int16_t method" "int encrypt" .Sh DESCRIPTION The .Fn zip_encryption_method_supported returns if the encryption method .Ar method is supported for encryption (if .Ar encrypt is zero) or decryption (otherwise). .Sh RETURN VALUES Returns 1 if the method is supported, 0 otherwise. .Sh SEE ALSO .Xr libzip 3 , .Xr zip_compression_method_supported 3 , .Xr zip_file_set_encryption 3 .Sh HISTORY .Fn zip_encryption_method_supported was added in libzip 1.7.0. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_error.html ================================================ ================================================ FILE: external/libzip/man/zip_error.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_error.mdoc -- description of zip_error_t .\" Copyright (C) 2025 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_ERROR" "5" "May 5, 2025" "NiH" "File Formats Manual" .nh .if n .ad l .SH "NAME" \fBzip_error\fR \- error information .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIzip_error_t error\fR; .SH "DESCRIPTION" A \fBzip_error\fR represents information about an error. It is usually allocated directly on the stack or as member of another structure, not via a pointer. .PP It is initialized with zip_error_init(3) or zip_error_init_with_code(3). .PP The type of error can be accessed with zip_error_code_zip(3) and zip_error_code_system(3). It can be converted to a human readable string with zip_error_strerror(3). .PP After use, it should be cleaned up with zip_error_fini(3). .SH "SEE ALSO" zip_error_code_system(3), zip_error_code_zip(3), zip_error_fini(3), zip_error_init(3), zip_error_init_with_code(3), zip_error_strerror(3) .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_error.mdoc ================================================ .\" zip_error.mdoc -- description of zip_error_t .\" Copyright (C) 2025 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd May 5, 2025 .Dt ZIP_ERROR 5 .Os .Sh NAME .Nm zip_error .Nd error information .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Vt zip_error_t error ; .Sh DESCRIPTION A .Nm represents information about an error. It is usually allocated directly on the stack or as member of another structure, not via a pointer. .Pp It is initialized with .Xr zip_error_init 3 or .Xr zip_error_init_with_code 3 . .Pp The type of error can be accessed with .Xr zip_error_code_zip 3 and .Xr zip_error_code_system 3 . It can be converted to a human readable string with .Xr zip_error_strerror 3 . .Pp After use, it should be cleaned up with .Xr zip_error_fini 3 . .Sh SEE ALSO .Xr zip_error_code_system 3 , .Xr zip_error_code_zip 3 , .Xr zip_error_fini 3 , .Xr zip_error_init 3 , .Xr zip_error_init_with_code 3 , .Xr zip_error_strerror 3 .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_error_clear.html ================================================ ================================================ FILE: external/libzip/man/zip_error_clear.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_error_clear.mdoc -- clear error state for archive or file .\" Copyright (C) 2006-2021 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_ERROR_CLEAR" "3" "December 18, 2017" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_error_clear\fR, \fBzip_file_error_clear\fR \- clear error state for archive or file .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIvoid\fR .br .PD 0 .HP 4n \fBzip_error_clear\fR(\fIzip_t\ *archive\fR); .PD .PP \fIvoid\fR .br .PD 0 .HP 4n \fBzip_file_error_clear\fR(\fIzip_file_t\ *file\fR); .PD .SH "DESCRIPTION" The \fBzip_error_clear\fR() function clears the error state for the zip archive \fIarchive\fR. .PP The \fBzip_file_error_clear\fR() function does the same for the zip file \fIfile\fR. .SH "SEE ALSO" libzip(3), zip_get_error(3) .SH "HISTORY" \fBzip_error_clear\fR() and \fBzip_file_error_clear\fR() were added in libzip 0.8. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_error_clear.mdoc ================================================ .\" zip_error_clear.mdoc -- clear error state for archive or file .\" Copyright (C) 2006-2021 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd December 18, 2017 .Dt ZIP_ERROR_CLEAR 3 .Os .Sh NAME .Nm zip_error_clear , .Nm zip_file_error_clear .Nd clear error state for archive or file .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft void .Fn zip_error_clear "zip_t *archive" .Ft void .Fn zip_file_error_clear "zip_file_t *file" .Sh DESCRIPTION The .Fn zip_error_clear function clears the error state for the zip archive .Ar archive . .Pp The .Fn zip_file_error_clear function does the same for the zip file .Ar file . .Sh SEE ALSO .Xr libzip 3 , .Xr zip_get_error 3 .Sh HISTORY .Fn zip_error_clear and .Fn zip_file_error_clear were added in libzip 0.8. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_error_code_system.html ================================================ ================================================ FILE: external/libzip/man/zip_error_code_system.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_error_code_system.mdoc -- get system error part of zip_error .\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_ERROR_CODE_SYSTEM" "3" "December 18, 2017" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_error_code_system\fR \- get operating system error part of zip_error .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIint\fR .br .PD 0 .HP 4n \fBzip_error_code_system\fR(\fIconst\ zip_error_t\ *ze\fR); .PD .SH "DESCRIPTION" The \fBzip_error_code_system\fR() function returns the system specific part of the error from the zip_error error \fIze\fR. For finding out what system reported the error, use zip_error_system_type(3). .SH "SEE ALSO" libzip(3), zip_error_code_zip(3), zip_error_system_type(3) .SH "HISTORY" \fBzip_error_code_system\fR() was added in libzip 1.0. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_error_code_system.mdoc ================================================ .\" zip_error_code_system.mdoc -- get system error part of zip_error .\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd December 18, 2017 .Dt ZIP_ERROR_CODE_SYSTEM 3 .Os .Sh NAME .Nm zip_error_code_system .Nd get operating system error part of zip_error .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft int .Fn zip_error_code_system "const zip_error_t *ze" .Sh DESCRIPTION The .Fn zip_error_code_system function returns the system specific part of the error from the zip_error error .Ar ze . For finding out what system reported the error, use .Xr zip_error_system_type 3 . .Sh SEE ALSO .Xr libzip 3 , .Xr zip_error_code_zip 3 , .Xr zip_error_system_type 3 .Sh HISTORY .Fn zip_error_code_system was added in libzip 1.0. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_error_code_zip.html ================================================ ================================================ FILE: external/libzip/man/zip_error_code_zip.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_error_code_zip.mdoc -- get libzip error part of zip_error .\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_ERROR_CODE_ZIP" "3" "December 18, 2017" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_error_code_zip\fR \- get libzip error part of zip_error .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIint\fR .br .PD 0 .HP 4n \fBzip_error_code_zip\fR(\fIconst\ zip_error_t\ *ze\fR); .PD .SH "DESCRIPTION" The \fBzip_error_code_zip\fR() function returns the libzip specific part of the error from the zip_error error \fIze\fR. .SH "SEE ALSO" libzip(3), zip_error_code_system(3) .SH "HISTORY" \fBzip_error_code_zip\fR() was added in libzip 1.0. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_error_code_zip.mdoc ================================================ .\" zip_error_code_zip.mdoc -- get libzip error part of zip_error .\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd December 18, 2017 .Dt ZIP_ERROR_CODE_ZIP 3 .Os .Sh NAME .Nm zip_error_code_zip .Nd get libzip error part of zip_error .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft int .Fn zip_error_code_zip "const zip_error_t *ze" .Sh DESCRIPTION The .Fn zip_error_code_zip function returns the libzip specific part of the error from the zip_error error .Ar ze . .Sh SEE ALSO .Xr libzip 3 , .Xr zip_error_code_system 3 .Sh HISTORY .Fn zip_error_code_zip was added in libzip 1.0. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_error_fini.html ================================================ ================================================ FILE: external/libzip/man/zip_error_fini.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_error_fini.mdoc -- clean up zip_error .\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_ERROR_FINI" "3" "December 18, 2017" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_error_fini\fR \- clean up zip_error structure .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIvoid\fR .br .PD 0 .HP 4n \fBzip_error_fini\fR(\fIzip_error_t\ *ze\fR); .PD .SH "DESCRIPTION" The \fBzip_error_fini\fR() function cleans up and frees internally allocated memory of the zip_error pointed to by \fIze\fR. .SH "SEE ALSO" libzip(3), zip_error_init(3) .SH "HISTORY" \fBzip_error_fini\fR() was added in libzip 1.0. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_error_fini.mdoc ================================================ .\" zip_error_fini.mdoc -- clean up zip_error .\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd December 18, 2017 .Dt ZIP_ERROR_FINI 3 .Os .Sh NAME .Nm zip_error_fini .Nd clean up zip_error structure .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft void .Fn zip_error_fini "zip_error_t *ze" .Sh DESCRIPTION The .Fn zip_error_fini function cleans up and frees internally allocated memory of the zip_error pointed to by .Ar ze . .Sh SEE ALSO .Xr libzip 3 , .Xr zip_error_init 3 .Sh HISTORY .Fn zip_error_fini was added in libzip 1.0. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_error_get.html ================================================ ================================================ FILE: external/libzip/man/zip_error_get.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_error_get.mdoc -- get error codes for archive or file .\" Copyright (C) 2004-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_ERROR_GET" "3" "December 18, 2017" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_error_get\fR, \fBzip_file_error_get\fR \- get error codes for archive or file (obsolete interface) .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIvoid\fR .br .PD 0 .HP 4n \fBzip_error_get\fR(\fIzip_t\ *archive\fR, \fIint\ *zep\fR, \fIint\ *sep\fR); .PD .PP \fIvoid\fR .br .PD 0 .HP 4n \fBzip_file_error_get\fR(\fIzip_file_t\ *file\fR, \fIint\ *zep\fR, \fIint\ *sep\fR); .PD .SH "DESCRIPTION" The functions \fBzip_error_get\fR() and \fBzip_file_error_get\fR() are deprecated. Use zip_error_code_system(3), zip_error_code_zip(3), zip_file_get_error(3), and zip_get_error(3) instead. .PP For \fBzip_error_get\fR(), replace .nf .sp .RS 6n int ze, se; zip_error_get(za, &ze, &se); .RE .fi with .nf .sp .RS 6n int ze, se; zip_error_t *error = zip_get_error(za); ze = zip_error_code_zip(error); se = zip_error_code_system(error); .RE .fi For \fBzip_file_error_get\fR(), replace .nf .sp .RS 6n int ze, se; zip_file_error_get(zf, &ze, &se); .RE .fi with .nf .sp .RS 6n int ze, se; zip_error_t *error = zip_file_get_error(zf); ze = zip_error_code_zip(error); se = zip_error_code_system(error); .RE .fi .SH "SEE ALSO" libzip(3), zip_error_code_system(3), zip_error_code_zip(3), zip_file_get_error(3), zip_get_error(3) .SH "HISTORY" \fBzip_error_get\fR() was added in libzip 0.6. It was deprecated in libzip 1.0, use \fBzip_get_error\fR(), \fBzip_error_code_zip\fR(), / \fBzip_error_code_system\fR() instead. .PP \fBzip_file_error_get\fR() was added in libzip 0.6. It was deprecated in libzip 1.0, use \fBzip_file_get_error\fR(), \fBzip_error_code_zip\fR(), / \fBzip_error_code_system\fR() instead. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_error_get.mdoc ================================================ .\" zip_error_get.mdoc -- get error codes for archive or file .\" Copyright (C) 2004-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd December 18, 2017 .Dt ZIP_ERROR_GET 3 .Os .Sh NAME .Nm zip_error_get , .Nm zip_file_error_get .Nd get error codes for archive or file (obsolete interface) .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft void .Fn zip_error_get "zip_t *archive" "int *zep" "int *sep" .Ft void .Fn zip_file_error_get "zip_file_t *file" "int *zep" "int *sep" .Sh DESCRIPTION The functions .Fn zip_error_get and .Fn zip_file_error_get are deprecated. Use .Xr zip_error_code_system 3 , .Xr zip_error_code_zip 3 , .Xr zip_file_get_error 3 , and .Xr zip_get_error 3 instead. .Pp For .Fn zip_error_get , replace .Bd -literal -offset indent int ze, se; zip_error_get(za, &ze, &se); .Ed with .Bd -literal -offset indent int ze, se; zip_error_t *error = zip_get_error(za); ze = zip_error_code_zip(error); se = zip_error_code_system(error); .Ed For .Fn zip_file_error_get , replace .Bd -literal -offset indent int ze, se; zip_file_error_get(zf, &ze, &se); .Ed with .Bd -literal -offset indent int ze, se; zip_error_t *error = zip_file_get_error(zf); ze = zip_error_code_zip(error); se = zip_error_code_system(error); .Ed .Sh SEE ALSO .Xr libzip 3 , .Xr zip_error_code_system 3 , .Xr zip_error_code_zip 3 , .Xr zip_file_get_error 3 , .Xr zip_get_error 3 .Sh HISTORY .Fn zip_error_get was added in libzip 0.6. It was deprecated in libzip 1.0, use .Fn zip_get_error , .Fn zip_error_code_zip , / .Fn zip_error_code_system instead. .Pp .Fn zip_file_error_get was added in libzip 0.6. It was deprecated in libzip 1.0, use .Fn zip_file_get_error , .Fn zip_error_code_zip , / .Fn zip_error_code_system instead. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_error_get_sys_type.html ================================================ ================================================ FILE: external/libzip/man/zip_error_get_sys_type.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_error_get_sys_type.mdoc -- get type of error .\" Copyright (C) 2004-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_ERROR_GET_SYS_TYPE" "3" "December 18, 2017" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_error_get_sys_type\fR \- get type of system error code (obsolete interface) .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIint\fR .br .PD 0 .HP 4n \fBzip_error_get_sys_type\fR(\fIint\ ze\fR); .PD .SH "DESCRIPTION" The function \fBzip_error_get_sys_type\fR() is deprecated; use zip_error_init_with_code(3) and zip_error_system_type(3) instead. .PP Replace .nf .sp .RS 6n int i = zip_error_get_sys_type(ze); .RE .fi with .nf .sp .RS 6n zip_error_t error; zip_error_init_with_code(&error, ze); int i = zip_error_system_type(&error); .RE .fi .SH "SEE ALSO" libzip(3), zip_error_init_with_code(3), zip_error_system_type(3) .SH "HISTORY" \fBzip_error_get_sys_type\fR() was added in libzip 0.6. It was deprecated in libzip 1.0, use \fBzip_error_system_type\fR() instead. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_error_get_sys_type.mdoc ================================================ .\" zip_error_get_sys_type.mdoc -- get type of error .\" Copyright (C) 2004-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd December 18, 2017 .Dt ZIP_ERROR_GET_SYS_TYPE 3 .Os .Sh NAME .Nm zip_error_get_sys_type .Nd get type of system error code (obsolete interface) .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft int .Fn zip_error_get_sys_type "int ze" .Sh DESCRIPTION The function .Fn zip_error_get_sys_type is deprecated; use .Xr zip_error_init_with_code 3 and .Xr zip_error_system_type 3 instead. .Pp Replace .Bd -literal -offset indent int i = zip_error_get_sys_type(ze); .Ed with .Bd -literal -offset indent zip_error_t error; zip_error_init_with_code(&error, ze); int i = zip_error_system_type(&error); .Ed .Sh SEE ALSO .Xr libzip 3 , .Xr zip_error_init_with_code 3 , .Xr zip_error_system_type 3 .Sh HISTORY .Fn zip_error_get_sys_type was added in libzip 0.6. It was deprecated in libzip 1.0, use .Fn zip_error_system_type instead. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_error_init.html ================================================ ================================================ FILE: external/libzip/man/zip_error_init.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_error_init.mdoc -- initialize zip_error .\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_ERROR_INIT" "3" "December 18, 2017" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_error_init\fR, \fBzip_error_init_with_code\fR \- initialize zip_error structure .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIvoid\fR .br .PD 0 .HP 4n \fBzip_error_init\fR(\fIzip_error_t\ *error\fR); .PD .PP \fIvoid\fR .br .PD 0 .HP 4n \fBzip_error_init_with_code\fR(\fIzip_error_t\ *error\fR, \fIint\ ze\fR); .PD .SH "DESCRIPTION" The \fBzip_error_init\fR() function initializes the zip_error pointed to by \fIerror\fR. \fI*error\fR must be allocated before calling \fBzip_error_init\fR(). .PP The \fBzip_error_init_with_code\fR() function does the same, but additionally sets the zip error code to \fIze\fR and sets the system error code to the current errno(3) value, if appropriate. .SH "SEE ALSO" libzip(3), zip_error_fini(3) .SH "HISTORY" \fBzip_error_init\fR() and \fBzip_error_init_with_code\fR() were added in libzip 1.0. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_error_init.mdoc ================================================ .\" zip_error_init.mdoc -- initialize zip_error .\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd December 18, 2017 .Dt ZIP_ERROR_INIT 3 .Os .Sh NAME .Nm zip_error_init , .Nm zip_error_init_with_code .Nd initialize zip_error structure .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft void .Fn zip_error_init "zip_error_t *error" .Ft void .Fn zip_error_init_with_code "zip_error_t *error" "int ze" .Sh DESCRIPTION The .Fn zip_error_init function initializes the zip_error pointed to by .Ar error . .Ar *error must be allocated before calling .Fn zip_error_init . .Pp The .Fn zip_error_init_with_code function does the same, but additionally sets the zip error code to .Ar ze and sets the system error code to the current .Xr errno 3 value, if appropriate. .\" TODO: describe when you would need to call this at all .Sh SEE ALSO .Xr libzip 3 , .Xr zip_error_fini 3 .Sh HISTORY .Fn zip_error_init and .Fn zip_error_init_with_code were added in libzip 1.0. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_error_set.html ================================================ ================================================ FILE: external/libzip/man/zip_error_set.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_error_set.mdoc -- set zip_error .\" Copyright (C) 2014-2021 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_ERROR_SET" "3" "December 5, 2022" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_error_set\fR \- fill in zip_error structure .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIvoid\fR .br .PD 0 .HP 4n \fBzip_error_set\fR(\fIzip_error_t\ *ze\fR, \fIint\ le\fR, \fIint\ se\fR); .PD .SH "DESCRIPTION" The \fBzip_error_set\fR() function sets the zip_error pointed to by \fIze\fR to the libzip error code \fIle\fR and the system error code \fIse\fR. .PP \fIze\fR must be allocated and initialized with zip_error_init(3) before calling \fBzip_error_set\fR(). .SH "SEE ALSO" libzip(3), zip_error_init(3), zip_error_set_from_source(3) .SH "HISTORY" \fBzip_error_set\fR() was added in libzip 1.0. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_error_set.mdoc ================================================ .\" zip_error_set.mdoc -- set zip_error .\" Copyright (C) 2014-2021 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd December 5, 2022 .Dt ZIP_ERROR_SET 3 .Os .Sh NAME .Nm zip_error_set .Nd fill in zip_error structure .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft void .Fn zip_error_set "zip_error_t *ze" "int le" "int se" .Sh DESCRIPTION The .Fn zip_error_set function sets the zip_error pointed to by .Ar ze to the libzip error code .Ar le and the system error code .Ar se . .Pp .Ar ze must be allocated and initialized with .Xr zip_error_init 3 before calling .Fn zip_error_set . .Sh SEE ALSO .Xr libzip 3 , .Xr zip_error_init 3 , .Xr zip_error_set_from_source 3 .Sh HISTORY .Fn zip_error_set was added in libzip 1.0. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_error_set_from_source.html ================================================ ================================================ FILE: external/libzip/man/zip_error_set_from_source.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_error_set_from_source.mdoc -- set zip_error from source .\" Copyright (C) 2022 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_ERROR_SET_FROM_SOURCE" "3" "December 5, 2022" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_error_set_from_source\fR \- fill in zip_error structure from source .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIvoid\fR .br .PD 0 .HP 4n \fBzip_error_set_from_source\fR(\fIzip_error_t\ *ze\fR, \fIzip_source_t\ *src\fR); .PD .SH "DESCRIPTION" The \fBzip_error_set_from_source\fR() function sets the zip_error pointed to by \fIze\fR to the error reported by \fIsrc\fR as returned by zip_error_source(3). \fIze\fR must be allocated and initialized with zip_error_init(3) before calling \fBzip_error_set_from_source\fR(). .SH "SEE ALSO" libzip(3), zip_error_init(3), zip_error_set(3) .SH "HISTORY" \fBzip_error_set_from_source\fR() was added in libzip 1.10. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_error_set_from_source.mdoc ================================================ .\" zip_error_set_from_source.mdoc -- set zip_error from source .\" Copyright (C) 2022 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd December 5, 2022 .Dt ZIP_ERROR_SET_FROM_SOURCE 3 .Os .Sh NAME .Nm zip_error_set_from_source .Nd fill in zip_error structure from source .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft void .Fn zip_error_set_from_source "zip_error_t *ze" "zip_source_t *src" .Sh DESCRIPTION The .Fn zip_error_set_from_source function sets the zip_error pointed to by .Ar ze to the error reported by .Ar src as returned by .Xr zip_error_source 3 . .Ar ze must be allocated and initialized with .Xr zip_error_init 3 before calling .Fn zip_error_set_from_source . .Sh SEE ALSO .Xr libzip 3 , .Xr zip_error_init 3 , .Xr zip_error_set 3 .Sh HISTORY .Fn zip_error_set_from_source was added in libzip 1.10. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_error_strerror.html ================================================ ================================================ FILE: external/libzip/man/zip_error_strerror.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_error_strerror.mdoc -- create human-readable version of zip_error .\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_ERROR_STRERROR" "3" "December 18, 2017" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_error_strerror\fR \- create human-readable string for zip_error .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIconst char *\fR .br .PD 0 .HP 4n \fBzip_error_strerror\fR(\fIzip_error_t\ *ze\fR); .PD .SH "DESCRIPTION" The \fBzip_error_strerror\fR() function returns an error message string corresponding to \fIze\fR like strerror(3). This string will stay valid until the next call to \fBzip_error_strerror\fR() or until zip_error_fini(3) is called. .SH "SEE ALSO" libzip(3), strerror(3), zip_error_fini(3) .SH "HISTORY" \fBzip_error_strerror\fR() was added in libzip 1.0. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_error_strerror.mdoc ================================================ .\" zip_error_strerror.mdoc -- create human-readable version of zip_error .\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd December 18, 2017 .Dt ZIP_ERROR_STRERROR 3 .Os .Sh NAME .Nm zip_error_strerror .Nd create human-readable string for zip_error .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft const char * .Fn zip_error_strerror "zip_error_t *ze" .Sh DESCRIPTION The .Fn zip_error_strerror function returns an error message string corresponding to .Ar ze like .Xr strerror 3 . This string will stay valid until the next call to .Fn zip_error_strerror or until .Xr zip_error_fini 3 is called. .Sh SEE ALSO .Xr libzip 3 , .Xr strerror 3 , .Xr zip_error_fini 3 .Sh HISTORY .Fn zip_error_strerror was added in libzip 1.0. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_error_system_type.html ================================================ ================================================ FILE: external/libzip/man/zip_error_system_type.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_error_system_type.mdoc -- return system type for error .\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_ERROR_SYSTEM_TYPE" "3" "December 18, 2017" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_error_system_type\fR \- return type of system error .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIint\fR .br .PD 0 .HP 4n \fBzip_error_system_type\fR(\fIconst\ zip_error_t\ *ze\fR); .PD .SH "DESCRIPTION" The \fBzip_error_system_type\fR() function returns the type of the system specific part for the zip_error \fIze\fR. Currently, the following system types are defined: .TP 13n \fRZIP_ET_NONE\fR System specific part of \fIze\fR is unused. .TP 13n \fRZIP_ET_SYS\fR System specific part of \fIze\fR is an errno(2). .TP 13n \fRZIP_ET_ZLIB\fR System specific part of \fIze\fR is a zlib(3) error. .SH "SEE ALSO" libzip(3), zip_error_code_system(3) .SH "HISTORY" \fBzip_error_system_type\fR() was added in libzip 1.0. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_error_system_type.mdoc ================================================ .\" zip_error_system_type.mdoc -- return system type for error .\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd December 18, 2017 .Dt ZIP_ERROR_SYSTEM_TYPE 3 .Os .Sh NAME .Nm zip_error_system_type .Nd return type of system error .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft int .Fn zip_error_system_type "const zip_error_t *ze" .Sh DESCRIPTION The .Fn zip_error_system_type function returns the type of the system specific part for the zip_error .Ar ze . Currently, the following system types are defined: .Bl -tag -width ZIP_ET_NONE .It Dv ZIP_ET_NONE System specific part of .Ar ze is unused. .It Dv ZIP_ET_SYS System specific part of .Ar ze is an .Xr errno 2 . .It Dv ZIP_ET_ZLIB System specific part of .Ar ze is a .Xr zlib 3 error. .El .Sh SEE ALSO .Xr libzip 3 , .Xr zip_error_code_system 3 .Sh HISTORY .Fn zip_error_system_type was added in libzip 1.0. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_error_to_data.html ================================================ ================================================ FILE: external/libzip/man/zip_error_to_data.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_error_to_data.mdoc -- create error data for ZIP_SOURCE_ERROR .\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_ERROR_TO_DATA" "3" "December 18, 2017" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_error_to_data\fR \- convert zip_error to return value suitable for ZIP_SOURCE_ERROR .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIzip_int64_t\fR .br .PD 0 .HP 4n \fBzip_error_to_data\fR(\fIconst\ zip_error_t\ *ze\fR, \fIvoid\ *data\fR, \fIzip_uint64_t\ len\fR); .PD .SH "DESCRIPTION" \fBzip_error_to_data\fR() function converts the zip_error \fIze\fR into data suitable as return value for \fRZIP_SOURCE_ERROR\fR. The data is written into the buffer \fIdata\fR of size \fIlen\fR. If the buffer is not large enough to hold 2 ints, an error is returned. .SH "RETURN VALUES" \fBzip_error_to_data\fR() returns 2*(sizeof int) on success, and \-1 on error. .SH "SEE ALSO" libzip(3), zip_source_function(3) .SH "HISTORY" \fBzip_error_to_data\fR() was added in libzip 1.0. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_error_to_data.mdoc ================================================ .\" zip_error_to_data.mdoc -- create error data for ZIP_SOURCE_ERROR .\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd December 18, 2017 .Dt ZIP_ERROR_TO_DATA 3 .Os .Sh NAME .Nm zip_error_to_data .Nd convert zip_error to return value suitable for ZIP_SOURCE_ERROR .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft zip_int64_t .Fn zip_error_to_data "const zip_error_t *ze" "void *data" "zip_uint64_t len" .Sh DESCRIPTION .Fn zip_error_to_data function converts the zip_error .Ar ze into data suitable as return value for .Dv ZIP_SOURCE_ERROR . The data is written into the buffer .Ar data of size .Ar len . If the buffer is not large enough to hold 2 ints, an error is returned. .Sh RETURN VALUES .Fn zip_error_to_data returns 2*(sizeof int) on success, and \-1 on error. .Sh SEE ALSO .Xr libzip 3 , .Xr zip_source_function 3 .Sh HISTORY .Fn zip_error_to_data was added in libzip 1.0. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_error_to_str.html ================================================ ================================================ FILE: external/libzip/man/zip_error_to_str.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_error_to_str.mdoc -- get string representation of zip error code .\" Copyright (C) 2003-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_ERROR_TO_STR" "3" "December 18, 2017" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_error_to_str\fR \- get string representation of zip error (obsolete interface) .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIint\fR .br .PD 0 .HP 4n \fBzip_error_to_str\fR(\fIchar\ *buf\fR, \fIzip_uint64_t\ len\fR, \fIint\ ze\fR, \fIint\ se\fR); .PD .SH "DESCRIPTION" The function \fBzip_error_to_str\fR() is deprecated; use zip_error_init_with_code(3) and zip_error_strerror(3) instead. .PP Replace .nf .sp .RS 6n char buf[BUFSIZE]; zip_error_to_str(buf, sizeof(buf), ze, se); printf("%s", buf); .RE .fi with .nf .sp .RS 6n zip_error_t error; zip_error_init_with_code(&error, ze); printf("%s", zip_error_strerror(&error)); zip_error_fini(&error); .RE .fi .SH "SEE ALSO" libzip(3), zip_error_init_with_code(3), zip_error_strerror(3) .SH "HISTORY" \fBzip_error_to_str\fR() was added in libzip 0.6. In libzip 0.10 the type of \fIlen\fR was changed from \fIsize_t\fR to \fIzip_uint64_t\fR. It was deprecated in libzip 1.0, use \fBzip_error_init_with_code\fR() and \fBzip_error_strerror\fR() instead. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_error_to_str.mdoc ================================================ .\" zip_error_to_str.mdoc -- get string representation of zip error code .\" Copyright (C) 2003-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd December 18, 2017 .Dt ZIP_ERROR_TO_STR 3 .Os .Sh NAME .Nm zip_error_to_str .Nd get string representation of zip error (obsolete interface) .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft int .Fn zip_error_to_str "char *buf" "zip_uint64_t len" "int ze" "int se" .Sh DESCRIPTION The function .Fn zip_error_to_str is deprecated; use .Xr zip_error_init_with_code 3 and .Xr zip_error_strerror 3 instead. .Pp Replace .Bd -literal -offset indent char buf[BUFSIZE]; zip_error_to_str(buf, sizeof(buf), ze, se); printf("%s", buf); .Ed with .Bd -literal -offset indent zip_error_t error; zip_error_init_with_code(&error, ze); printf("%s", zip_error_strerror(&error)); zip_error_fini(&error); .Ed .Sh SEE ALSO .Xr libzip 3 , .Xr zip_error_init_with_code 3 , .Xr zip_error_strerror 3 .Sh HISTORY .Fn zip_error_to_str was added in libzip 0.6. In libzip 0.10 the type of .Ar len was changed from .Vt size_t to .Vt zip_uint64_t . It was deprecated in libzip 1.0, use .Fn zip_error_init_with_code and .Fn zip_error_strerror instead. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_errors.html ================================================ ================================================ FILE: external/libzip/man/zip_errors.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_errors.mdoc -- list of all libzip error codes .\" Copyright (C) 1999-2024 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .\" This file was generated automatically by ./make_zip_errors.sh .\" from ../lib/zip.h; make changes there. .\" .TH "ZIP_ERRORS" "3" "March 15, 2024" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_errors\fR \- list of all libzip error codes .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .SH "DESCRIPTION" The following error codes are used by libzip: .TP 23n [\fRZIP_ER_CANCELLED\fR] Operation cancelled. .TP 23n [\fRZIP_ER_CHANGED\fR] Entry has been changed. .TP 23n [\fRZIP_ER_CLOSE\fR] Closing zip archive failed. .TP 23n [\fRZIP_ER_COMPNOTSUPP\fR] Compression method not supported. .TP 23n [\fRZIP_ER_COMPRESSED_DATA\fR] Compressed data invalid. .TP 23n [\fRZIP_ER_CRC\fR] CRC error. .TP 23n [\fRZIP_ER_DATA_LENGTH\fR] Unexpected length of data. .TP 23n [\fRZIP_ER_DELETED\fR] Entry has been deleted. .TP 23n [\fRZIP_ER_ENCRNOTSUPP\fR] Encryption method not supported. .TP 23n [\fRZIP_ER_EOF\fR] Premature end of file. .TP 23n [\fRZIP_ER_EXISTS\fR] File already exists. .TP 23n [\fRZIP_ER_INCONS\fR] Zip archive inconsistent. .TP 23n [\fRZIP_ER_INTERNAL\fR] Internal error. .TP 23n [\fRZIP_ER_INUSE\fR] Resource still in use. .TP 23n [\fRZIP_ER_INVAL\fR] Invalid argument. .TP 23n [\fRZIP_ER_MEMORY\fR] Malloc failure. .TP 23n [\fRZIP_ER_MULTIDISK\fR] Multi-disk zip archives not supported. .TP 23n [\fRZIP_ER_NOENT\fR] No such file. .TP 23n [\fRZIP_ER_NOPASSWD\fR] No password provided. .TP 23n [\fRZIP_ER_NOT_ALLOWED\fR] Not allowed in torrentzip. .TP 23n [\fRZIP_ER_NOZIP\fR] Not a zip archive. .TP 23n [\fRZIP_ER_OK\fR] No error. .TP 23n [\fRZIP_ER_OPEN\fR] Can't open file. .TP 23n [\fRZIP_ER_OPNOTSUPP\fR] Operation not supported. .TP 23n [\fRZIP_ER_RDONLY\fR] Read-only archive. .TP 23n [\fRZIP_ER_READ\fR] Read error. .TP 23n [\fRZIP_ER_REMOVE\fR] Can't remove file. .TP 23n [\fRZIP_ER_RENAME\fR] Renaming temporary file failed. .TP 23n [\fRZIP_ER_SEEK\fR] Seek error. .TP 23n [\fRZIP_ER_TELL\fR] Tell error. .TP 23n [\fRZIP_ER_TMPOPEN\fR] Failure to create temporary file. .TP 23n [\fRZIP_ER_TRUNCATED_ZIP\fR] .br Possibly truncated or corrupted zip archive. .TP 23n [\fRZIP_ER_WRITE\fR] Write error. .TP 23n [\fRZIP_ER_WRONGPASSWD\fR] Wrong password provided. .TP 23n [\fRZIP_ER_ZIPCLOSED\fR] Containing zip archive was closed. .TP 23n [\fRZIP_ER_ZLIB\fR] Zlib error. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_errors.mdoc ================================================ .\" zip_errors.mdoc -- list of all libzip error codes .\" Copyright (C) 1999-2024 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .\" This file was generated automatically by ./make_zip_errors.sh .\" from ../lib/zip.h; make changes there. .\" .Dd March 15, 2024 .Dt ZIP_ERRORS 3 .Os .Sh NAME .Nm zip_errors .Nd list of all libzip error codes .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Sh DESCRIPTION The following error codes are used by libzip: .Bl -tag -width XZIPXERXCOMPNOTSUPPXX .It Bq Er ZIP_ER_CANCELLED Operation cancelled. .It Bq Er ZIP_ER_CHANGED Entry has been changed. .It Bq Er ZIP_ER_CLOSE Closing zip archive failed. .It Bq Er ZIP_ER_COMPNOTSUPP Compression method not supported. .It Bq Er ZIP_ER_COMPRESSED_DATA Compressed data invalid. .It Bq Er ZIP_ER_CRC CRC error. .It Bq Er ZIP_ER_DATA_LENGTH Unexpected length of data. .It Bq Er ZIP_ER_DELETED Entry has been deleted. .It Bq Er ZIP_ER_ENCRNOTSUPP Encryption method not supported. .It Bq Er ZIP_ER_EOF Premature end of file. .It Bq Er ZIP_ER_EXISTS File already exists. .It Bq Er ZIP_ER_INCONS Zip archive inconsistent. .It Bq Er ZIP_ER_INTERNAL Internal error. .It Bq Er ZIP_ER_INUSE Resource still in use. .It Bq Er ZIP_ER_INVAL Invalid argument. .It Bq Er ZIP_ER_MEMORY Malloc failure. .It Bq Er ZIP_ER_MULTIDISK Multi-disk zip archives not supported. .It Bq Er ZIP_ER_NOENT No such file. .It Bq Er ZIP_ER_NOPASSWD No password provided. .It Bq Er ZIP_ER_NOT_ALLOWED Not allowed in torrentzip. .It Bq Er ZIP_ER_NOZIP Not a zip archive. .It Bq Er ZIP_ER_OK No error. .It Bq Er ZIP_ER_OPEN Can't open file. .It Bq Er ZIP_ER_OPNOTSUPP Operation not supported. .It Bq Er ZIP_ER_RDONLY Read-only archive. .It Bq Er ZIP_ER_READ Read error. .It Bq Er ZIP_ER_REMOVE Can't remove file. .It Bq Er ZIP_ER_RENAME Renaming temporary file failed. .It Bq Er ZIP_ER_SEEK Seek error. .It Bq Er ZIP_ER_TELL Tell error. .It Bq Er ZIP_ER_TMPOPEN Failure to create temporary file. .It Bq Er ZIP_ER_TRUNCATED_ZIP Possibly truncated or corrupted zip archive. .It Bq Er ZIP_ER_WRITE Write error. .It Bq Er ZIP_ER_WRONGPASSWD Wrong password provided. .It Bq Er ZIP_ER_ZIPCLOSED Containing zip archive was closed. .It Bq Er ZIP_ER_ZLIB Zlib error. .El .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_fclose.html ================================================ ================================================ FILE: external/libzip/man/zip_fclose.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_fclose.mdoc -- close file in zip archive .\" Copyright (C) 2003-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_FCLOSE" "3" "December 18, 2017" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_fclose\fR \- close file in zip archive .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIint\fR .br .PD 0 .HP 4n \fBzip_fclose\fR(\fIzip_file_t\ *file\fR); .PD .SH "DESCRIPTION" The \fBzip_fclose\fR() function closes \fIfile\fR and frees the memory allocated for it. .SH "RETURN VALUES" Upon successful completion 0 is returned. Otherwise, the error code is returned. .SH "SEE ALSO" libzip(3), zip_fopen(3), zip_fread(3), zip_fseek(3) .SH "HISTORY" \fBzip_fclose\fR() was added in libzip 0.6. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_fclose.mdoc ================================================ .\" zip_fclose.mdoc -- close file in zip archive .\" Copyright (C) 2003-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd December 18, 2017 .Dt ZIP_FCLOSE 3 .Os .Sh NAME .Nm zip_fclose .Nd close file in zip archive .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft int .Fn zip_fclose "zip_file_t *file" .Sh DESCRIPTION The .Fn zip_fclose function closes .Ar file and frees the memory allocated for it. .Sh RETURN VALUES Upon successful completion 0 is returned. Otherwise, the error code is returned. .Sh SEE ALSO .Xr libzip 3 , .Xr zip_fopen 3 , .Xr zip_fread 3 , .Xr zip_fseek 3 .Sh HISTORY .Fn zip_fclose was added in libzip 0.6. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_fdopen.html ================================================ ================================================ FILE: external/libzip/man/zip_fdopen.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_fdopen.mdoc -- open zip archive using existing file descriptor .\" Copyright (C) 2009-2021 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_FDOPEN" "3" "September 23, 2022" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_fdopen\fR \- open zip archive using open file descriptor .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIzip_t *\fR .br .PD 0 .HP 4n \fBzip_fdopen\fR(\fIint\ fd\fR, \fIint\ flags\fR, \fIint\ *errorp\fR); .PD .SH "DESCRIPTION" The zip archive specified by the open file descriptor \fIfd\fR is opened and a pointer to a \fIstruct zip\fR, used to manipulate the archive, is returned. In contrast to zip_open(3), using \fBzip_fdopen\fR the archive can only be opened in read-only mode. The \fIfd\fR argument may not be used any longer after calling \fBzip_fdopen\fR. The \fIflags\fR are specified by \fIor\fR'ing the following values, or 0 for none of them. .RS 6n .TP 15n \fRZIP_CHECKCONS\fR Perform additional stricter consistency checks on the archive, and error if they fail. .RE .PP If an error occurs and \fIerrorp\fR is non-\fRNULL\fR, it will be set to the corresponding error code. .SH "RETURN VALUES" Upon successful completion \fBzip_fdopen\fR() returns a \fIstruct zip\fR pointer, and \fIfd\fR should not be used any longer, nor passed to close(2). Otherwise, \fRNULL\fR is returned and \fI*errorp\fR is set to indicate the error. In the error case, \fIfd\fR remains unchanged. .SH "ERRORS" The file specified by \fIfd\fR is prepared for use by libzip(3) unless: .TP 19n [\fRZIP_ER_INCONS\fR] Inconsistencies were found in the file specified by \fIpath\fR. This error is often caused by specifying \fRZIP_CHECKCONS\fR but can also happen without it. .TP 19n [\fRZIP_ER_INVAL\fR] The \fIflags\fR argument is invalid. Not all zip_open(3) flags are allowed for \fBzip_fdopen\fR, see \fIDESCRIPTION\fR. .TP 19n [\fRZIP_ER_MEMORY\fR] Required memory could not be allocated. .TP 19n [\fRZIP_ER_NOZIP\fR] The file specified by \fIfd\fR is not a zip archive. .TP 19n [\fRZIP_ER_OPEN\fR] The file specified by \fIfd\fR could not be prepared for use by libzip(3). .TP 19n [\fRZIP_ER_OPNOTSUPP\fR] .br This functionality has been disabled at compile time. .TP 19n [\fRZIP_ER_READ\fR] A read error occurred; see \fIerrno\fR for details. .TP 19n [\fRZIP_ER_SEEK\fR] The file specified by \fIfd\fR does not allow seeks. .SH "SEE ALSO" libzip(3), zip_close(3), zip_error_strerror(3), zip_open(3) .SH "HISTORY" \fBzip_fdopen\fR() was added in libzip 1.0. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_fdopen.mdoc ================================================ .\" zip_fdopen.mdoc -- open zip archive using existing file descriptor .\" Copyright (C) 2009-2021 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd September 23, 2022 .Dt ZIP_FDOPEN 3 .Os .Sh NAME .Nm zip_fdopen .Nd open zip archive using open file descriptor .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft zip_t * .Fn zip_fdopen "int fd" "int flags" "int *errorp" .Sh DESCRIPTION The zip archive specified by the open file descriptor .Ar fd is opened and a pointer to a .Ft struct zip , used to manipulate the archive, is returned. In contrast to .Xr zip_open 3 , using .Nm zip_fdopen the archive can only be opened in read-only mode. The .Ar fd argument may not be used any longer after calling .Nm zip_fdopen . The .Fa flags are specified by .Em or Ns No 'ing the following values, or 0 for none of them. .Bl -tag -offset indent -width ZIP_CHECKCONS .It Dv ZIP_CHECKCONS Perform additional stricter consistency checks on the archive, and error if they fail. .El .Pp If an error occurs and .Ar errorp is .No non- Ns Dv NULL , it will be set to the corresponding error code. .Sh RETURN VALUES Upon successful completion .Fn zip_fdopen returns a .Ft struct zip pointer, and .Ar fd should not be used any longer, nor passed to .Xr close 2 . Otherwise, .Dv NULL is returned and .Ar *errorp is set to indicate the error. In the error case, .Ar fd remains unchanged. .Sh ERRORS The file specified by .Ar fd is prepared for use by .Xr libzip 3 unless: .Bl -tag -width Er .It Bq Er ZIP_ER_INCONS Inconsistencies were found in the file specified by .Ar path . This error is often caused by specifying .Dv ZIP_CHECKCONS but can also happen without it. .It Bq Er ZIP_ER_INVAL The .Ar flags argument is invalid. Not all .Xr zip_open 3 flags are allowed for .Nm zip_fdopen , see .Sx DESCRIPTION . .It Bq Er ZIP_ER_MEMORY Required memory could not be allocated. .It Bq Er ZIP_ER_NOZIP The file specified by .Ar fd is not a zip archive. .It Bq Er ZIP_ER_OPEN The file specified by .Ar fd could not be prepared for use by .Xr libzip 3 . .It Bq Er ZIP_ER_OPNOTSUPP This functionality has been disabled at compile time. .It Bq Er ZIP_ER_READ A read error occurred; see .Va errno for details. .It Bq Er ZIP_ER_SEEK The file specified by .Ar fd does not allow seeks. .El .Sh SEE ALSO .Xr libzip 3 , .Xr zip_close 3 , .Xr zip_error_strerror 3 , .Xr zip_open 3 .Sh HISTORY .Fn zip_fdopen was added in libzip 1.0. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_file.html ================================================ ================================================ FILE: external/libzip/man/zip_file.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_file.mdoc -- description of zip_file_t .\" Copyright (C) 2025 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_FILE" "5" "May 5, 2025" "NiH" "File Formats Manual" .nh .if n .ad l .SH "NAME" \fBzip_file\fR \- file in archive .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIzip_file_t *file\fR; .SH "DESCRIPTION" A \fBzip_file\fR represents a file inside an archive, opened for reading. It is created with zip_fopen(3), zip_fopen_index(3), zip_fopen_encrypted(3), or zip_fopen_index_encrypted(3). .PP Data is accessed with zip_fread(3), zip_file_is_seekable(3), zip_ftell(3), or zip_fseek(3). .PP It is closed with zip_fclose(3). .PP If the containing \fIzip_t\fR is closed, all further uses of the \fIzip_file_t\fR return an error. It is a convenience wrapper around a \fIzip_source_t\fR as created by zip_source_zip(3). .SH "SEE ALSO" zip_fclose(3), zip_file_is_seekable(3), zip_fopen(3), zip_fopen_encrypted(3), zip_fopen_index(3), zip_fopen_index_encrypted(3,) zip_fread(3), zip_fseek(3), zip_ftell(3), zip_source_zip(3), .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_file.mdoc ================================================ .\" zip_file.mdoc -- description of zip_file_t .\" Copyright (C) 2025 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd May 5, 2025 .Dt ZIP_FILE 5 .Os .Sh NAME .Nm zip_file .Nd file in archive .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Vt zip_file_t *file ; .Sh DESCRIPTION A .Nm represents a file inside an archive, opened for reading. It is created with .Xr zip_fopen 3 , .Xr zip_fopen_index 3 , .Xr zip_fopen_encrypted 3 , or .Xr zip_fopen_index_encrypted 3 . .Pp Data is accessed with .Xr zip_fread 3 , .Xr zip_file_is_seekable 3 , .Xr zip_ftell 3 , or .Xr zip_fseek 3 . .Pp It is closed with .Xr zip_fclose 3 . .Pp If the containing .Vt zip_t is closed, all further uses of the .Vt zip_file_t return an error. It is a convenience wrapper around a .Vt zip_source_t as created by .Xr zip_source_zip 3 . .Sh SEE ALSO .Xr zip_fclose 3 , .Xr zip_file_is_seekable 3 , .Xr zip_fopen 3 , .Xr zip_fopen_encrypted 3 , .Xr zip_fopen_index 3 , .Xr zip_fopen_index_encrypted 3, .Xr zip_fread 3 , .Xr zip_fseek 3 , .Xr zip_ftell 3 , .Xr zip_source_zip 3 , .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_file_add.html ================================================ ================================================ FILE: external/libzip/man/zip_file_add.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_file_add.mdoc -- add files to zip archive .\" Copyright (C) 2004-2021 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_FILE_ADD" "3" "March 18, 2024" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_file_add\fR, \fBzip_file_replace\fR \- add file to zip archive or replace file in zip archive .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIzip_int64_t\fR .br .PD 0 .HP 4n \fBzip_file_add\fR(\fIzip_t\ *archive\fR, \fIconst\ char\ *name\fR, \fIzip_source_t\ *source\fR, \fIzip_flags_t\ flags\fR); .PD .PP \fIint\fR .br .PD 0 .HP 4n \fBzip_file_replace\fR(\fIzip_t\ *archive\fR, \fIzip_uint64_t\ index\fR, \fIzip_source_t\ *source\fR, \fIzip_flags_t\ flags\fR); .PD .SH "DESCRIPTION" The function \fBzip_file_add\fR() adds a file to a zip archive, while \fBzip_file_replace\fR() replaces an existing file in a zip archive. The argument \fIarchive\fR specifies the zip archive to which the file should be added. \fIname\fR is the file's name in the zip archive (for \fBzip_file_add\fR()), while \fIindex\fR specifies which file should be replaced (for \fBzip_file_replace\fR()). The \fIflags\fR argument can be any combination of \fRZIP_FL_OVERWRITE\fR with one of \fRZIP_FL_ENC_*\fR: .TP 22n \fRZIP_FL_OVERWRITE\fR Overwrite any existing file of the same name. For \fBzip_file_add\fR only. .TP 22n \fRZIP_FL_ENC_GUESS\fR Guess encoding of \fIname\fR (default). (Only CP-437 and UTF-8 are recognized.) .TP 22n \fRZIP_FL_ENC_UTF_8\fR Interpret \fIname\fR as UTF-8. .TP 22n \fRZIP_FL_ENC_CP437\fR Interpret \fIname\fR as code page 437 (CP-437). .PD 0 .PP The data is obtained from the \fIsource\fR argument, see zip_source(5). .PD .PP \fINOTE\fR: zip_source_free(3) should not be called on a \fIsource\fR after it was used successfully in a \fBzip_file_add\fR or \fBzip_file_replace\fR call. .PP Please also note that when using \fBzip_replace\fR, the target file's extra field information will be deleted since this usually is dependent on the file contents. If you want to keep them, query them beforehand with zip_file_extra_field_get(3) and restore them after \fBzip_replace\fR with zip_file_extra_field_set(3). .SH "RETURN VALUES" Upon successful completion, \fBzip_file_add\fR() returns the index of the new file in the archive, and \fBzip_file_replace\fR() returns 0. Otherwise, \-1 is returned and the error code in \fIarchive\fR is set to indicate the error. .SH "EXAMPLES" .nf .RS 6n zip_source_t *s; const char buf[]="teststring"; if ((s=zip_source_buffer(archive, buf, sizeof(buf), 0)) == NULL || zip_file_add(archive, name, s, ZIP_FL_ENC_UTF_8) < 0) { zip_source_free(s); printf("error adding file: %s\en", zip_strerror(archive)); } .RE .fi .SH "ERRORS" \fBzip_file_add\fR() and \fBzip_file_replace\fR() fail if: .TP 19n [\fRZIP_ER_EXISTS\fR] There is already a file called \fIname\fR in the archive. (Only applies to \fBzip_file_add\fR(), and only if \fRZIP_FL_OVERWRITE\fR is not provided). .TP 19n [\fRZIP_ER_INVAL\fR] \fIsource\fR or \fIname\fR are \fRNULL\fR, or \fIindex\fR is invalid. .TP 19n [\fRZIP_ER_MEMORY\fR] Required memory could not be allocated. .TP 19n [\fRZIP_ER_RDONLY\fR] Archive was opened in read-only mode. .SH "SEE ALSO" libzip(3), zip_source(5) .SH "HISTORY" \fBzip_file_add\fR() and \fBzip_file_replace\fR() were added in libzip 0.11. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_file_add.mdoc ================================================ .\" zip_file_add.mdoc -- add files to zip archive .\" Copyright (C) 2004-2021 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd March 18, 2024 .Dt ZIP_FILE_ADD 3 .Os .Sh NAME .Nm zip_file_add , .Nm zip_file_replace .Nd add file to zip archive or replace file in zip archive .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft zip_int64_t .Fn zip_file_add "zip_t *archive" "const char *name" "zip_source_t *source" "zip_flags_t flags" .Ft int .Fn zip_file_replace "zip_t *archive" "zip_uint64_t index" "zip_source_t *source" "zip_flags_t flags" .Sh DESCRIPTION The function .Fn zip_file_add adds a file to a zip archive, while .Fn zip_file_replace replaces an existing file in a zip archive. The argument .Ar archive specifies the zip archive to which the file should be added. .Ar name is the file's name in the zip archive (for .Fn zip_file_add ) , while .Ar index specifies which file should be replaced (for .Fn zip_file_replace ) . The .Ar flags argument can be any combination of .Dv ZIP_FL_OVERWRITE with one of .Dv ZIP_FL_ENC_* : .Bl -tag -width XZIPXFLXENCXSTRICTXX .It Dv ZIP_FL_OVERWRITE Overwrite any existing file of the same name. For .Nm zip_file_add only. .It Dv ZIP_FL_ENC_GUESS Guess encoding of .Ar name (default). (Only CP-437 and UTF-8 are recognized.) .It Dv ZIP_FL_ENC_UTF_8 Interpret .Ar name as UTF-8. .It Dv ZIP_FL_ENC_CP437 Interpret .Ar name as code page 437 (CP-437). .El The data is obtained from the .Ar source argument, see .Xr zip_source 5 . .Pp .Em NOTE : .Xr zip_source_free 3 should not be called on a .Ar source after it was used successfully in a .Nm zip_file_add or .Nm zip_file_replace call. .Pp Please also note that when using .Nm zip_replace , the target file's extra field information will be deleted since this usually is dependent on the file contents. If you want to keep them, query them beforehand with .Xr zip_file_extra_field_get 3 and restore them after .Nm zip_replace with .Xr zip_file_extra_field_set 3 . .Sh RETURN VALUES Upon successful completion, .Fn zip_file_add returns the index of the new file in the archive, and .Fn zip_file_replace returns 0. Otherwise, \-1 is returned and the error code in .Ar archive is set to indicate the error. .Sh EXAMPLES .Bd -literal -offset indent zip_source_t *s; const char buf[]="teststring"; if ((s=zip_source_buffer(archive, buf, sizeof(buf), 0)) == NULL || zip_file_add(archive, name, s, ZIP_FL_ENC_UTF_8) < 0) { zip_source_free(s); printf("error adding file: %s\en", zip_strerror(archive)); } .Ed .Sh ERRORS .Fn zip_file_add and .Fn zip_file_replace fail if: .Bl -tag -width Er .It Bq Er ZIP_ER_EXISTS There is already a file called .Ar name in the archive. (Only applies to .Fn zip_file_add , and only if .Dv ZIP_FL_OVERWRITE is not provided). .It Bq Er ZIP_ER_INVAL .Ar source or .Ar name are .Dv NULL , or .Ar index is invalid. .It Bq Er ZIP_ER_MEMORY Required memory could not be allocated. .It Bq Er ZIP_ER_RDONLY Archive was opened in read-only mode. .El .Sh SEE ALSO .Xr libzip 3 , .Xr zip_source 5 .Sh HISTORY .Fn zip_file_add and .Fn zip_file_replace were added in libzip 0.11. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_file_attributes_init.html ================================================ ================================================ FILE: external/libzip/man/zip_file_attributes_init.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_file_attributes_init.mdoc -- initialize attributes structure .\" Copyright (C) 2020 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP files. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_FILE_ATTRIBUTES_INIT" "3" "April 17, 2020" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_file_attributes_init\fR \- initialize zip file attributes structure .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIvoid\fR .br .PD 0 .HP 4n \fBzip_file_attributes_init\fR(\fIzip_file_attributes_t\ *attributes\fR); .PD .SH "DESCRIPTION" The \fBzip_file_attributes_init\fR() initializes a \fIzip_file_attributes_t\fR structure with default values. It must be called before modifying such a structure for the first time. .SH "SEE ALSO" libzip(3), zip_source_function(3) .SH "HISTORY" \fBzip_file_attributes_init\fR() was added in libzip 1.7.0. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_file_attributes_init.mdoc ================================================ .\" zip_file_attributes_init.mdoc -- initialize attributes structure .\" Copyright (C) 2020 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP files. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd April 17, 2020 .Dt ZIP_FILE_ATTRIBUTES_INIT 3 .Os .Sh NAME .Nm zip_file_attributes_init .Nd initialize zip file attributes structure .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft void .Fn zip_file_attributes_init "zip_file_attributes_t *attributes" .Sh DESCRIPTION The .Fn zip_file_attributes_init initializes a .Vt zip_file_attributes_t structure with default values. It must be called before modifying such a structure for the first time. .Sh SEE ALSO .Xr libzip 3 , .Xr zip_source_function 3 .Sh HISTORY .Fn zip_file_attributes_init was added in libzip 1.7.0. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_file_extra_field_delete.html ================================================ ================================================ FILE: external/libzip/man/zip_file_extra_field_delete.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_file_extra_field_delete.mdoc -- delete extra field for file in zip .\" Copyright (C) 2012-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP files. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_FILE_EXTRA_FIELD_DELETE" "3" "December 18, 2017" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_file_extra_field_delete\fR, \fBzip_file_extra_field_delete_by_id\fR \- delete extra field for file in zip .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIint\fR .br .PD 0 .HP 4n \fBzip_file_extra_field_delete\fR(\fIzip_t\ *archive\fR, \fIzip_uint64_t\ index\fR, \fIzip_uint16_t\ extra_field_index\fR, \fIzip_flags_t\ flags\fR); .PD .PP \fIint\fR .br .PD 0 .HP 4n \fBzip_file_extra_field_delete_by_id\fR(\fIzip_t\ *archive\fR, \fIzip_uint64_t\ index\fR, \fIzip_uint16_t\ extra_field_id\fR, \fIzip_uint16_t\ extra_field_index\fR, \fIzip_flags_t\ flags\fR); .PD .SH "DESCRIPTION" The \fBzip_file_extra_field_delete\fR() function deletes the extra field with index \fIextra_field_index\fR for the file at position \fIindex\fR in the zip archive. .PP If \fIextra_field_index\fR is \fRZIP_EXTRA_FIELD_ALL\fR, then all extra fields will be deleted. .PP The following \fIflags\fR are supported: .RS 6n .TP 18n \fRZIP_FL_CENTRAL\fR Delete extra fields from the archive's central directory. .TP 18n \fRZIP_FL_LOCAL\fR Delete extra fields from the local file headers. .RE .PP The \fBzip_file_extra_field_delete_by_id\fR() function deletes the extra field with ID (two-byte signature) \fIextra_field_id\fR and index \fIextra_field_index\fR (in other words, the \fIextra_field_index\fR'th extra field with ID \fIextra_field_id\fR) The other arguments are the same as for \fBzip_file_extra_field_delete\fR() (\fRZIP_EXTRA_FIELD_ALL\fR will delete all extra fields of the specified ID). .PP Please note that due to the library design, the index of an extra field may be different between central directory and local file headers. For this reason, it is not allowed to specify both \fRZIP_FL_CENTRAL\fR and \fRZIP_FL_LOCAL\fR in \fIflags\fR, except when deleting all extra fields (i.e., \fIextra_field_index\fR being \fRZIP_EXTRA_FIELD_ALL\fR). .SH "RETURN VALUES" Upon successful completion 0 is returned. Otherwise, \-1 is returned and the error code in \fIarchive\fR is set to indicate the error. .SH "ERRORS" \fBzip_file_extra_field_delete\fR() and \fBzip_file_extra_field_delete_by_id\fR() fail if: .TP 19n [\fRZIP_ER_NOENT\fR] \fIindex\fR is not a valid file index in \fIarchive\fR. .SH "SEE ALSO" libzip(3), zip_file_extra_field_get(3), zip_file_extra_field_set(3), zip_file_extra_fields_count(3) .SH "HISTORY" \fBzip_file_extra_field_delete\fR() and \fBzip_file_extra_field_delete_by_id\fR() were added in libzip 0.11. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_file_extra_field_delete.mdoc ================================================ .\" zip_file_extra_field_delete.mdoc -- delete extra field for file in zip .\" Copyright (C) 2012-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP files. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd December 18, 2017 .Dt ZIP_FILE_EXTRA_FIELD_DELETE 3 .Os .Sh NAME .Nm zip_file_extra_field_delete , .Nm zip_file_extra_field_delete_by_id .Nd delete extra field for file in zip .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft int .Fn zip_file_extra_field_delete "zip_t *archive" "zip_uint64_t index" "zip_uint16_t extra_field_index" "zip_flags_t flags" .Ft int .Fn zip_file_extra_field_delete_by_id "zip_t *archive" "zip_uint64_t index" "zip_uint16_t extra_field_id" "zip_uint16_t extra_field_index" "zip_flags_t flags" .Sh DESCRIPTION The .Fn zip_file_extra_field_delete function deletes the extra field with index .Ar extra_field_index for the file at position .Ar index in the zip archive. .Pp If .Ar extra_field_index is .Dv ZIP_EXTRA_FIELD_ALL , then all extra fields will be deleted. .Pp The following .Ar flags are supported: .Bl -tag -width ZIP_FL_CENTRALXX -offset indent .It Dv ZIP_FL_CENTRAL Delete extra fields from the archive's central directory. .It Dv ZIP_FL_LOCAL Delete extra fields from the local file headers. .El .Pp The .Fn zip_file_extra_field_delete_by_id function deletes the extra field with ID (two-byte signature) .Ar extra_field_id and index .Ar extra_field_index (in other words, the .Ar extra_field_index Ns No 'th extra field with ID .Ar extra_field_id ) The other arguments are the same as for .Fn zip_file_extra_field_delete .Dv ( ZIP_EXTRA_FIELD_ALL will delete all extra fields of the specified ID). .Pp Please note that due to the library design, the index of an extra field may be different between central directory and local file headers. For this reason, it is not allowed to specify both .Dv ZIP_FL_CENTRAL and .Dv ZIP_FL_LOCAL in .Ar flags , except when deleting all extra fields (i.e., .Ar extra_field_index being .Dv ZIP_EXTRA_FIELD_ALL ) . .Sh RETURN VALUES Upon successful completion 0 is returned. Otherwise, \-1 is returned and the error code in .Ar archive is set to indicate the error. .Sh ERRORS .Fn zip_file_extra_field_delete and .Fn zip_file_extra_field_delete_by_id fail if: .Bl -tag -width Er .It Bq Er ZIP_ER_NOENT .Ar index is not a valid file index in .Ar archive . .El .Sh SEE ALSO .Xr libzip 3 , .Xr zip_file_extra_field_get 3 , .Xr zip_file_extra_field_set 3 , .Xr zip_file_extra_fields_count 3 .Sh HISTORY .Fn zip_file_extra_field_delete and .Fn zip_file_extra_field_delete_by_id were added in libzip 0.11. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_file_extra_field_get.html ================================================ ================================================ FILE: external/libzip/man/zip_file_extra_field_get.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_file_extra_field_get.mdoc -- get extra field for file in zip .\" Copyright (C) 2012-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP files. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_FILE_EXTRA_FIELD_GET" "3" "December 18, 2017" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_file_extra_field_get\fR, \fBzip_file_extra_field_get_by_id\fR \- get extra field for file in zip .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIconst zip_uint8_t *\fR .br .PD 0 .HP 4n \fBzip_file_extra_field_get\fR(\fIzip_t\ *archive\fR, \fIzip_uint64_t\ index\fR, \fIzip_uint16_t\ extra_field_index\fR, \fIzip_uint16_t\ *idp\fR, \fIzip_uint16_t\ *lenp\fR, \fIzip_flags_t\ flags\fR); .PD .PP \fIconst zip_uint8_t *\fR .br .PD 0 .HP 4n \fBzip_file_extra_field_get_by_id\fR(\fIzip_t\ *archive\fR, \fIzip_uint64_t\ index\fR, \fIzip_uint16_t\ extra_field_id\fR, \fIzip_uint16_t\ extra_field_index\fR, \fIzip_uint16_t\ *lenp\fR, \fIzip_flags_t\ flags\fR); .PD .SH "DESCRIPTION" The \fBzip_file_extra_field_get\fR() function returns the extra field with index \fIextra_field_index\fR for the file at position \fIindex\fR in the zip archive. This pointer should not be modified or free(3)'d, and becomes invalid when \fIarchive\fR is closed. If \fIidp\fR is not \fRNULL\fR, the integer to which it points will be set to the ID (two-byte signature) of the selected extra field. If \fIlenp\fR is not \fRNULL\fR, the integer to which it points will be set to the length of the extra field. Generally speaking, \fIlenp\fR and \fIidp\fR should be passed since only the extra field data is returned (i.e., neither the ID nor the length, if the \fIidp\fR and \fIlenp\fR arguments are not provided). .PP The following \fIflags\fR are supported: .RS 6n .TP 20n \fRZIP_FL_CENTRAL\fR Return extra fields from the archive's central directory. .TP 20n \fRZIP_FL_LOCAL\fR Return extra fields from the local file headers. .TP 20n \fRZIP_FL_UNCHANGED\fR Return the original unchanged extra fields, ignoring any changes made. .RE .PP The \fBzip_file_extra_field_get_by_id\fR() function returns the extra field with ID (two-byte signature) \fIextra_field_id\fR and index \fIextra_field_index\fR (in other words, the \fIextra_field_index\fR'th extra field with ID \fIextra_field_id\fR) The other arguments are the same as for \fBzip_file_extra_field_get\fR(). .SH "RETURN VALUES" Upon successful completion, a pointer to an extra field is returned, or \fRNULL\fR if there is no extra field with that \fIextra_field_index\fR for the file with index \fIindex\fR. In case of an error, \fRNULL\fR is returned and the error code in \fIarchive\fR is set to indicate the error. .SH "ERRORS" \fBzip_file_extra_field_get\fR() and \fBzip_file_extra_field_get_by_id\fR() fail if: .TP 19n [\fRZIP_ER_NOENT\fR] \fIindex\fR is not a valid file index in \fIarchive\fR, or \fIextra_field_index\fR is not a valid extra file index (for ID \fIextra_field_id\fR). .SH "SEE ALSO" libzip(3), zip_file_extra_field_delete(3), zip_file_extra_field_set(3), zip_file_extra_fields_count(3) .SH "HISTORY" \fBzip_file_extra_field_get\fR() and \fBzip_file_extra_field_get_by_id\fR() were added in libzip 0.11. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> .SH "CAVEATS" Please note that the extra field IDs 0x0001 (ZIP64 extension), 0x6375 (Infozip UTF-8 comment), and 0x7075 (Infozip UTF-8 file name) can not be read using \fBzip_file_extra_field_get\fR() since they are used by libzip(3) internally. ================================================ FILE: external/libzip/man/zip_file_extra_field_get.mdoc ================================================ .\" zip_file_extra_field_get.mdoc -- get extra field for file in zip .\" Copyright (C) 2012-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP files. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd December 18, 2017 .Dt ZIP_FILE_EXTRA_FIELD_GET 3 .Os .Sh NAME .Nm zip_file_extra_field_get , .Nm zip_file_extra_field_get_by_id .Nd get extra field for file in zip .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft const zip_uint8_t * .Fn zip_file_extra_field_get "zip_t *archive" "zip_uint64_t index" "zip_uint16_t extra_field_index" "zip_uint16_t *idp" "zip_uint16_t *lenp" "zip_flags_t flags" .Ft const zip_uint8_t * .Fn zip_file_extra_field_get_by_id "zip_t *archive" "zip_uint64_t index" "zip_uint16_t extra_field_id" "zip_uint16_t extra_field_index" "zip_uint16_t *lenp" "zip_flags_t flags" .Sh DESCRIPTION The .Fn zip_file_extra_field_get function returns the extra field with index .Ar extra_field_index for the file at position .Ar index in the zip archive. This pointer should not be modified or .Xr free 3 Ap d , and becomes invalid when .Ar archive is closed. If .Ar idp is not .Dv NULL , the integer to which it points will be set to the ID (two-byte signature) of the selected extra field. If .Ar lenp is not .Dv NULL , the integer to which it points will be set to the length of the extra field. Generally speaking, .Ar lenp and .Ar idp should be passed since only the extra field data is returned (i.e., neither the ID nor the length, if the .Ar idp and .Ar lenp arguments are not provided). .Pp The following .Ar flags are supported: .Bl -tag -width ZIP_FL_UNCHANGEDXX -offset indent .It Dv ZIP_FL_CENTRAL Return extra fields from the archive's central directory. .It Dv ZIP_FL_LOCAL Return extra fields from the local file headers. .It Dv ZIP_FL_UNCHANGED Return the original unchanged extra fields, ignoring any changes made. .El .Pp The .Fn zip_file_extra_field_get_by_id function returns the extra field with ID (two-byte signature) .Ar extra_field_id and index .Ar extra_field_index (in other words, the .Ar extra_field_index Ns No 'th extra field with ID .Ar extra_field_id ) The other arguments are the same as for .Fn zip_file_extra_field_get . .Sh RETURN VALUES Upon successful completion, a pointer to an extra field is returned, or .Dv NULL if there is no extra field with that .Ar extra_field_index for the file with index .Ar index . In case of an error, .Dv NULL is returned and the error code in .Ar archive is set to indicate the error. .Sh ERRORS .Fn zip_file_extra_field_get and .Fn zip_file_extra_field_get_by_id fail if: .Bl -tag -width Er .It Bq Er ZIP_ER_NOENT .Ar index is not a valid file index in .Ar archive , or .Ar extra_field_index is not a valid extra file index (for ID .Ar extra_field_id ) . .El .Sh SEE ALSO .Xr libzip 3 , .Xr zip_file_extra_field_delete 3 , .Xr zip_file_extra_field_set 3 , .Xr zip_file_extra_fields_count 3 .Sh HISTORY .Fn zip_file_extra_field_get and .Fn zip_file_extra_field_get_by_id were added in libzip 0.11. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at .Sh CAVEATS Please note that the extra field IDs 0x0001 (ZIP64 extension), 0x6375 (Infozip UTF-8 comment), and 0x7075 (Infozip UTF-8 file name) can not be read using .Fn zip_file_extra_field_get since they are used by .Xr libzip 3 internally. ================================================ FILE: external/libzip/man/zip_file_extra_field_set.html ================================================ ================================================ FILE: external/libzip/man/zip_file_extra_field_set.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_file_extra_field_set.mdoc -- set extra field for file in zip .\" Copyright (C) 2012-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP files. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_FILE_EXTRA_FIELD_SET" "3" "December 18, 2017" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_file_extra_field_set\fR \- set extra field for file in zip .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIint\fR .br .PD 0 .HP 4n \fBzip_file_extra_field_set\fR(\fIzip_t\ *archive\fR, \fIzip_uint64_t\ index\fR, \fIzip_uint16_t\ extra_field_id\fR, \fIzip_uint16_t\ extra_field_index\fR, \fIconst\ zip_uint8_t\ *extra_field_data\fR, \fIzip_uint16_t\ len\fR, \fIzip_flags_t\ flags\fR); .PD .SH "DESCRIPTION" The \fBzip_file_extra_field_set\fR() function sets the extra field with ID (two-byte signature) \fIextra_field_id\fR and index \fIextra_field_index\fR for the file at position \fIindex\fR in the zip archive. The extra field's data will be set to \fIextra_field_data\fR and length \fIlen\fR. If a new entry shall be appended, set \fIextra_field_index\fR to \fRZIP_EXTRA_FIELD_NEW\fR. .PP At least one of the following \fIflags\fR must be set: .RS 6n .TP 18n \fRZIP_FL_CENTRAL\fR Set extra field in the archive's central directory. .TP 18n \fRZIP_FL_LOCAL\fR Set extra field in the local file headers. .RE .PP Please note that the extra field IDs 0x0001 (ZIP64 extension), 0x6375 (Infozip UTF-8 comment), and 0x7075 (Infozip UTF-8 file name) can not be set using \fBzip_file_extra_field_set\fR() since they are set by libzip(3) automatically when needed. .SH "RETURN VALUES" Upon successful completion 0 is returned. Otherwise, \-1 is returned and the error code in \fIarchive\fR is set to indicate the error. .SH "ERRORS" \fBzip_file_extra_field_set\fR() fails if: .TP 19n [\fRZIP_ER_INVAL\fR] The extra field size is too large (ID and length need 4 bytes; the maximum length of all extra fields for one file combined is 65536 bytes). This error also occurs if \fIextra_field_index\fR is too large. .TP 19n [\fRZIP_ER_MEMORY\fR] Required memory could not be allocated. .TP 19n [\fRZIP_ER_NOENT\fR] \fIindex\fR is not a valid file index in \fIarchive\fR. .SH "SEE ALSO" libzip(3), zip_file_extra_field_delete(3), zip_file_extra_field_get(3), zip_file_extra_fields_count(3) .SH "HISTORY" \fBzip_file_extra_field_set\fR() was added in libzip 0.11. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_file_extra_field_set.mdoc ================================================ .\" zip_file_extra_field_set.mdoc -- set extra field for file in zip .\" Copyright (C) 2012-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP files. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd December 18, 2017 .Dt ZIP_FILE_EXTRA_FIELD_SET 3 .Os .Sh NAME .Nm zip_file_extra_field_set .Nd set extra field for file in zip .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft int .Fn zip_file_extra_field_set "zip_t *archive" "zip_uint64_t index" "zip_uint16_t extra_field_id" "zip_uint16_t extra_field_index" "const zip_uint8_t *extra_field_data" "zip_uint16_t len" "zip_flags_t flags" .Sh DESCRIPTION The .Fn zip_file_extra_field_set function sets the extra field with ID (two-byte signature) .Ar extra_field_id and index .Ar extra_field_index for the file at position .Ar index in the zip archive. The extra field's data will be set to .Ar extra_field_data and length .Ar len . If a new entry shall be appended, set .Ar extra_field_index to .Dv ZIP_EXTRA_FIELD_NEW . .Pp At least one of the following .Ar flags must be set: .Bl -tag -width ZIP_FL_CENTRALXX -offset indent .It Dv ZIP_FL_CENTRAL Set extra field in the archive's central directory. .It Dv ZIP_FL_LOCAL Set extra field in the local file headers. .El .Pp Please note that the extra field IDs 0x0001 (ZIP64 extension), 0x6375 (Infozip UTF-8 comment), and 0x7075 (Infozip UTF-8 file name) can not be set using .Fn zip_file_extra_field_set since they are set by .Xr libzip 3 automatically when needed. .Sh RETURN VALUES Upon successful completion 0 is returned. Otherwise, \-1 is returned and the error code in .Ar archive is set to indicate the error. .Sh ERRORS .Fn zip_file_extra_field_set fails if: .Bl -tag -width Er .It Bq Er ZIP_ER_INVAL The extra field size is too large (ID and length need 4 bytes; the maximum length of all extra fields for one file combined is 65536 bytes). This error also occurs if .Ar extra_field_index is too large. .It Bq Er ZIP_ER_MEMORY Required memory could not be allocated. .It Bq Er ZIP_ER_NOENT .Ar index is not a valid file index in .Ar archive . .El .Sh SEE ALSO .Xr libzip 3 , .Xr zip_file_extra_field_delete 3 , .Xr zip_file_extra_field_get 3 , .Xr zip_file_extra_fields_count 3 .Sh HISTORY .Fn zip_file_extra_field_set was added in libzip 0.11. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_file_extra_fields_count.html ================================================ ================================================ FILE: external/libzip/man/zip_file_extra_fields_count.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_file_extra_fields_count.mdoc -- count extra field for file in zip .\" Copyright (C) 2012-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP files. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_FILE_EXTRA_FIELDS_COUNT" "3" "December 18, 2017" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_file_extra_fields_count\fR, \fBzip_file_extra_fields_count_by_id\fR \- count extra fields for file in zip .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIzip_int16_t\fR .br .PD 0 .HP 4n \fBzip_file_extra_fields_count\fR(\fIzip_t\ *archive\fR, \fIzip_uint64_t\ index\fR, \fIzip_flags_t\ flags\fR); .PD .PP \fIzip_int16_t\fR .br .PD 0 .HP 4n \fBzip_file_extra_fields_count_by_id\fR(\fIzip_t\ *archive\fR, \fIzip_uint64_t\ index\fR, \fIzip_uint16_t\ extra_field_id\fR, \fIzip_flags_t\ flags\fR); .PD .SH "DESCRIPTION" The \fBzip_file_extra_fields_count\fR() function counts the extra fields for the file at position \fIindex\fR in the zip archive. .PP The following \fIflags\fR are supported: .RS 6n .TP 18n \fRZIP_FL_CENTRAL\fR Count extra fields from the archive's central directory. .TP 18n \fRZIP_FL_LOCAL\fR Count extra fields from the local file headers. .TP 18n \fRZIP_FL_UNCHANGED\fR Count the original unchanged extra fields, ignoring any changes made. .RE .PP The \fBzip_file_extra_fields_count_by_id\fR() function counts the extra fields with ID (two-byte signature) \fIextra_field_id\fR. The other arguments are the same as for \fBzip_file_extra_fields_count\fR(). .PP Extra fields that are the same in the central directory and the local file header are merged into one. Therefore, the counts with \fRZIP_FL_CENTRAL\fR and \fRZIP_FL_LOCAL\fR do not need to add up to the same value as when given \fRZIP_FL_CENTRAL|ZIP_FL_LOCAL\fR at the same time. .SH "RETURN VALUES" Upon successful completion, the requested number of extra fields is returned. Otherwise, \-1 is returned and the error code in \fIarchive\fR is set to indicate the error. .SH "ERRORS" \fBzip_file_extra_fields_count\fR() and \fBzip_file_extra_fields_count_by_id\fR() fail if: .TP 19n [\fRZIP_ER_NOENT\fR] \fIindex\fR is not a valid file index in \fIarchive\fR. .SH "SEE ALSO" libzip(3), zip_file_extra_field_delete(3), zip_file_extra_field_get(3), zip_file_extra_field_set(3) .SH "HISTORY" \fBzip_file_extra_fields_count\fR() and \fBzip_file_extra_fields_count_by_id\fR() were added in libzip 0.11. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_file_extra_fields_count.mdoc ================================================ .\" zip_file_extra_fields_count.mdoc -- count extra field for file in zip .\" Copyright (C) 2012-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP files. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd December 18, 2017 .Dt ZIP_FILE_EXTRA_FIELDS_COUNT 3 .Os .Sh NAME .Nm zip_file_extra_fields_count , .Nm zip_file_extra_fields_count_by_id .Nd count extra fields for file in zip .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft zip_int16_t .Fn zip_file_extra_fields_count "zip_t *archive" "zip_uint64_t index" "zip_flags_t flags" .Ft zip_int16_t .Fn zip_file_extra_fields_count_by_id "zip_t *archive" "zip_uint64_t index" "zip_uint16_t extra_field_id" "zip_flags_t flags" .Sh DESCRIPTION The .Fn zip_file_extra_fields_count function counts the extra fields for the file at position .Ar index in the zip archive. .Pp The following .Ar flags are supported: .Bl -tag -width ZIP_FL_CENTRALXX -offset indent .It Dv ZIP_FL_CENTRAL Count extra fields from the archive's central directory. .It Dv ZIP_FL_LOCAL Count extra fields from the local file headers. .It Dv ZIP_FL_UNCHANGED Count the original unchanged extra fields, ignoring any changes made. .El .Pp The .Fn zip_file_extra_fields_count_by_id function counts the extra fields with ID (two-byte signature) .Ar extra_field_id . The other arguments are the same as for .Fn zip_file_extra_fields_count . .Pp Extra fields that are the same in the central directory and the local file header are merged into one. Therefore, the counts with .Dv ZIP_FL_CENTRAL and .Dv ZIP_FL_LOCAL do not need to add up to the same value as when given .Dv ZIP_FL_CENTRAL|ZIP_FL_LOCAL at the same time. .Sh RETURN VALUES Upon successful completion, the requested number of extra fields is returned. Otherwise, \-1 is returned and the error code in .Ar archive is set to indicate the error. .Sh ERRORS .Fn zip_file_extra_fields_count and .Fn zip_file_extra_fields_count_by_id fail if: .Bl -tag -width Er .It Bq Er ZIP_ER_NOENT .Ar index is not a valid file index in .Ar archive . .\" TODO: _zip_read_local_ef errors .El .Sh SEE ALSO .Xr libzip 3 , .Xr zip_file_extra_field_delete 3 , .Xr zip_file_extra_field_get 3 , .Xr zip_file_extra_field_set 3 .Sh HISTORY .Fn zip_file_extra_fields_count and .Fn zip_file_extra_fields_count_by_id were added in libzip 0.11. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_file_get_comment.html ================================================ ================================================ FILE: external/libzip/man/zip_file_get_comment.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_file_get_comment.mdoc -- get comment for file in zip .\" Copyright (C) 2006-2021 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP files. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_FILE_GET_COMMENT" "3" "September 22, 2020" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_file_get_comment\fR \- get comment for file in zip .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIconst char *\fR .br .PD 0 .HP 4n \fBzip_file_get_comment\fR(\fIzip_t\ *archive\fR, \fIzip_uint64_t\ index\fR, \fIzip_uint32_t\ *lenp\fR, \fIzip_flags_t\ flags\fR); .PD .SH "DESCRIPTION" The \fBzip_file_get_comment\fR() function returns the comment for the file at position \fIindex\fR in the zip archive. The name is in UTF-8 encoding unless \fRZIP_FL_ENC_RAW\fR was specified (see below). This pointer should not be modified or free(3)'d, and becomes invalid when \fIarchive\fR is closed. If \fIlenp\fR is not \fRNULL\fR, the integer to which it points will be set to the length of the comment. If \fIflags\fR is set to \fRZIP_FL_UNCHANGED\fR, the original unchanged comment is returned. .PP Additionally, the following \fIflags\fR are supported: .RS 6n .TP 21n \fRZIP_FL_ENC_RAW\fR Return the unmodified comment as it is in the ZIP archive. .TP 21n \fRZIP_FL_ENC_GUESS\fR (Default.) Guess the encoding of the comment in the ZIP archive and convert it to UTF-8, if necessary. (Only CP-437 and UTF-8 are recognized.) .TP 21n \fRZIP_FL_ENC_STRICT\fR Follow the ZIP specification for file names and extend it to file comments, expecting them to be encoded in CP-437 in the ZIP archive (except if it is a UTF-8 comment from the special extra field). Convert it to UTF-8. .RE \fINote\fR: ASCII is a subset of both CP-437 and UTF-8. .SH "RETURN VALUES" Upon successful completion, a pointer to the comment is returned, or \fRNULL\fR if there is no comment. In case of an error, \fRNULL\fR is returned and the error code in \fIarchive\fR is set to indicate the error. .SH "ERRORS" \fBzip_file_get_comment\fR() fails if: .TP 19n [\fRZIP_ER_INVAL\fR] \fIindex\fR is not a valid file index in \fIarchive\fR. .SH "SEE ALSO" libzip(3), zip_file_set_comment(3), zip_get_archive_comment(3) .SH "HISTORY" \fBzip_file_get_comment\fR() was added in libzip 0.11. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_file_get_comment.mdoc ================================================ .\" zip_file_get_comment.mdoc -- get comment for file in zip .\" Copyright (C) 2006-2021 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP files. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd September 22, 2020 .Dt ZIP_FILE_GET_COMMENT 3 .Os .Sh NAME .Nm zip_file_get_comment .Nd get comment for file in zip .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft const char * .Fn zip_file_get_comment "zip_t *archive" "zip_uint64_t index" "zip_uint32_t *lenp" "zip_flags_t flags" .Sh DESCRIPTION The .Fn zip_file_get_comment function returns the comment for the file at position .Ar index in the zip archive. The name is in UTF-8 encoding unless .Dv ZIP_FL_ENC_RAW was specified (see below). This pointer should not be modified or .Xr free 3 Ap d , and becomes invalid when .Ar archive is closed. If .Ar lenp is not .Dv NULL , the integer to which it points will be set to the length of the comment. If .Ar flags is set to .Dv ZIP_FL_UNCHANGED , the original unchanged comment is returned. .Pp Additionally, the following .Ar flags are supported: .Bl -tag -width ZIP_FL_ENC_STRICTXX -offset indent .It Dv ZIP_FL_ENC_RAW Return the unmodified comment as it is in the ZIP archive. .It Dv ZIP_FL_ENC_GUESS (Default.) Guess the encoding of the comment in the ZIP archive and convert it to UTF-8, if necessary. (Only CP-437 and UTF-8 are recognized.) .It Dv ZIP_FL_ENC_STRICT Follow the ZIP specification for file names and extend it to file comments, expecting them to be encoded in CP-437 in the ZIP archive (except if it is a UTF-8 comment from the special extra field). Convert it to UTF-8. .El .Em Note : ASCII is a subset of both CP-437 and UTF-8. .Sh RETURN VALUES Upon successful completion, a pointer to the comment is returned, or .Dv NULL if there is no comment. In case of an error, .Dv NULL is returned and the error code in .Ar archive is set to indicate the error. .Sh ERRORS .Fn zip_file_get_comment fails if: .Bl -tag -width Er .It Bq Er ZIP_ER_INVAL .Ar index is not a valid file index in .Ar archive . .El .Sh SEE ALSO .Xr libzip 3 , .Xr zip_file_set_comment 3 , .Xr zip_get_archive_comment 3 .Sh HISTORY .Fn zip_file_get_comment was added in libzip 0.11. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_file_get_error.html ================================================ ================================================ FILE: external/libzip/man/zip_file_get_error.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_file_get_error.mdoc -- extract zip_error from zip_file .\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_FILE_GET_ERROR" "3" "December 18, 2017" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_file_get_error\fR \- extract zip_error from zip_file .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIzip_error_t *\fR .br .PD 0 .HP 4n \fBzip_file_get_error\fR(\fIzip_file_t\ *zf\fR); .PD .SH "DESCRIPTION" \fBzip_file_get_error\fR() function returns the zip_error associated with the zip_file \fIzf\fR. .SH "SEE ALSO" libzip(3) .SH "HISTORY" \fBzip_file_get_error\fR() was added in libzip 1.0. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_file_get_error.mdoc ================================================ .\" zip_file_get_error.mdoc -- extract zip_error from zip_file .\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd December 18, 2017 .Dt ZIP_FILE_GET_ERROR 3 .Os .Sh NAME .Nm zip_file_get_error .Nd extract zip_error from zip_file .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft zip_error_t * .Fn zip_file_get_error "zip_file_t *zf" .Sh DESCRIPTION .Fn zip_file_get_error function returns the zip_error associated with the zip_file .Ar zf . .Sh SEE ALSO .Xr libzip 3 .Sh HISTORY .Fn zip_file_get_error was added in libzip 1.0. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_file_get_external_attributes.html ================================================ ================================================ FILE: external/libzip/man/zip_file_get_external_attributes.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_file_get_external_attributes.mdoc -- get external attributes for file in zip .\" Copyright (C) 2013-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP files. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_FILE_GET_EXTERNAL_ATTRIBUTES" "3" "December 18, 2017" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_file_get_external_attributes\fR \- get external attributes for file in zip .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIint\fR .br .PD 0 .HP 4n \fBzip_file_get_external_attributes\fR(\fIzip_t\ *archive\fR, \fIzip_uint64_t\ index\fR, \fIzip_flags_t\ flags\fR, \fIzip_uint8_t\ *opsys\fR, \fIzip_uint32_t\ *attributes\fR); .PD .SH "DESCRIPTION" The \fBzip_file_get_external_attributes\fR() function returns the operating system and external attributes for the file at position \fIindex\fR in the zip archive. The external attributes usually contain the operating system-specific file permissions. If \fIflags\fR is set to \fRZIP_FL_UNCHANGED\fR, the original unchanged values are returned. If \fIopsys\fR or \fIattributes\fR are \fRNULL\fR, they are not filled in. .PP The following operating systems are defined by the zip specification: .RS 6n .PD 0 .PP \fRZIP_OPSYS_ACORN_RISC\fR .PP \fRZIP_OPSYS_ALTERNATE_MVS\fR .PP \fRZIP_OPSYS_AMIGA\fR .PP \fRZIP_OPSYS_ATARI_ST\fR .PP \fRZIP_OPSYS_BEOS\fR .PP \fRZIP_OPSYS_CPM\fR .PP \fRZIP_OPSYS_DOS\fR .PP \fRZIP_OPSYS_MACINTOSH\fR .PP \fRZIP_OPSYS_MVS\fR .PP \fRZIP_OPSYS_OPENVMS\fR .PP \fRZIP_OPSYS_OS_2\fR .PP \fRZIP_OPSYS_OS_400\fR .PP \fRZIP_OPSYS_OS_X\fR .PP \fRZIP_OPSYS_TANDEM\fR .PP \fRZIP_OPSYS_UNIX\fR .PP \fRZIP_OPSYS_VFAT\fR .PP \fRZIP_OPSYS_VM_CMS\fR .PP \fRZIP_OPSYS_VSE\fR .PP \fRZIP_OPSYS_WINDOWS_NTFS\fR (uncommon, use \fRZIP_OPSYS_DOS\fR instead) .PP \fRZIP_OPSYS_Z_SYSTEM\fR .RE .PD .PP The defines above follow the PKWARE Inc. Appnote; please note that the InfoZIP Appnote has a slightly different mapping. .SH "RETURN VALUES" Upon successful completion, 0 is returned. In case of an error, \fR\-1\fR is returned and the error code in \fIarchive\fR is set to indicate the error. .SH "EXAMPLES" The following code can be used to expand \fIattributes\fR if the operating system is \fRZIP_OPSYS_DOS\fR. .nf .sp .RS 0n #include #define FA_RDONLY 0x01 // FILE_ATTRIBUTE_READONLY #define FA_DIREC 0x10 // FILE_ATTRIBUTE_DIRECTORY static mode_t _zip_dos_attr2mode(zip_uint32_t attr) { mode_t m = S_IRUSR | S_IRGRP | S_IROTH; if (0 == (attr & FA_RDONLY)) m |= S_IWUSR | S_IWGRP | S_IWOTH; if (attr & FA_DIREC) m = (S_IFDIR | (m & ~S_IFMT)) | S_IXUSR | S_IXGRP | S_IXOTH; return m; } .RE .fi .SH "ERRORS" \fBzip_file_get_external_attributes\fR() fails if: .TP 19n [\fRZIP_ER_INVAL\fR] \fIindex\fR is not a valid file index in \fIarchive\fR. .SH "SEE ALSO" libzip(3), zip_file_set_external_attributes(3) .SH "HISTORY" \fBzip_file_get_external_attributes\fR() was added in libzip 0.11.2. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_file_get_external_attributes.mdoc ================================================ .\" zip_file_get_external_attributes.mdoc -- get external attributes for file in zip .\" Copyright (C) 2013-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP files. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd December 18, 2017 .Dt ZIP_FILE_GET_EXTERNAL_ATTRIBUTES 3 .Os .Sh NAME .Nm zip_file_get_external_attributes .Nd get external attributes for file in zip .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft int .Fn zip_file_get_external_attributes "zip_t *archive" "zip_uint64_t index" "zip_flags_t flags" "zip_uint8_t *opsys" "zip_uint32_t *attributes" .Sh DESCRIPTION The .Fn zip_file_get_external_attributes function returns the operating system and external attributes for the file at position .Ar index in the zip archive. The external attributes usually contain the operating system-specific file permissions. If .Ar flags is set to .Dv ZIP_FL_UNCHANGED , the original unchanged values are returned. If .Ar opsys or .Ar attributes are .Dv NULL , they are not filled in. .Pp The following operating systems are defined by the zip specification: .Bl -item -compact -offset indent .It .Dv ZIP_OPSYS_ACORN_RISC .It .Dv ZIP_OPSYS_ALTERNATE_MVS .It .Dv ZIP_OPSYS_AMIGA .It .Dv ZIP_OPSYS_ATARI_ST .It .Dv ZIP_OPSYS_BEOS .It .Dv ZIP_OPSYS_CPM .It .Dv ZIP_OPSYS_DOS .It .Dv ZIP_OPSYS_MACINTOSH .It .Dv ZIP_OPSYS_MVS .It .Dv ZIP_OPSYS_OPENVMS .It .Dv ZIP_OPSYS_OS_2 .It .Dv ZIP_OPSYS_OS_400 .It .Dv ZIP_OPSYS_OS_X .It .Dv ZIP_OPSYS_TANDEM .It .Dv ZIP_OPSYS_UNIX .It .Dv ZIP_OPSYS_VFAT .It .Dv ZIP_OPSYS_VM_CMS .It .Dv ZIP_OPSYS_VSE .It .Dv ZIP_OPSYS_WINDOWS_NTFS (uncommon, use .Dv ZIP_OPSYS_DOS instead) .It .Dv ZIP_OPSYS_Z_SYSTEM .El .Pp The defines above follow the PKWARE Inc. Appnote; please note that the InfoZIP Appnote has a slightly different mapping. .Sh RETURN VALUES Upon successful completion, 0 is returned. In case of an error, .Dv \-1 is returned and the error code in .Ar archive is set to indicate the error. .Sh EXAMPLES The following code can be used to expand .Ar attributes if the operating system is .Dv ZIP_OPSYS_DOS . .Bd -literal #include #define FA_RDONLY 0x01 // FILE_ATTRIBUTE_READONLY #define FA_DIREC 0x10 // FILE_ATTRIBUTE_DIRECTORY static mode_t _zip_dos_attr2mode(zip_uint32_t attr) { mode_t m = S_IRUSR | S_IRGRP | S_IROTH; if (0 == (attr & FA_RDONLY)) m |= S_IWUSR | S_IWGRP | S_IWOTH; if (attr & FA_DIREC) m = (S_IFDIR | (m & ~S_IFMT)) | S_IXUSR | S_IXGRP | S_IXOTH; return m; } .Ed .Sh ERRORS .Fn zip_file_get_external_attributes fails if: .Bl -tag -width Er .It Bq Er ZIP_ER_INVAL .Ar index is not a valid file index in .Ar archive . .El .Sh SEE ALSO .Xr libzip 3 , .Xr zip_file_set_external_attributes 3 .Sh HISTORY .Fn zip_file_get_external_attributes was added in libzip 0.11.2. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_file_rename.html ================================================ ================================================ FILE: external/libzip/man/zip_file_rename.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_file_rename.mdoc -- rename file in zip archive .\" Copyright (C) 2003-2021 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_FILE_RENAME" "3" "September 22, 2020" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_file_rename\fR \- rename file in zip archive .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIint\fR .br .PD 0 .HP 4n \fBzip_file_rename\fR(\fIzip_t\ *archive\fR, \fIzip_uint64_t\ index\fR, \fIconst\ char\ *name\fR, \fIzip_flags_t\ flags\fR); .PD .SH "DESCRIPTION" The file at position \fIindex\fR in the zip archive \fIarchive\fR is renamed to \fIname\fR. The \fIflags\fR argument can be any of: .TP 22n \fRZIP_FL_ENC_GUESS\fR Guess encoding of \fIname\fR (default). (Only CP-437 and UTF-8 are recognized.) .TP 22n \fRZIP_FL_ENC_UTF_8\fR Interpret \fIname\fR as UTF-8. .TP 22n \fRZIP_FL_ENC_CP437\fR Interpret \fIname\fR as code page 437 (CP-437). .SH "RETURN VALUES" Upon successful completion 0 is returned. Otherwise, \-1 is returned and the error code in \fIarchive\fR is set to indicate the error. .SH "ERRORS" \fBzip_file_rename\fR() fails if: .TP 19n [\fRZIP_ER_DELETED\fR] The file to be renamed has been deleted from the archive. .TP 19n [\fRZIP_ER_EXISTS\fR] There is already a file called \fIname\fR in the archive. .TP 19n [\fRZIP_ER_INVAL\fR] \fIindex\fR is not a valid file index in \fIarchive\fR, \fIname is\fR \fRNULL\fR, the empty string, or not a valid UTF-8 encoded string. Also a file cannot be renamed to a directory or vice versa. Directories are denoted by a trailing slash. .SH "SEE ALSO" libzip(3), zip_unchange(3) .SH "HISTORY" \fBzip_file_rename\fR() was added in libzip 0.11. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_file_rename.mdoc ================================================ .\" zip_file_rename.mdoc -- rename file in zip archive .\" Copyright (C) 2003-2021 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd September 22, 2020 .Dt ZIP_FILE_RENAME 3 .Os .Sh NAME .Nm zip_file_rename .Nd rename file in zip archive .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft int .Fn zip_file_rename "zip_t *archive" "zip_uint64_t index" "const char *name" "zip_flags_t flags" .Sh DESCRIPTION The file at position .Ar index in the zip archive .Ar archive is renamed to .Ar name . The .Ar flags argument can be any of: .Bl -tag -width XZIPXFLXENCXSTRICTXX .It Dv ZIP_FL_ENC_GUESS Guess encoding of .Ar name (default). (Only CP-437 and UTF-8 are recognized.) .It Dv ZIP_FL_ENC_UTF_8 Interpret .Ar name as UTF-8. .It Dv ZIP_FL_ENC_CP437 Interpret .Ar name as code page 437 (CP-437). .El .Sh RETURN VALUES Upon successful completion 0 is returned. Otherwise, \-1 is returned and the error code in .Ar archive is set to indicate the error. .Sh ERRORS .Fn zip_file_rename fails if: .Bl -tag -width Er .It Bq Er ZIP_ER_DELETED The file to be renamed has been deleted from the archive. .It Bq Er ZIP_ER_EXISTS There is already a file called .Ar name in the archive. .It Bq Er ZIP_ER_INVAL .Ar index is not a valid file index in .Ar archive , .Ar name is .Dv NULL , the empty string, or not a valid UTF-8 encoded string. Also a file cannot be renamed to a directory or vice versa. Directories are denoted by a trailing slash. .El .Sh SEE ALSO .Xr libzip 3 , .Xr zip_unchange 3 .Sh HISTORY .Fn zip_file_rename was added in libzip 0.11. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_file_set_comment.html ================================================ ================================================ FILE: external/libzip/man/zip_file_set_comment.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_file_set_comment.mdoc -- set comment for file in zip .\" Copyright (C) 2006-2021 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP files. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_FILE_SET_COMMENT" "3" "September 22, 2020" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_file_set_comment\fR \- set comment for file in zip .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIint\fR .br .PD 0 .HP 4n \fBzip_file_set_comment\fR(\fIzip_t\ *archive\fR, \fIzip_uint64_t\ index\fR, \fIconst\ char\ *comment\fR, \fIzip_uint16_t\ len\fR, \fIzip_flags_t\ flags\fR); .PD .SH "DESCRIPTION" The \fBzip_file_set_comment\fR() function sets the comment for the file at position \fIindex\fR in the zip archive to \fIcomment\fR of length \fIlen\fR. If \fIcomment\fR is \fRNULL\fR and \fIlen\fR is 0, the file comment will be removed. The \fIflags\fR argument can be any of: .TP 22n \fRZIP_FL_ENC_GUESS\fR Guess encoding of \fIcomment\fR (default). (Only CP-437 and UTF-8 are recognized.) .TP 22n \fRZIP_FL_ENC_UTF_8\fR Interpret \fIcomment\fR as UTF-8. .TP 22n \fRZIP_FL_ENC_CP437\fR Interpret \fIcomment\fR as code page 437 (CP-437). .SH "RETURN VALUES" Upon successful completion 0 is returned. Otherwise, \-1 is returned and the error information in \fIarchive\fR is set to indicate the error. .SH "ERRORS" \fBzip_file_set_comment\fR() fails if: .TP 19n [\fRZIP_ER_INVAL\fR] \fIindex\fR is not a valid file index in \fIarchive\fR, or \fIlen\fR is less than 0 or longer than the maximum comment length in a zip file (65535), or \fIcomment\fR is not a valid UTF-8 encoded string. .TP 19n [\fRZIP_ER_MEMORY\fR] Required memory could not be allocated. .TP 19n [\fRZIP_ER_RDONLY\fR] The \fIarchive\fR was opened in read-only mode. .SH "SEE ALSO" libzip(3), zip_file_get_comment(3), zip_get_archive_comment(3), zip_set_archive_comment(3) .SH "HISTORY" \fBzip_file_set_comment\fR() was added in libzip 0.11. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_file_set_comment.mdoc ================================================ .\" zip_file_set_comment.mdoc -- set comment for file in zip .\" Copyright (C) 2006-2021 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP files. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd September 22, 2020 .Dt ZIP_FILE_SET_COMMENT 3 .Os .Sh NAME .Nm zip_file_set_comment .Nd set comment for file in zip .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft int .Fn zip_file_set_comment "zip_t *archive" "zip_uint64_t index" "const char *comment" "zip_uint16_t len" "zip_flags_t flags" .Sh DESCRIPTION The .Fn zip_file_set_comment function sets the comment for the file at position .Ar index in the zip archive to .Ar comment of length .Ar len . If .Ar comment is .Dv NULL and .Ar len is 0, the file comment will be removed. The .Ar flags argument can be any of: .Bl -tag -width XZIPXFLXENCXSTRICTXX .It Dv ZIP_FL_ENC_GUESS Guess encoding of .Ar comment (default). (Only CP-437 and UTF-8 are recognized.) .It Dv ZIP_FL_ENC_UTF_8 Interpret .Ar comment as UTF-8. .It Dv ZIP_FL_ENC_CP437 Interpret .Ar comment as code page 437 (CP-437). .El .Sh RETURN VALUES Upon successful completion 0 is returned. Otherwise, \-1 is returned and the error information in .Ar archive is set to indicate the error. .Sh ERRORS .Fn zip_file_set_comment fails if: .Bl -tag -width Er .It Bq Er ZIP_ER_INVAL .Ar index is not a valid file index in .Ar archive , or .Ar len is less than 0 or longer than the maximum comment length in a zip file (65535), or .Ar comment is not a valid UTF-8 encoded string. .It Bq Er ZIP_ER_MEMORY Required memory could not be allocated. .It Bq Er ZIP_ER_RDONLY The .Ar archive was opened in read-only mode. .El .Sh SEE ALSO .Xr libzip 3 , .Xr zip_file_get_comment 3 , .Xr zip_get_archive_comment 3 , .Xr zip_set_archive_comment 3 .Sh HISTORY .Fn zip_file_set_comment was added in libzip 0.11. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_file_set_encryption.html ================================================ ================================================ FILE: external/libzip/man/zip_file_set_encryption.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_file_set_encryption.mdoc -- set encryption method for file .\" Copyright (C) 2016-2021 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP files. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_FILE_SET_ENCRYPTION" "3" "April 2, 2020" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_file_set_encryption\fR \- set encryption method for file in zip .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIint\fR .br .PD 0 .HP 4n \fBzip_file_set_encryption\fR(\fIzip_t\ *archive\fR, \fIzip_uint64_t\ index\fR, \fIzip_uint16_t\ method\fR, \fIconst\ char\ *password\fR); .PD .SH "DESCRIPTION" The \fBzip_file_set_encryption\fR() function sets the encryption method for the file at position \fIindex\fR in the zip archive to \fImethod\fR using the password \fIpassword\fR. The \fImethod\fR is the same as returned by zip_stat(3). For the \fImethod\fR argument, currently only the following values are supported: .TP 19n \fRZIP_EM_NONE\fR No encryption. .TP 19n \fRZIP_EM_AES_128\fR Winzip AES-128 encryption. .TP 19n \fRZIP_EM_AES_192\fR Winzip AES-192 encryption. .TP 19n \fRZIP_EM_AES_256\fR Winzip AES-256 encryption. .TP 19n \fRZIP_EM_TRAD_PKWARE\fR .br Traditional PKWare encryption. Do not use this method, it is not secure. It is only provided for backwards compatibility. .PP If \fIpassword\fR is \fRNULL\fR, the default password provided by zip_set_default_password(3) is used. .PP The current encryption method for a file in a zip archive can be determined using zip_stat(3). .SH "RETURN VALUES" Upon successful completion 0 is returned. Otherwise, \-1 is returned and the error information in \fIarchive\fR is set to indicate the error. .SH "ERRORS" \fBzip_file_set_encryption\fR() fails if: .TP 19n [\fRZIP_ER_ENCRNOTSUPP\fR] Unsupported compression method requested. .TP 19n [\fRZIP_ER_INVAL\fR] \fIindex\fR is not a valid file index in \fIarchive\fR, or the argument combination is invalid. .TP 19n [\fRZIP_ER_MEMORY\fR] Required memory could not be allocated. .TP 19n [\fRZIP_ER_RDONLY\fR] Read-only zip file, no changes allowed. .SH "SEE ALSO" libzip(3), zip_encryption_method_supported(3), zip_fopen_encrypted(3), zip_fopen_index_encrypted(3), zip_set_default_password(3), zip_stat(3) .SH "HISTORY" \fBzip_file_set_encryption\fR() was added in libzip 1.2.0. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_file_set_encryption.mdoc ================================================ .\" zip_file_set_encryption.mdoc -- set encryption method for file .\" Copyright (C) 2016-2021 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP files. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd April 2, 2020 .Dt ZIP_FILE_SET_ENCRYPTION 3 .Os .Sh NAME .Nm zip_file_set_encryption .Nd set encryption method for file in zip .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft int .Fn zip_file_set_encryption "zip_t *archive" "zip_uint64_t index" "zip_uint16_t method" "const char *password" .Sh DESCRIPTION The .Fn zip_file_set_encryption function sets the encryption method for the file at position .Ar index in the zip archive to .Ar method using the password .Ar password . The .Ar method is the same as returned by .Xr zip_stat 3 . For the .Ar method argument, currently only the following values are supported: .Bl -tag -width ZIP_CM_DEFLATE_XX .It Dv ZIP_EM_NONE No encryption. .It Dv ZIP_EM_AES_128 Winzip AES-128 encryption. .It Dv ZIP_EM_AES_192 Winzip AES-192 encryption. .It Dv ZIP_EM_AES_256 Winzip AES-256 encryption. .It Dv ZIP_EM_TRAD_PKWARE Traditional PKWare encryption. Do not use this method, it is not secure. It is only provided for backwards compatibility. .El .Pp If .Ar password is .Dv NULL , the default password provided by .Xr zip_set_default_password 3 is used. .Pp The current encryption method for a file in a zip archive can be determined using .Xr zip_stat 3 . .Sh RETURN VALUES Upon successful completion 0 is returned. Otherwise, \-1 is returned and the error information in .Ar archive is set to indicate the error. .Sh ERRORS .Fn zip_file_set_encryption fails if: .Bl -tag -width Er .It Bq Er ZIP_ER_ENCRNOTSUPP Unsupported compression method requested. .It Bq Er ZIP_ER_INVAL .Ar index is not a valid file index in .Ar archive , or the argument combination is invalid. .It Bq Er ZIP_ER_MEMORY Required memory could not be allocated. .It Bq Er ZIP_ER_RDONLY Read-only zip file, no changes allowed. .El .Sh SEE ALSO .Xr libzip 3 , .Xr zip_encryption_method_supported 3 , .Xr zip_fopen_encrypted 3 , .Xr zip_fopen_index_encrypted 3 , .Xr zip_set_default_password 3 , .Xr zip_stat 3 .Sh HISTORY .Fn zip_file_set_encryption was added in libzip 1.2.0. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_file_set_external_attributes.html ================================================ ================================================ FILE: external/libzip/man/zip_file_set_external_attributes.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_file_set_external_attributes.mdoc -- set external attributes for file in zip .\" Copyright (C) 2013-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP files. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_FILE_SET_EXTERNAL_ATTRIBUTES" "3" "December 18, 2017" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_file_set_external_attributes\fR \- set external attributes for file in zip .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIint\fR .br .PD 0 .HP 4n \fBzip_file_set_external_attributes\fR(\fIzip_t\ *archive\fR, \fIzip_uint64_t\ index\fR, \fIzip_flags_t\ flags\fR, \fIzip_uint8_t\ opsys\fR, \fIzip_uint32_t\ attributes\fR); .PD .SH "DESCRIPTION" The \fBzip_file_set_external_attributes\fR() function sets the operating system and external attributes for the file at position \fIindex\fR in the zip archive. Currently, no \fIflags\fR are supported. .PP For a list of known \fIopsys\fR values, see zip_file_get_external_attributes(3). .SH "RETURN VALUES" Upon successful completion 0 is returned. Otherwise, \-1 is returned and the error information in \fIarchive\fR is set to indicate the error. .SH "ERRORS" \fBzip_file_set_external_attributes\fR() fails if: .TP 19n [\fRZIP_ER_INVAL\fR] \fIindex\fR is not a valid file index in \fIarchive\fR. .TP 19n [\fRZIP_ER_MEMORY\fR] Required memory could not be allocated. .TP 19n [\fRZIP_ER_RDONLY\fR] The \fIarchive\fR was opened in read-only mode. .SH "SEE ALSO" libzip(3), zip_file_get_external_attributes(3) .SH "HISTORY" \fBzip_file_set_external_attributes\fR() was added in libzip 0.11.2. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_file_set_external_attributes.mdoc ================================================ .\" zip_file_set_external_attributes.mdoc -- set external attributes for file in zip .\" Copyright (C) 2013-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP files. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd December 18, 2017 .Dt ZIP_FILE_SET_EXTERNAL_ATTRIBUTES 3 .Os .Sh NAME .Nm zip_file_set_external_attributes .Nd set external attributes for file in zip .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft int .Fn zip_file_set_external_attributes "zip_t *archive" "zip_uint64_t index" "zip_flags_t flags" "zip_uint8_t opsys" "zip_uint32_t attributes" .Sh DESCRIPTION The .Fn zip_file_set_external_attributes function sets the operating system and external attributes for the file at position .Ar index in the zip archive. Currently, no .Ar flags are supported. .Pp For a list of known .Ar opsys values, see .Xr zip_file_get_external_attributes 3 . .Sh RETURN VALUES Upon successful completion 0 is returned. Otherwise, \-1 is returned and the error information in .Ar archive is set to indicate the error. .Sh ERRORS .Fn zip_file_set_external_attributes fails if: .Bl -tag -width Er .It Bq Er ZIP_ER_INVAL .Ar index is not a valid file index in .Ar archive . .It Bq Er ZIP_ER_MEMORY Required memory could not be allocated. .It Bq Er ZIP_ER_RDONLY The .Ar archive was opened in read-only mode. .El .Sh SEE ALSO .Xr libzip 3 , .Xr zip_file_get_external_attributes 3 .Sh HISTORY .Fn zip_file_set_external_attributes was added in libzip 0.11.2. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_file_set_mtime.html ================================================ ================================================ FILE: external/libzip/man/zip_file_set_mtime.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_file_set_mtime.mdoc -- set mtime for file in zip .\" Copyright (C) 2014-2022 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP files. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_FILE_SET_MTIME" "3" "June 18, 2022" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_file_set_dostime\fR, \fBzip_file_set_mtime\fR \- set last modification time (mtime) for file in zip .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIint\fR .br .PD 0 .HP 4n \fBzip_file_set_dostime\fR(\fIzip_t\ *archive\fR, \fIzip_uint64_t\ index\fR, \fIzip_uint16_t\ dostime\fR, \fIzip_uint16_t\ dosdate\fR, \fIzip_flags_t\ flags\fR); .PD .PP \fIint\fR .br .PD 0 .HP 4n \fBzip_file_set_mtime\fR(\fIzip_t\ *archive\fR, \fIzip_uint64_t\ index\fR, \fItime_t\ mtime\fR, \fIzip_flags_t\ flags\fR); .PD .SH "DESCRIPTION" The \fBzip_file_set_mtime\fR() function sets the last modification time (mtime) for the file at position \fIindex\fR in the zip archive to \fImtime\fR. Currently, no support for any \fIflags\fR is implemented. .PP In the zip archive, the time and date are saved as two 16-bit integers. To set the values directly, call the \fBzip_file_set_dostime\fR() function. The values of the time bytes are defined as follows: .RS 6n .TP 7n 0-4 seconds divided by two (1-2 = 1, 3-4 = 2, ...) .TP 7n 5-10 minute (0-59) .TP 7n 11-15 hour (0-23) .RE .PP The values of the date bytes are defined as follows: .RS 6n .TP 7n 0-4 day of the month (1-31) .TP 7n 5-8 month (January = 1, February = 2, ...) .TP 7n 9-15 year offset from 1980 (1980 = 0, 1981 = 1, ...) .RE .SH "RETURN VALUES" Upon successful completion 0 is returned. Otherwise, \-1 is returned and the error information in \fIarchive\fR is set to indicate the error. .SH "ERRORS" \fBzip_file_set_dostime\fR() and \fBzip_file_set_mtime\fR() fail if: .TP 19n [\fRZIP_ER_INVAL\fR] \fIindex\fR is not a valid file index in \fIarchive\fR. .TP 19n [\fRZIP_ER_MEMORY\fR] Required memory could not be allocated. .TP 19n [\fRZIP_ER_OPNOTSUPP\fR] .br Traditional PKWare encryption uses the file's mtime, therefore it cannot be changed without re-encrypting the data. .TP 19n [\fRZIP_ER_RDONLY\fR] The \fIarchive\fR was opened in read-only mode. .SH "SEE ALSO" libzip(3), zip_stat(3) .SH "HISTORY" \fBzip_file_set_mtime\fR() was added in libzip 1.0. \fBzip_file_set_dostime\fR() was added in libzip 1.6. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> .SH "CAVEATS" Following historical practice, the \fBzip_file_set_mtime\fR() function translates the time from the zip archive into the local time zone. If you want to avoid this, use the \fBzip_file_set_dostime\fR() function instead. ================================================ FILE: external/libzip/man/zip_file_set_mtime.mdoc ================================================ .\" zip_file_set_mtime.mdoc -- set mtime for file in zip .\" Copyright (C) 2014-2022 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP files. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd June 18, 2022 .Dt ZIP_FILE_SET_MTIME 3 .Os .Sh NAME .Nm zip_file_set_dostime , .Nm zip_file_set_mtime .Nd set last modification time (mtime) for file in zip .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft int .Fn zip_file_set_dostime "zip_t *archive" "zip_uint64_t index" "zip_uint16_t dostime" "zip_uint16_t dosdate" "zip_flags_t flags" .Ft int .Fn zip_file_set_mtime "zip_t *archive" "zip_uint64_t index" "time_t mtime" "zip_flags_t flags" .Sh DESCRIPTION The .Fn zip_file_set_mtime function sets the last modification time (mtime) for the file at position .Ar index in the zip archive to .Ar mtime . Currently, no support for any .Ar flags is implemented. .Pp In the zip archive, the time and date are saved as two 16-bit integers. To set the values directly, call the .Fn zip_file_set_dostime function. The values of the time bytes are defined as follows: .Bl -tag -width 5n -offset indent .It 0-4 seconds divided by two (1-2 = 1, 3-4 = 2, ...) .It 5-10 minute (0-59) .It 11-15 hour (0-23) .El .Pp The values of the date bytes are defined as follows: .Bl -tag -width 5n -offset indent .It 0-4 day of the month (1-31) .It 5-8 month (January = 1, February = 2, ...) .It 9-15 year offset from 1980 (1980 = 0, 1981 = 1, ...) .El .Sh RETURN VALUES Upon successful completion 0 is returned. Otherwise, \-1 is returned and the error information in .Ar archive is set to indicate the error. .Sh ERRORS .Fn zip_file_set_dostime and .Fn zip_file_set_mtime fail if: .Bl -tag -width Er .It Bq Er ZIP_ER_INVAL .Ar index is not a valid file index in .Ar archive . .It Bq Er ZIP_ER_MEMORY Required memory could not be allocated. .It Bq Er ZIP_ER_OPNOTSUPP Traditional PKWare encryption uses the file's mtime, therefore it cannot be changed without re-encrypting the data. .It Bq Er ZIP_ER_RDONLY The .Ar archive was opened in read-only mode. .El .Sh SEE ALSO .Xr libzip 3 , .Xr zip_stat 3 .Sh HISTORY .Fn zip_file_set_mtime was added in libzip 1.0. .Fn zip_file_set_dostime was added in libzip 1.6. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at .Sh CAVEATS Following historical practice, the .Fn zip_file_set_mtime function translates the time from the zip archive into the local time zone. If you want to avoid this, use the .Fn zip_file_set_dostime function instead. ================================================ FILE: external/libzip/man/zip_file_strerror.html ================================================ ================================================ FILE: external/libzip/man/zip_file_strerror.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_file_strerror.mdoc -- get string representation for a zip error .\" Copyright (C) 2003-2021 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_FILE_STRERROR" "3" "December 18, 2017" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_file_strerror\fR, \fBzip_strerror\fR \- get string representation for a zip error .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIconst char *\fR .br .PD 0 .HP 4n \fBzip_file_strerror\fR(\fIzip_file_t\ *file\fR); .PD .PP \fIconst char *\fR .br .PD 0 .HP 4n \fBzip_strerror\fR(\fIzip_t\ *archive\fR); .PD .SH "DESCRIPTION" The \fBzip_strerror\fR() function returns a string describing the last error for the zip archive \fIarchive\fR, while the \fBzip_file_strerror\fR() function does the same for a zip file \fIfile\fR (one file in an archive). The returned string must not be modified or freed, and becomes invalid when \fIarchive\fR or \fIfile\fR, respectively, is closed or on the next call to \fBzip_strerror\fR() or \fBzip_file_strerror\fR(), respectively, for the same archive. .SH "RETURN VALUES" \fBzip_file_strerror\fR() and \fBzip_strerror\fR() return a pointer to the error string. .SH "SEE ALSO" libzip(3), zip_error_strerror(3) .SH "HISTORY" \fBzip_file_strerror\fR() and \fBzip_strerror\fR() were added in libzip 0.6. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_file_strerror.mdoc ================================================ .\" zip_file_strerror.mdoc -- get string representation for a zip error .\" Copyright (C) 2003-2021 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd December 18, 2017 .Dt ZIP_FILE_STRERROR 3 .Os .Sh NAME .Nm zip_file_strerror , .Nm zip_strerror .Nd get string representation for a zip error .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft const char * .Fn zip_file_strerror "zip_file_t *file" .Ft const char * .Fn zip_strerror "zip_t *archive" .Sh DESCRIPTION The .Fn zip_strerror function returns a string describing the last error for the zip archive .Ar archive , while the .Fn zip_file_strerror function does the same for a zip file .Ar file (one file in an archive). The returned string must not be modified or freed, and becomes invalid when .Ar archive or .Ar file , respectively, is closed or on the next call to .Fn zip_strerror or .Fn zip_file_strerror , respectively, for the same archive. .Sh RETURN VALUES .Fn zip_file_strerror and .Fn zip_strerror return a pointer to the error string. .Sh SEE ALSO .Xr libzip 3 , .Xr zip_error_strerror 3 .Sh HISTORY .Fn zip_file_strerror and .Fn zip_strerror were added in libzip 0.6. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_fopen.html ================================================ ================================================ FILE: external/libzip/man/zip_fopen.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_fopen.mdoc -- open file in zip archive for reading .\" Copyright (C) 2003-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_FOPEN" "3" "December 18, 2017" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_fopen\fR, \fBzip_fopen_index\fR \- open file in zip archive for reading .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIzip_file_t *\fR .br .PD 0 .HP 4n \fBzip_fopen\fR(\fIzip_t\ *archive\fR, \fIconst\ char\ *fname\fR, \fIzip_flags_t\ flags\fR); .PD .PP \fIzip_file_t *\fR .br .PD 0 .HP 4n \fBzip_fopen_index\fR(\fIzip_t\ *archive\fR, \fIzip_uint64_t\ index\fR, \fIzip_flags_t\ flags\fR); .PD .SH "DESCRIPTION" The \fBzip_fopen\fR() function opens the file name \fIfname\fR in \fIarchive\fR. The \fIflags\fR argument specifies how the name lookup should be done, according to the values are described in zip_name_locate(3). Also, the following values may be \fIor\fR'ed to it. .RS 6n .TP 19n \fRZIP_FL_COMPRESSED\fR Read the compressed data. Otherwise the data is uncompressed by \fBzip_fread\fR(). .TP 19n \fRZIP_FL_UNCHANGED\fR Read the original data from the zip archive, ignoring any changes made to the file; this is not supported by all data sources. .RE .PP The \fBzip_fopen_index\fR() function opens the file at position \fIindex\fR. .PP If encrypted data is encountered, the functions call zip_fopen_encrypted(3) or zip_fopen_index_encrypted(3) respectively, using the default password set with zip_set_default_password(3). .SH "RETURN VALUES" Upon successful completion, a \fIstruct zip_file\fR pointer is returned. Otherwise, \fRNULL\fR is returned and the error code in \fIarchive\fR is set to indicate the error. .SH "ERRORS" .TP 19n [\fRZIP_ER_CHANGED\fR] The file data has been changed and the data source does not support rereading data. .TP 19n [\fRZIP_ER_COMPNOTSUPP\fR] The compression method used is not supported. .TP 19n [\fRZIP_ER_ENCRNOTSUPP\fR] The encryption method used is not supported. .TP 19n [\fRZIP_ER_MEMORY\fR] Required memory could not be allocated. .TP 19n [\fRZIP_ER_NOPASSWD\fR] The file is encrypted, but no password has been provided. .TP 19n [\fRZIP_ER_READ\fR] A file read error occurred. .TP 19n [\fRZIP_ER_SEEK\fR] A file seek error occurred. .TP 19n [\fRZIP_ER_WRONGPASSWD\fR] The provided password does not match the password used for encryption. Note that some incorrect passwords are not detected by the check done by \fBzip_fopen\fR(). .TP 19n [\fRZIP_ER_ZLIB\fR] Initializing the zlib stream failed. .PP The function \fBzip_fopen\fR() may also fail and set \fIzip_err\fR for any of the errors specified for the routine zip_name_locate(3). .PP The function \fBzip_fopen_index\fR() may also fail with \fRZIP_ER_INVAL\fR if \fIindex\fR is invalid. .SH "SEE ALSO" libzip(3), zip_fclose(3), zip_fread(3), zip_fseek(3), zip_get_num_entries(3), zip_name_locate(3), zip_set_default_password(3) .SH "HISTORY" \fBzip_fopen\fR() and \fBzip_fopen_index\fR() were added in libzip 1.0. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_fopen.mdoc ================================================ .\" zip_fopen.mdoc -- open file in zip archive for reading .\" Copyright (C) 2003-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd December 18, 2017 .Dt ZIP_FOPEN 3 .Os .Sh NAME .Nm zip_fopen , .Nm zip_fopen_index .Nd open file in zip archive for reading .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft zip_file_t * .Fn zip_fopen "zip_t *archive" "const char *fname" "zip_flags_t flags" .Ft zip_file_t * .Fn zip_fopen_index "zip_t *archive" "zip_uint64_t index" "zip_flags_t flags" .Sh DESCRIPTION The .Fn zip_fopen function opens the file name .Ar fname in .Ar archive . The .Ar flags argument specifies how the name lookup should be done, according to the values are described in .Xr zip_name_locate 3 . Also, the following values may be .Em or Ns No 'ed to it. .Bl -tag -offset indent -width ZIP_FL_COMPRESSED .It Dv ZIP_FL_COMPRESSED Read the compressed data. Otherwise the data is uncompressed by .Fn zip_fread . .It Dv ZIP_FL_UNCHANGED Read the original data from the zip archive, ignoring any changes made to the file; this is not supported by all data sources. .El .Pp The .Fn zip_fopen_index function opens the file at position .Ar index . .Pp If encrypted data is encountered, the functions call .Xr zip_fopen_encrypted 3 or .Xr zip_fopen_index_encrypted 3 respectively, using the default password set with .Xr zip_set_default_password 3 . .Sh RETURN VALUES Upon successful completion, a .Ft struct zip_file pointer is returned. Otherwise, .Dv NULL is returned and the error code in .Ar archive is set to indicate the error. .Sh ERRORS .Bl -tag -width Er .It Bq Er ZIP_ER_CHANGED The file data has been changed and the data source does not support rereading data. .It Bq Er ZIP_ER_COMPNOTSUPP The compression method used is not supported. .It Bq Er ZIP_ER_ENCRNOTSUPP The encryption method used is not supported. .It Bq Er ZIP_ER_MEMORY Required memory could not be allocated. .It Bq Er ZIP_ER_NOPASSWD The file is encrypted, but no password has been provided. .It Bq Er ZIP_ER_READ A file read error occurred. .It Bq Er ZIP_ER_SEEK A file seek error occurred. .It Bq Er ZIP_ER_WRONGPASSWD The provided password does not match the password used for encryption. Note that some incorrect passwords are not detected by the check done by .Fn zip_fopen . .It Bq Er ZIP_ER_ZLIB Initializing the zlib stream failed. .El .Pp The function .Fn zip_fopen may also fail and set .Va zip_err for any of the errors specified for the routine .Xr zip_name_locate 3 . .Pp The function .Fn zip_fopen_index may also fail with .Er ZIP_ER_INVAL if .Ar index is invalid. .Sh SEE ALSO .Xr libzip 3 , .Xr zip_fclose 3 , .Xr zip_fread 3 , .Xr zip_fseek 3 , .Xr zip_get_num_entries 3 , .Xr zip_name_locate 3 , .Xr zip_set_default_password 3 .Sh HISTORY .Fn zip_fopen and .Fn zip_fopen_index were added in libzip 1.0. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_fopen_encrypted.html ================================================ ================================================ FILE: external/libzip/man/zip_fopen_encrypted.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_fopen_encrypted.mdoc -- open encrypted file in zip archive for reading .\" Copyright (C) 2011-2021 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_FOPEN_ENCRYPTED" "3" "September 15, 2020" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_fopen_encrypted\fR, \fBzip_fopen_index_encrypted\fR \- open encrypted file in zip archive for reading .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIzip_file_t *\fR .br .PD 0 .HP 4n \fBzip_fopen_encrypted\fR(\fIzip_t\ *archive\fR, \fIconst\ char\ *fname\fR, \fIzip_flags_t\ flags\fR, \fIconst\ char\ *password\fR); .PD .PP \fIzip_file_t *\fR .br .PD 0 .HP 4n \fBzip_fopen_index_encrypted\fR(\fIzip_t\ *archive\fR, \fIzip_uint64_t\ index\fR, \fIzip_flags_t\ flags\fR, \fIconst\ char\ *password\fR); .PD .SH "DESCRIPTION" The \fBzip_fopen_encrypted\fR() function opens the encrypted file name \fIfname\fR in \fIarchive\fR using the password given in the \fIpassword\fR argument. If \fIpassword\fR is \fRNULL\fR or the empty string, the default password is used (see zip_set_default_password(3)). The \fIflags\fR argument are the same as for zip_fopen(3). .PP The \fBzip_fopen_index_encrypted\fR() function opens the file at position \fIindex\fR, see zip_fopen_index(3). These functions are called automatically by zip_fopen(3); you only need to call them if you want to specify a non-default password (see zip_set_default_password(3)). .SH "RETURN VALUES" Upon successful completion, a \fIstruct zip_file\fR pointer is returned. Otherwise, \fRNULL\fR is returned and the error code in \fIarchive\fR is set to indicate the error. .SH "ERRORS" .TP 22n [\fRZIP_ER_NOPASSWD\fR] No password was provided. .PP The function \fBzip_fopen_encrypted\fR() may also fail and set \fIzip_err\fR for any of the errors specified for the routine zip_fopen(3). .PP The function \fBzip_fopen_index_encrypted\fR() may also fail and set \fIzip_err\fR for any of the errors specified for the routine zip_fopen_index(3). .SH "SEE ALSO" libzip(3), zip_fclose(3), zip_fopen(3), zip_fread(3), zip_get_num_entries(3), zip_name_locate(3) .SH "HISTORY" \fBzip_fopen_encrypted\fR() and \fBzip_fopen_index_encrypted\fR() were added in libzip 1.0. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> .SH "CAVEATS" The zip file format provides very limited possibility for password verification (a short hash of is compared against one byte in the zip archive). For this reason, reading a file while using an incorrect password may immediately fail with \fRZIP_ER_WRONGPASSWD\fR, but if the mismatch is not detected, a zlib error may be returned later instead. Since zlib errors can also be caused by broken compressed data, there is no way to make sure if the password was incorrect or if it was correct, but the compressed data was invalid. ================================================ FILE: external/libzip/man/zip_fopen_encrypted.mdoc ================================================ .\" zip_fopen_encrypted.mdoc -- open encrypted file in zip archive for reading .\" Copyright (C) 2011-2021 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd September 15, 2020 .Dt ZIP_FOPEN_ENCRYPTED 3 .Os .Sh NAME .Nm zip_fopen_encrypted , .Nm zip_fopen_index_encrypted .Nd open encrypted file in zip archive for reading .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft zip_file_t * .Fn zip_fopen_encrypted "zip_t *archive" "const char *fname" "zip_flags_t flags" "const char *password" .Ft zip_file_t * .Fn zip_fopen_index_encrypted "zip_t *archive" "zip_uint64_t index" "zip_flags_t flags" "const char *password" .Sh DESCRIPTION The .Fn zip_fopen_encrypted function opens the encrypted file name .Ar fname in .Ar archive using the password given in the .Ar password argument. If .Ar password is .Dv NULL or the empty string, the default password is used (see .Xr zip_set_default_password 3 ) . The .Ar flags argument are the same as for .Xr zip_fopen 3 . .Pp The .Fn zip_fopen_index_encrypted function opens the file at position .Ar index , see .Xr zip_fopen_index 3 . These functions are called automatically by .Xr zip_fopen 3 ; you only need to call them if you want to specify a non-default password (see .Xr zip_set_default_password 3 ) . .Sh RETURN VALUES Upon successful completion, a .Ft struct zip_file pointer is returned. Otherwise, .Dv NULL is returned and the error code in .Ar archive is set to indicate the error. .Sh ERRORS .Bl -tag -width ZIP_ER_ENCRNOTSUPPXX .It Bq Er ZIP_ER_NOPASSWD No password was provided. .El .Pp The function .Fn zip_fopen_encrypted may also fail and set .Va zip_err for any of the errors specified for the routine .Xr zip_fopen 3 . .Pp The function .Fn zip_fopen_index_encrypted may also fail and set .Va zip_err for any of the errors specified for the routine .Xr zip_fopen_index 3 . .Sh SEE ALSO .Xr libzip 3 , .Xr zip_fclose 3 , .Xr zip_fopen 3 , .Xr zip_fread 3 , .Xr zip_get_num_entries 3 , .Xr zip_name_locate 3 .Sh HISTORY .Fn zip_fopen_encrypted and .Fn zip_fopen_index_encrypted were added in libzip 1.0. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at .Sh CAVEATS The zip file format provides very limited possibility for password verification (a short hash of is compared against one byte in the zip archive). For this reason, reading a file while using an incorrect password may immediately fail with .Er ZIP_ER_WRONGPASSWD , but if the mismatch is not detected, a zlib error may be returned later instead. Since zlib errors can also be caused by broken compressed data, there is no way to make sure if the password was incorrect or if it was correct, but the compressed data was invalid. ================================================ FILE: external/libzip/man/zip_fread.html ================================================ ================================================ FILE: external/libzip/man/zip_fread.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_fread.mdoc -- read from file .\" Copyright (C) 2003-2022 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_FREAD" "3" "September 11, 2024" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_fread\fR \- read from file .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIzip_int64_t\fR .br .PD 0 .HP 4n \fBzip_fread\fR(\fIzip_file_t\ *file\fR, \fIvoid\ *buf\fR, \fIzip_uint64_t\ nbytes\fR); .PD .SH "DESCRIPTION" The \fBzip_fread\fR() function reads up to \fInbytes\fR bytes from \fIfile\fR into \fIbuf\fR from the current position in the file (see zip_fseek(3)). After reading, the current position is updated by the number of bytes read. .SH "RETURN VALUES" If successful, the number of bytes actually read is returned. When \fBzip_fread\fR() is called after reaching the end of the file, 0 is returned. In case of error, \-1 is returned. .SH "SEE ALSO" libzip(3), zip_fclose(3), zip_file_get_error(3), zip_fopen(3), zip_fseek(3) .SH "HISTORY" \fBzip_fread\fR() was added in libzip 0.6. In libzip 0.10 the return type was changed from \fIssize_t\fR to \fIzip_int64_t\fR. In libzip 0.10 the type of \fInbytes\fR was changed from \fIsize_t\fR to \fIzip_uint64_t\fR. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_fread.mdoc ================================================ .\" zip_fread.mdoc -- read from file .\" Copyright (C) 2003-2022 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd September 11, 2024 .Dt ZIP_FREAD 3 .Os .Sh NAME .Nm zip_fread .Nd read from file .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft zip_int64_t .Fn zip_fread "zip_file_t *file" "void *buf" "zip_uint64_t nbytes" .Sh DESCRIPTION The .Fn zip_fread function reads up to .Ar nbytes bytes from .Ar file into .Ar buf from the current position in the file (see .Xr zip_fseek 3 ) . After reading, the current position is updated by the number of bytes read. .Sh RETURN VALUES If successful, the number of bytes actually read is returned. When .Fn zip_fread is called after reaching the end of the file, 0 is returned. In case of error, \-1 is returned. .Sh SEE ALSO .Xr libzip 3 , .Xr zip_fclose 3 , .Xr zip_file_get_error 3 , .Xr zip_fopen 3 , .Xr zip_fseek 3 .Sh HISTORY .Fn zip_fread was added in libzip 0.6. In libzip 0.10 the return type was changed from .Vt ssize_t to .Vt zip_int64_t . In libzip 0.10 the type of .Ar nbytes was changed from .Vt size_t to .Vt zip_uint64_t . .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_fseek.html ================================================ ================================================ FILE: external/libzip/man/zip_fseek.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_fseek.mdoc -- seek in file .\" Copyright (C) 2016-2022 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_FSEEK" "3" "September 11, 2024" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_fseek\fR, \fBzip_file_is_seekable\fR \- seek in file .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIzip_int8_t\fR .br .PD 0 .HP 4n \fBzip_fseek\fR(\fIzip_file_t\ *file\fR, \fIzip_int64_t\ offset\fR, \fIint\ whence\fR); .PD .PP \fIint\fR .br .PD 0 .HP 4n \fBzip_file_is_seekable\fR(\fIzip_file_t\ *file\fR); .PD .SH "DESCRIPTION" The \fBzip_fseek\fR() function seeks to the specified \fIoffset\fR relative to \fIwhence\fR, just like fseek(3). .PP \fBzip_fseek\fR only works on uncompressed (stored), unencrypted data. When called on compressed or encrypted data it will return an error. .PP The \fBzip_file_is_seekable\fR() function returns 1 if a file is seekable. .SH "RETURN VALUES" If successful, \fBzip_fseek\fR() returns 0. Otherwise, \-1 is returned. .PP \fBzip_file_is_seekable\fR() returns 1 if a file is seekable and 0 if not. On an invalid argument, it returns \-1. .SH "SEE ALSO" libzip(3), zip_fclose(3), zip_file_get_error(3), zip_fopen(3), zip_fread(3), zip_ftell(3) .SH "HISTORY" \fBzip_fseek\fR() was added in libzip 1.2.0. \fBzip_file_is_seekable\fR() was added in libzip 1.9.0. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_fseek.mdoc ================================================ .\" zip_fseek.mdoc -- seek in file .\" Copyright (C) 2016-2022 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd September 11, 2024 .Dt ZIP_FSEEK 3 .Os .Sh NAME .Nm zip_fseek , .Nm zip_file_is_seekable .Nd seek in file .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft zip_int8_t .Fn zip_fseek "zip_file_t *file" "zip_int64_t offset" "int whence" .Ft int .Fn zip_file_is_seekable "zip_file_t *file" .Sh DESCRIPTION The .Fn zip_fseek function seeks to the specified .Ar offset relative to .Ar whence , just like .Xr fseek 3 . .Pp .Nm only works on uncompressed (stored), unencrypted data. When called on compressed or encrypted data it will return an error. .Pp The .Fn zip_file_is_seekable function returns 1 if a file is seekable. .Sh RETURN VALUES If successful, .Fn zip_fseek returns 0. Otherwise, \-1 is returned. .Pp .Fn zip_file_is_seekable returns 1 if a file is seekable and 0 if not. On an invalid argument, it returns \-1. .Sh SEE ALSO .Xr libzip 3 , .Xr zip_fclose 3 , .Xr zip_file_get_error 3 , .Xr zip_fopen 3 , .Xr zip_fread 3 , .Xr zip_ftell 3 .Sh HISTORY .Fn zip_fseek was added in libzip 1.2.0. .Fn zip_file_is_seekable was added in libzip 1.9.0. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_ftell.html ================================================ ================================================ FILE: external/libzip/man/zip_ftell.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_ftell.mdoc -- tell position in file .\" Copyright (C) 2016-2021 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_FTELL" "3" "September 11, 2024" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_ftell\fR \- tell position in file .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIzip_int64_t\fR .br .PD 0 .HP 4n \fBzip_ftell\fR(\fIzip_file_t\ *file\fR); .PD .SH "DESCRIPTION" The \fBzip_ftell\fR() function reports the current offset in the file. .SH "RETURN VALUES" If successful, \fBzip_ftell\fR returns the current file position. Otherwise, \-1 is returned. .SH "SEE ALSO" libzip(3), zip_fclose(3), zip_file_get_error(3), zip_fopen(3), zip_fread(3), zip_fseek(3) .SH "HISTORY" \fBzip_ftell\fR() was added in libzip 1.2.0. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_ftell.mdoc ================================================ .\" zip_ftell.mdoc -- tell position in file .\" Copyright (C) 2016-2021 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd September 11, 2024 .Dt ZIP_FTELL 3 .Os .Sh NAME .Nm zip_ftell .Nd tell position in file .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft zip_int64_t .Fn zip_ftell "zip_file_t *file" .Sh DESCRIPTION The .Fn zip_ftell function reports the current offset in the file. .Sh RETURN VALUES If successful, .Nm returns the current file position. Otherwise, \-1 is returned. .Sh SEE ALSO .Xr libzip 3 , .Xr zip_fclose 3 , .Xr zip_file_get_error 3 , .Xr zip_fopen 3 , .Xr zip_fread 3 , .Xr zip_fseek 3 .Sh HISTORY .Fn zip_ftell was added in libzip 1.2.0. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_get_archive_comment.html ================================================ ================================================ FILE: external/libzip/man/zip_get_archive_comment.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_get_archive_comment.mdoc -- get zip archive comment .\" Copyright (C) 2006-2021 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_GET_ARCHIVE_COMMENT" "3" "September 22, 2020" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_get_archive_comment\fR \- get zip archive comment .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIconst char *\fR .br .PD 0 .HP 4n \fBzip_get_archive_comment\fR(\fIzip_t\ *archive\fR, \fIint\ *lenp\fR, \fIzip_flags_t\ flags\fR); .PD .SH "DESCRIPTION" The \fBzip_get_archive_comment\fR() function returns the comment for the entire zip archive. The return value is in UTF-8 encoding unless \fRZIP_FL_ENC_RAW\fR was specified (see below). This pointer should not be modified or free(3)'d, and becomes invalid when \fIarchive\fR is closed. If \fIlenp\fR is not \fRNULL\fR, the integer to which it points will be set to the length of the comment. If \fIflags\fR is set to \fRZIP_FL_UNCHANGED\fR, the original unchanged comment is returned. .PP Additionally, the following \fIflags\fR are supported: .RS 6n .TP 21n \fRZIP_FL_ENC_RAW\fR Return the unmodified archive comment as it is in the ZIP archive. .TP 21n \fRZIP_FL_ENC_GUESS\fR (Default.) Guess the encoding of the archive comment in the ZIP archive and convert it to UTF-8, if necessary. (Only CP-437 and UTF-8 are recognized.) .TP 21n \fRZIP_FL_ENC_STRICT\fR Follow the ZIP specification for file names and extend it to the archive comment, thus also expecting it in CP-437 encoding. Convert it to UTF-8. .RE \fINote\fR: ASCII is a subset of both CP-437 and UTF-8. .SH "RETURN VALUES" Upon successful completion, a pointer to the comment is returned, or \fRNULL\fR if there is no comment. .SH "SEE ALSO" libzip(3), zip_file_get_comment(3) .SH "HISTORY" \fBzip_get_archive_comment\fR() was added in libzip 0.7. In libzip 0.11 the type of \fIflags\fR was changed from \fIint\fR to \fIzip_flags_t\fR. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_get_archive_comment.mdoc ================================================ .\" zip_get_archive_comment.mdoc -- get zip archive comment .\" Copyright (C) 2006-2021 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd September 22, 2020 .Dt ZIP_GET_ARCHIVE_COMMENT 3 .Os .Sh NAME .Nm zip_get_archive_comment .Nd get zip archive comment .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft const char * .Fn zip_get_archive_comment "zip_t *archive" "int *lenp" "zip_flags_t flags" .Sh DESCRIPTION The .Fn zip_get_archive_comment function returns the comment for the entire zip archive. The return value is in UTF-8 encoding unless .Dv ZIP_FL_ENC_RAW was specified (see below). This pointer should not be modified or .Xr free 3 Ap d , and becomes invalid when .Ar archive is closed. If .Ar lenp is not .Dv NULL , the integer to which it points will be set to the length of the comment. If .Ar flags is set to .Dv ZIP_FL_UNCHANGED , the original unchanged comment is returned. .Pp Additionally, the following .Ar flags are supported: .Bl -tag -width ZIP_FL_ENC_STRICTXX -offset indent .It Dv ZIP_FL_ENC_RAW Return the unmodified archive comment as it is in the ZIP archive. .It Dv ZIP_FL_ENC_GUESS (Default.) Guess the encoding of the archive comment in the ZIP archive and convert it to UTF-8, if necessary. (Only CP-437 and UTF-8 are recognized.) .It Dv ZIP_FL_ENC_STRICT Follow the ZIP specification for file names and extend it to the archive comment, thus also expecting it in CP-437 encoding. Convert it to UTF-8. .El .Em Note : ASCII is a subset of both CP-437 and UTF-8. .Sh RETURN VALUES Upon successful completion, a pointer to the comment is returned, or .Dv NULL if there is no comment. .\" In case of an error, .\" .Dv NULL .\" is returned and the error code in .\" .Ar archive .\" is set to indicate the error. .Sh SEE ALSO .Xr libzip 3 , .Xr zip_file_get_comment 3 .Sh HISTORY .Fn zip_get_archive_comment was added in libzip 0.7. In libzip 0.11 the type of .Ar flags was changed from .Vt int to .Vt zip_flags_t . .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_get_archive_flag.html ================================================ ================================================ FILE: external/libzip/man/zip_get_archive_flag.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_get_archive_flag.mdoc -- get comment for file in zip .\" Copyright (C) 2008-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP files. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_GET_ARCHIVE_FLAG" "3" "January 23, 2023" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_get_archive_flag\fR \- get status flags for zip .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIint\fR .br .PD 0 .HP 4n \fBzip_get_archive_flag\fR(\fIzip_t\ *archive\fR, \fIzip_flags_t\ flag\fR, \fIzip_flags_t\ flags\fR); .PD .SH "DESCRIPTION" The \fBzip_get_archive_flag\fR() function returns if the flag \fIflag\fR is set for the archive \fIarchive\fR. The archive flags might have been changed with \fBzip_set_archive_flag\fR(); if \fIflags\fR is set to \fRZIP_FL_UNCHANGED\fR, the original unchanged flags are tested. .PP Supported flags are: .TP 20n \fRZIP_AFL_CREATE_OR_KEEP_FILE_FOR_EMPTY_ARCHIVE\fR If this flag is cleared, the archive file will be removed if the archive is empty. If it is set, an empty archive will be created, which is not recommended by the zip specification. This flag is always cleared unless explicitly set by the user with zip_set_archive_flag(3). .TP 20n \fRZIP_AFL_IS_TORRENTZIP\fR The archive is in torrentzip format. .TP 20n \fRZIP_AFL_RDONLY\fR The archive is read-only. .TP 20n \fRZIP_AFL_WANT_TORRENTZIP\fR If the flag is set, the archive will be written in torrentzip format. This flag is always cleared unless explicitly set by the user with zip_set_archive_flag(3). .SH "RETURN VALUES" \fBzip_get_archive_flag\fR() returns 1 if \fIflag\fR is set for \fIarchive\fR, 0 if not, and \-1 if an error occurred. .SH "SEE ALSO" libzip(3), zip_set_archive_flag(3) .SH "HISTORY" \fBzip_get_archive_flag\fR() was added in libzip 0.9. In libzip 0.11 the type of \fIflag\fR was changed from \fIint\fR to \fIzip_flags_t m\fR and the type of \fIflags\fR was changed from \fIint\fR to \fIzip_flags_t\fR. \fRZIP_AFL_CREATE_OR_KEEP_FILE_FOR_EMPTY_ARCHIVE\fR, \fRZIP_AFL_IS_TORRENTZIP\fR, and \fRZIP_AFL_WANT_TORRENTZIP\fR were added in libzip 1.10.0. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_get_archive_flag.mdoc ================================================ .\" zip_get_archive_flag.mdoc -- get comment for file in zip .\" Copyright (C) 2008-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP files. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd January 23, 2023 .Dt ZIP_GET_ARCHIVE_FLAG 3 .Os .Sh NAME .Nm zip_get_archive_flag .Nd get status flags for zip .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft int .Fn zip_get_archive_flag "zip_t *archive" "zip_flags_t flag" "zip_flags_t flags" .Sh DESCRIPTION The .Fn zip_get_archive_flag function returns if the flag .Ar flag is set for the archive .Ar archive . The archive flags might have been changed with .Fn zip_set_archive_flag ; if .Ar flags is set to .Dv ZIP_FL_UNCHANGED , the original unchanged flags are tested. .Pp Supported flags are: .Bl -tag -width XZIPXAFLXRDONLYXXX .It Dv ZIP_AFL_CREATE_OR_KEEP_FILE_FOR_EMPTY_ARCHIVE If this flag is cleared, the archive file will be removed if the archive is empty. If it is set, an empty archive will be created, which is not recommended by the zip specification. This flag is always cleared unless explicitly set by the user with .Xr zip_set_archive_flag 3 . .It Dv ZIP_AFL_IS_TORRENTZIP The archive is in torrentzip format. .It Dv ZIP_AFL_RDONLY The archive is read-only. .It Dv ZIP_AFL_WANT_TORRENTZIP If the flag is set, the archive will be written in torrentzip format. This flag is always cleared unless explicitly set by the user with .Xr zip_set_archive_flag 3 . .El .Sh RETURN VALUES .Fn zip_get_archive_flag returns 1 if .Ar flag is set for .Ar archive , 0 if not, and \-1 if an error occurred. .Sh SEE ALSO .Xr libzip 3 , .Xr zip_set_archive_flag 3 .Sh HISTORY .Fn zip_get_archive_flag was added in libzip 0.9. In libzip 0.11 the type of .Ar flag was changed from .Vt int to .Vt zip_flags_t m and the type of .Ar flags was changed from .Vt int to .Vt zip_flags_t . .Dv ZIP_AFL_CREATE_OR_KEEP_FILE_FOR_EMPTY_ARCHIVE , .Dv ZIP_AFL_IS_TORRENTZIP , and .Dv ZIP_AFL_WANT_TORRENTZIP were added in libzip 1.10.0. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_get_error.html ================================================ ================================================ FILE: external/libzip/man/zip_get_error.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_get_error.mdoc -- get zip_error for archive .\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_GET_ERROR" "3" "December 18, 2017" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_get_error\fR \- get zip error for archive .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIzip_error_t *\fR .br .PD 0 .HP 4n \fBzip_get_error\fR(\fIzip_t\ *archive\fR); .PD .SH "DESCRIPTION" The \fBzip_get_error\fR() function returns the zip error for the zip archive \fIarchive\fR. .SH "SEE ALSO" libzip(3), zip_error_code_system(3), zip_error_code_zip(3) .SH "HISTORY" \fBzip_get_error\fR() was added in libzip 1.0. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_get_error.mdoc ================================================ .\" zip_get_error.mdoc -- get zip_error for archive .\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd December 18, 2017 .Dt ZIP_GET_ERROR 3 .Os .Sh NAME .Nm zip_get_error .Nd get zip error for archive .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft zip_error_t * .Fn zip_get_error "zip_t *archive" .Sh DESCRIPTION The .Fn zip_get_error function returns the zip error for the zip archive .Ar archive . .Sh SEE ALSO .Xr libzip 3 , .Xr zip_error_code_system 3 , .Xr zip_error_code_zip 3 .Sh HISTORY .Fn zip_get_error was added in libzip 1.0. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_get_file_comment.html ================================================ ================================================ FILE: external/libzip/man/zip_get_file_comment.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_get_file_comment.mdoc -- get comment for file in zip .\" Copyright (C) 2006-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP files. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_GET_FILE_COMMENT" "3" "December 18, 2017" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_get_file_comment\fR \- get comment for file in zip (obsolete interface) .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIconst char *\fR .br .PD 0 .HP 4n \fBzip_get_file_comment\fR(\fIzip_t\ *archive\fR, \fIzip_uint64_t\ index\fR, \fIint\ *lenp\fR, \fIint\ flags\fR); .PD .SH "DESCRIPTION" The \fBzip_get_file_comment\fR() function is the obsolete version of zip_file_get_comment(3). The only differences are the types of the \fIlenp\fR and \fIflags\fR arguments. .SH "SEE ALSO" libzip(3), zip_file_get_comment(3) .SH "HISTORY" \fBzip_get_file_comment\fR() was added in libzip 0.7. In libzip 0.10 the type of \fIindex\fR was changed from \fIint\fR to \fIzip_uint64_t\fR. It was deprecated in libzip 0.11, use \fBzip_file_get_comment\fR() instead. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_get_file_comment.mdoc ================================================ .\" zip_get_file_comment.mdoc -- get comment for file in zip .\" Copyright (C) 2006-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP files. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd December 18, 2017 .Dt ZIP_GET_FILE_COMMENT 3 .Os .Sh NAME .Nm zip_get_file_comment .Nd get comment for file in zip (obsolete interface) .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft const char * .Fn zip_get_file_comment "zip_t *archive" "zip_uint64_t index" "int *lenp" "int flags" .Sh DESCRIPTION The .Fn zip_get_file_comment function is the obsolete version of .Xr zip_file_get_comment 3 . The only differences are the types of the .Ar lenp and .Ar flags arguments. .Sh SEE ALSO .Xr libzip 3 , .Xr zip_file_get_comment 3 .Sh HISTORY .Fn zip_get_file_comment was added in libzip 0.7. In libzip 0.10 the type of .Ar index was changed from .Vt int to .Vt zip_uint64_t . It was deprecated in libzip 0.11, use .Fn zip_file_get_comment instead. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_get_name.html ================================================ ================================================ FILE: external/libzip/man/zip_get_name.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_get_name.mdoc -- get name of file by index .\" Copyright (C) 2003-2021 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_GET_NAME" "3" "September 22, 2020" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_get_name\fR \- get name of file by index .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIconst char *\fR .br .PD 0 .HP 4n \fBzip_get_name\fR(\fIzip_t\ *archive\fR, \fIzip_uint64_t\ index\fR, \fIzip_flags_t\ flags\fR); .PD .SH "DESCRIPTION" The \fBzip_get_name\fR() function returns the name of the file at position \fIindex\fR in \fIarchive\fR. The name is in UTF-8 encoding unless \fRZIP_FL_ENC_RAW\fR was specified (see below). .PP If \fIflags\fR is set to \fRZIP_FL_UNCHANGED\fR, the original unchanged filename is returned. The returned string must not be modified or freed, and becomes invalid when \fIarchive\fR is closed. .PP Additionally, the following \fIflags\fR are supported: .RS 6n .TP 21n \fRZIP_FL_ENC_RAW\fR Return the unmodified names as it is in the ZIP archive. .TP 21n \fRZIP_FL_ENC_GUESS\fR (Default.) Guess the encoding of the name in the ZIP archive and convert it to UTF-8, if necessary. (Only CP-437 and UTF-8 are recognized.) .TP 21n \fRZIP_FL_ENC_STRICT\fR Follow the ZIP specification and expect CP-437 encoded names in the ZIP archive (except if they are explicitly marked as UTF-8). Convert it to UTF-8. .RE \fINote\fR: ASCII is a subset of both CP-437 and UTF-8. .SH "RETURN VALUES" Upon successful completion, a pointer to the name is returned. Otherwise, \fRNULL\fR and the error code in \fIarchive\fR is set to indicate the error. .SH "ERRORS" \fBzip_get_name\fR() fails if: .TP 19n [\fRZIP_ER_DELETED\fR] \fIindex\fR refers to a file that has been deleted (see zip_delete(3)). .TP 19n [\fRZIP_ER_INVAL\fR] \fIindex\fR is not a valid file index in \fIarchive\fR, or \fIindex\fR points to an added file and \fRZIP_FL_UNCHANGED\fR is set. .TP 19n [\fRZIP_ER_MEMORY\fR] Required memory could not be allocated. .SH "SEE ALSO" libzip(3), zip_name_locate(3) .SH "HISTORY" \fBzip_get_name\fR() was added in libzip 0.6. In libzip 0.10 the type of \fIindex\fR was changed from \fIint\fR to \fIzip_uint64_t\fR. In libzip 0.11 the type of \fIflags\fR was changed from \fIint\fR to \fIzip_flags_t\fR. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_get_name.mdoc ================================================ .\" zip_get_name.mdoc -- get name of file by index .\" Copyright (C) 2003-2021 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd September 22, 2020 .Dt ZIP_GET_NAME 3 .Os .Sh NAME .Nm zip_get_name .Nd get name of file by index .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft const char * .Fn zip_get_name "zip_t *archive" "zip_uint64_t index" "zip_flags_t flags" .Sh DESCRIPTION The .Fn zip_get_name function returns the name of the file at position .Ar index in .Ar archive . The name is in UTF-8 encoding unless .Dv ZIP_FL_ENC_RAW was specified (see below). .Pp If .Ar flags is set to .Dv ZIP_FL_UNCHANGED , the original unchanged filename is returned. The returned string must not be modified or freed, and becomes invalid when .Ar archive is closed. .Pp Additionally, the following .Ar flags are supported: .Bl -tag -width ZIP_FL_ENC_STRICTXX -offset indent .It Dv ZIP_FL_ENC_RAW Return the unmodified names as it is in the ZIP archive. .It Dv ZIP_FL_ENC_GUESS (Default.) Guess the encoding of the name in the ZIP archive and convert it to UTF-8, if necessary. (Only CP-437 and UTF-8 are recognized.) .It Dv ZIP_FL_ENC_STRICT Follow the ZIP specification and expect CP-437 encoded names in the ZIP archive (except if they are explicitly marked as UTF-8). Convert it to UTF-8. .El .Em Note : ASCII is a subset of both CP-437 and UTF-8. .Sh RETURN VALUES Upon successful completion, a pointer to the name is returned. Otherwise, .Dv NULL and the error code in .Ar archive is set to indicate the error. .Sh ERRORS .Fn zip_get_name fails if: .Bl -tag -width Er .It Bq Er ZIP_ER_DELETED .Ar index refers to a file that has been deleted (see .Xr zip_delete 3 ) . .It Bq Er ZIP_ER_INVAL .Ar index is not a valid file index in .Ar archive , or .Ar index points to an added file and .Dv ZIP_FL_UNCHANGED is set. .It Bq Er ZIP_ER_MEMORY Required memory could not be allocated. .El .Sh SEE ALSO .Xr libzip 3 , .Xr zip_name_locate 3 .Sh HISTORY .Fn zip_get_name was added in libzip 0.6. In libzip 0.10 the type of .Ar index was changed from .Vt int to .Vt zip_uint64_t . In libzip 0.11 the type of .Ar flags was changed from .Vt int to .Vt zip_flags_t . .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_get_num_entries.html ================================================ ================================================ FILE: external/libzip/man/zip_get_num_entries.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_get_num_entries.mdoc -- get number of files in archive .\" Copyright (C) 2011-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_GET_NUM_ENTRIES" "3" "August 19, 2022" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_get_num_entries\fR \- get number of entries in archive .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIzip_int64_t\fR .br .PD 0 .HP 4n \fBzip_get_num_entries\fR(\fIzip_t\ *archive\fR, \fIzip_flags_t\ flags\fR); .PD .SH "DESCRIPTION" The \fBzip_get_num_entries\fR() function returns the number of entries in \fIarchive\fR. Entries are all files that are present in the original archive or that were added while the archive is open. This includes deleted files, since indices are not renumbered until the archive is closed. (This allows one to refer to deleted files, e. g. to undelete them.) .PP If \fIflags\fR is set to \fRZIP_FL_UNCHANGED\fR, the original number of files is returned. .SH "RETURN VALUES" \fBzip_get_num_entries\fR() returns the number of entries in the zip archive, or \-1 if \fIarchive\fR is \fRNULL\fR. .SH "SEE ALSO" libzip(3), zip_fopen_index(3), zip_stat_index(3) .SH "HISTORY" \fBzip_get_num_entries\fR() was added in libzip 0.10. In libzip 0.11 the return type was changed from \fIzip_uint64_t\fR to \fIzip_int64_t\fR. In libzip 0.11 the type of \fIflags\fR was changed from \fIint\fR to \fIzip_flags_t\fR. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_get_num_entries.mdoc ================================================ .\" zip_get_num_entries.mdoc -- get number of files in archive .\" Copyright (C) 2011-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd August 19, 2022 .Dt ZIP_GET_NUM_ENTRIES 3 .Os .Sh NAME .Nm zip_get_num_entries .Nd get number of entries in archive .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft zip_int64_t .Fn zip_get_num_entries "zip_t *archive" "zip_flags_t flags" .Sh DESCRIPTION The .Fn zip_get_num_entries function returns the number of entries in .Ar archive . Entries are all files that are present in the original archive or that were added while the archive is open. This includes deleted files, since indices are not renumbered until the archive is closed. (This allows one to refer to deleted files, e. g. to undelete them.) .Pp If .Ar flags is set to .Dv ZIP_FL_UNCHANGED , the original number of files is returned. .Sh RETURN VALUES .Fn zip_get_num_entries returns the number of entries in the zip archive, or \-1 if .Ar archive is .Dv NULL . .Sh SEE ALSO .Xr libzip 3 , .Xr zip_fopen_index 3 , .Xr zip_stat_index 3 .Sh HISTORY .Fn zip_get_num_entries was added in libzip 0.10. In libzip 0.11 the return type was changed from .Vt zip_uint64_t to .Vt zip_int64_t . In libzip 0.11 the type of .Ar flags was changed from .Vt int to .Vt zip_flags_t . .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_get_num_files.html ================================================ ================================================ FILE: external/libzip/man/zip_get_num_files.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_get_num_files.mdoc -- get number of files in archive .\" Copyright (C) 2003-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_GET_NUM_FILES" "3" "December 18, 2017" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_get_num_files\fR \- get number of files in archive (obsolete interface) .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIint\fR .br .PD 0 .HP 4n \fBzip_get_num_files\fR(\fIzip_t\ *archive\fR); .PD .SH "DESCRIPTION" \fIThis function is deprecated\fR. \fIUse\fR zip_get_num_entries(3) \fIinstead\fR. .PP The \fBzip_get_num_files\fR() function returns the number of files in \fIarchive\fR. .SH "RETURN VALUES" \fBzip_get_num_files\fR() returns the number of files in the zip archive, or \-1 if \fIarchive\fR is \fRNULL\fR. .SH "SEE ALSO" libzip(3), zip_fopen_index(3), zip_stat_index(3) .SH "HISTORY" \fBzip_get_num_files\fR() was added in libzip 0.6. It was deprecated in libzip 0.11, use \fBzip_get_num_entries\fR(\fIinstead\fR) instead. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_get_num_files.mdoc ================================================ .\" zip_get_num_files.mdoc -- get number of files in archive .\" Copyright (C) 2003-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd December 18, 2017 .Dt ZIP_GET_NUM_FILES 3 .Os .Sh NAME .Nm zip_get_num_files .Nd get number of files in archive (obsolete interface) .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft int .Fn zip_get_num_files "zip_t *archive" .Sh DESCRIPTION .Em This function is deprecated . .Em Use .Xr zip_get_num_entries 3 .Em instead . .Pp The .Fn zip_get_num_files function returns the number of files in .Ar archive . .Sh RETURN VALUES .Fn zip_get_num_files returns the number of files in the zip archive, or \-1 if .Ar archive is .Dv NULL . .Sh SEE ALSO .Xr libzip 3 , .Xr zip_fopen_index 3 , .Xr zip_stat_index 3 .Sh HISTORY .Fn zip_get_num_files was added in libzip 0.6. It was deprecated in libzip 0.11, use .Fn zip_get_num_entries instead instead. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_libzip_version.html ================================================ ================================================ FILE: external/libzip/man/zip_libzip_version.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_libzip_version.mdoc -- return run-time version of library .\" Copyright (C) 2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_LIBZIP_VERSION" "3" "December 18, 2017" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_libzip_version\fR \- return run-time version of library .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIconst char *\fR .br .PD 0 .HP 4n \fBzip_libzip_version\fR(\fIvoid\fR); .PD .SH "DESCRIPTION" \fBzip_libzip_version\fR returns the version number of the library as string in the format \(lq$MAJOR.$MINOR.$MICRO$SUFFIX\(rq where \fI$MAJOR\fR is the major version, \fI$MINOR\fR the minor, \fI$MICRO\fR the micro, and \fI$SUFFIX\fR a suffix that's only set for development versions. .SH "SEE ALSO" libzip(3) .SH "HISTORY" \fBzip_libzip_version\fR() was added in libzip 1.3.1. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_libzip_version.mdoc ================================================ .\" zip_libzip_version.mdoc -- return run-time version of library .\" Copyright (C) 2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd December 18, 2017 .Dt ZIP_LIBZIP_VERSION 3 .Os .Sh NAME .Nm zip_libzip_version .Nd return run-time version of library .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft const char * .Fn zip_libzip_version void .Sh DESCRIPTION .Nm returns the version number of the library as string in the format .Dq $MAJOR.$MINOR.$MICRO$SUFFIX where .Ar $MAJOR is the major version, .Ar $MINOR the minor, .Ar $MICRO the micro, and .Ar $SUFFIX a suffix that's only set for development versions. .Sh SEE ALSO .Xr libzip 3 .Sh HISTORY .Fn zip_libzip_version was added in libzip 1.3.1. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_name_locate.html ================================================ ================================================ FILE: external/libzip/man/zip_name_locate.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_name_locate.mdoc -- get index of file by name .\" Copyright (C) 2003-2022 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_NAME_LOCATE" "3" "March 15, 2022" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_name_locate\fR \- get index of file by name .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIzip_int64_t\fR .br .PD 0 .HP 4n \fBzip_name_locate\fR(\fIzip_t\ *archive\fR, \fIconst\ char\ *fname\fR, \fIzip_flags_t\ flags\fR); .PD .SH "DESCRIPTION" The \fBzip_name_locate\fR() function returns the index of the file named \fIfname\fR in \fIarchive\fR. If \fIarchive\fR does not contain a file with that name, \-1 is returned. .PP If neither \fRZIP_FL_ENC_RAW\fR nor \fRZIP_FL_ENC_STRICT\fR are specified, guess the encoding of the name in the ZIP archive and convert it to UTF-8, if necessary, before comparing. .PP If neither \fRZIP_FL_ENC_CP437\fR nor \fRZIP_FL_ENC_UTF_8\fR are specified, guess the encoding of \fIfname\fR. .PP Only CP-437 and UTF-8 are recognized. .PP The \fIflags\fR are specified by \fIor\fR'ing the following values, or 0 for none of them. .RS 6n .TP 19n \fRZIP_FL_NOCASE\fR Ignore case distinctions. (Will only work well if the file names are ASCII.) With this flag, \fBzip_name_locate\fR() will be slow for archives with many files. .TP 19n \fRZIP_FL_NODIR\fR Ignore directory part of file name in archive. With this flag, \fBzip_name_locate\fR() will be slow for archives with many files. .TP 19n \fRZIP_FL_ENC_GUESS\fR This flag has no effect (its value is 0); it can be used to explicitly denote the absence of encoding flags. .TP 19n \fRZIP_FL_ENC_RAW\fR Compare \fIfname\fR against the unmodified names as they are in the ZIP archive, without converting them to UTF-8. .TP 19n \fRZIP_FL_ENC_STRICT\fR Follow the ZIP specification and expect CP-437 encoded names in the ZIP archive (except if they are explicitly marked as UTF-8). Convert them to UTF-8 before comparing. .TP 19n \fRZIP_FL_ENC_CP437\fR \fIfname\fR is encoded as CP-437. .TP 19n \fRZIP_FL_ENC_UTF_8\fR \fIfname\fR is encoded as UTF-8. .RE .PP \fINote\fR: ASCII is a subset of both CP-437 and UTF-8. .SH "RETURN VALUES" \fBzip_name_locate\fR() returns the index of the file named \fIfname\fR or \-1, if \fIarchive\fR does not contain an entry of that name. .SH "ERRORS" \fBzip_name_locate\fR() fails if: .TP 19n [\fRZIP_ER_INVAL\fR] One of the arguments is invalid. .TP 19n [\fRZIP_ER_MEMORY\fR] Required memory could not be allocated. .TP 19n [\fRZIP_ER_NOENT\fR] No entry of the name \fIfname\fR is found in the archive. .SH "SEE ALSO" libzip(3), zip_get_name(3) .SH "HISTORY" \fBzip_name_locate\fR() was added in libzip 0.6. In libzip 0.11 the return type was changed from \fIint\fR to \fIzip_int64_t\fR. In libzip 0.11 the type of \fIflags\fR was changed from \fIint\fR to \fIzip_flags_t\fR. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_name_locate.mdoc ================================================ .\" zip_name_locate.mdoc -- get index of file by name .\" Copyright (C) 2003-2022 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd March 15, 2022 .Dt ZIP_NAME_LOCATE 3 .Os .Sh NAME .Nm zip_name_locate .Nd get index of file by name .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft zip_int64_t .Fn zip_name_locate "zip_t *archive" "const char *fname" "zip_flags_t flags" .Sh DESCRIPTION The .Fn zip_name_locate function returns the index of the file named .Ar fname in .Ar archive . If .Ar archive does not contain a file with that name, \-1 is returned. .Pp If neither .Dv ZIP_FL_ENC_RAW nor .Dv ZIP_FL_ENC_STRICT are specified, guess the encoding of the name in the ZIP archive and convert it to UTF-8, if necessary, before comparing. .Pp If neither .Dv ZIP_FL_ENC_CP437 nor .Dv ZIP_FL_ENC_UTF_8 are specified, guess the encoding of .Ar fname . .Pp Only CP-437 and UTF-8 are recognized. .Pp The .Fa flags are specified by .Em or Ns No 'ing the following values, or 0 for none of them. .Bl -tag -offset indent -width ZIP_FL_ENC_STRICT .It Dv ZIP_FL_NOCASE Ignore case distinctions. (Will only work well if the file names are ASCII.) With this flag, .Fn zip_name_locate will be slow for archives with many files. .It Dv ZIP_FL_NODIR Ignore directory part of file name in archive. With this flag, .Fn zip_name_locate will be slow for archives with many files. .It Dv ZIP_FL_ENC_GUESS This flag has no effect (its value is 0); it can be used to explicitly denote the absence of encoding flags. .It Dv ZIP_FL_ENC_RAW Compare .Ar fname against the unmodified names as they are in the ZIP archive, without converting them to UTF-8. .It Dv ZIP_FL_ENC_STRICT Follow the ZIP specification and expect CP-437 encoded names in the ZIP archive (except if they are explicitly marked as UTF-8). Convert them to UTF-8 before comparing. .It Dv ZIP_FL_ENC_CP437 .Ar fname is encoded as CP-437. .It Dv ZIP_FL_ENC_UTF_8 .Ar fname is encoded as UTF-8. .El .Pp .Em Note : ASCII is a subset of both CP-437 and UTF-8. .Sh RETURN VALUES .Fn zip_name_locate returns the index of the file named .Ar fname or \-1, if .Ar archive does not contain an entry of that name. .Sh ERRORS .Fn zip_name_locate fails if: .Bl -tag -width Er .It Bq Er ZIP_ER_INVAL One of the arguments is invalid. .It Bq Er ZIP_ER_MEMORY Required memory could not be allocated. .It Bq Er ZIP_ER_NOENT No entry of the name .Ar fname is found in the archive. .El .Sh SEE ALSO .Xr libzip 3 , .Xr zip_get_name 3 .Sh HISTORY .Fn zip_name_locate was added in libzip 0.6. In libzip 0.11 the return type was changed from .Vt int to .Vt zip_int64_t . In libzip 0.11 the type of .Ar flags was changed from .Vt int to .Vt zip_flags_t . .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_open.html ================================================ ================================================ FILE: external/libzip/man/zip_open.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_open.mdoc -- open zip archive .\" Copyright (C) 2003-2022 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_OPEN" "3" "May 5, 2025" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_open\fR, \fBzip_open_from_source\fR \- open zip archive .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIzip_t *\fR .br .PD 0 .HP 4n \fBzip_open\fR(\fIconst\ char\ *path\fR, \fIint\ flags\fR, \fIint\ *errorp\fR); .PD .PP \fIzip_t *\fR .br .PD 0 .HP 4n \fBzip_open_from_source\fR(\fIzip_source_t\ *zs\fR, \fIint\ flags\fR, \fIzip_error_t\ *ze\fR); .PD .SH "DESCRIPTION" The \fBzip_open\fR() function opens the zip archive specified by \fIpath\fR and returns a pointer to a \fIstruct zip\fR, used to manipulate the archive. The \fIflags\fR are specified by \fIor\fR'ing the following values, or 0 for none of them. .RS 6n .TP 15n \fRZIP_CHECKCONS\fR Perform additional stricter consistency checks on the archive, and error if they fail. .TP 15n \fRZIP_CREATE\fR Create the archive if it does not exist. .TP 15n \fRZIP_EXCL\fR Error if archive already exists. .TP 15n \fRZIP_TRUNCATE\fR If archive exists, ignore its current contents. In other words, handle it the same way as an empty archive. .TP 15n \fRZIP_RDONLY\fR Open archive in read-only mode. .RE .PP If an error occurs and \fIerrorp\fR is non-\fRNULL\fR, it will be set to the corresponding error code. .PP The \fBzip_open_from_source\fR() function opens a zip archive encapsulated by the zip_source \fIzs\fR using the provided \fIflags\fR. In case of error, the zip_error \fIze\fR is filled in. .SH "RETURN VALUES" Upon successful completion \fBzip_open\fR() and \fBzip_open_from_source\fR() return a \fIstruct zip\fR pointer. Otherwise, \fRNULL\fR is returned and \fBzip_open\fR() sets \fI*errorp\fR to indicate the error, while \fBzip_open_from\fR(\fIsource\fR) sets \fIze\fR to indicate the error. .SH "EXAMPLES" Here's an example of how you could report errors during \fBzip_open\fR: .nf .sp .RS 0n zip_t *za; int err; if ((za = zip_open(name, 0, &err)) == NULL) { zip_error_t error; zip_error_init_with_code(&error, err); fprintf(stderr, "%s: cannot open zip archive '%s': %s\en", progname, name, zip_error_strerror(&error)); zip_error_fini(&error); return -1; } .RE .fi .SH "ERRORS" The archive specified by \fIpath\fR is opened unless: .TP 19n [\fRZIP_ER_EXISTS\fR] The file specified by \fIpath\fR exists and \fRZIP_EXCL\fR is set. .TP 19n [\fRZIP_ER_INCONS\fR] Inconsistencies were found in the file specified by \fIpath\fR. This error is often caused by specifying \fRZIP_CHECKCONS\fR but can also happen without it. .TP 19n [\fRZIP_ER_INVAL\fR] The \fIpath\fR argument is \fRNULL\fR. .TP 19n [\fRZIP_ER_MEMORY\fR] Required memory could not be allocated. .TP 19n [\fRZIP_ER_NOENT\fR] The file specified by \fIpath\fR does not exist and \fRZIP_CREATE\fR is not set. .TP 19n [\fRZIP_ER_NOZIP\fR] The file specified by \fIpath\fR is not a zip archive. .TP 19n [\fRZIP_ER_OPEN\fR] The file specified by \fIpath\fR could not be opened. .TP 19n [\fRZIP_ER_READ\fR] A read error occurred; see \fIerrno\fR for details. .TP 19n [\fRZIP_ER_SEEK\fR] The file specified by \fIpath\fR does not allow seeks. .PD 0 .PP For newly created archives, \fBzip_open\fR() does not try to create the file; this is done when calling zip_close(3) and any errors, like missing write permissions, will be reported then. .PD .SH "SEE ALSO" libzip(3), zip_close(3), zip_error_strerror(3), zip_fdopen(3), zip_source(5) .SH "HISTORY" \fBzip_open\fR() and \fBzip_open_from_source\fR() were added in libzip 1.0. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_open.mdoc ================================================ .\" zip_open.mdoc -- open zip archive .\" Copyright (C) 2003-2022 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd May 5, 2025 .Dt ZIP_OPEN 3 .Os .Sh NAME .Nm zip_open , .Nm zip_open_from_source .Nd open zip archive .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft zip_t * .Fn zip_open "const char *path" "int flags" "int *errorp" .Ft zip_t * .Fn zip_open_from_source "zip_source_t *zs" "int flags" "zip_error_t *ze" .Sh DESCRIPTION The .Fn zip_open function opens the zip archive specified by .Ar path and returns a pointer to a .Ft struct zip , used to manipulate the archive. The .Fa flags are specified by .Em or Ns No 'ing the following values, or 0 for none of them. .Bl -tag -offset indent -width ZIP_CHECKCONS .It Dv ZIP_CHECKCONS Perform additional stricter consistency checks on the archive, and error if they fail. .It Dv ZIP_CREATE Create the archive if it does not exist. .It Dv ZIP_EXCL Error if archive already exists. .It Dv ZIP_TRUNCATE If archive exists, ignore its current contents. In other words, handle it the same way as an empty archive. .It Dv ZIP_RDONLY Open archive in read-only mode. .El .Pp If an error occurs and .Ar errorp is .Pf non- Dv NULL , it will be set to the corresponding error code. .Pp The .Fn zip_open_from_source function opens a zip archive encapsulated by the zip_source .Fa zs using the provided .Fa flags . In case of error, the zip_error .Fa ze is filled in. .Sh RETURN VALUES Upon successful completion .Fn zip_open and .Fn zip_open_from_source return a .Ft struct zip pointer. Otherwise, .Dv NULL is returned and .Fn zip_open sets .Ar *errorp to indicate the error, while .Fn zip_open_from source sets .Ar ze to indicate the error. .Sh EXAMPLES Here's an example of how you could report errors during .Nm : .Bd -literal zip_t *za; int err; if ((za = zip_open(name, 0, &err)) == NULL) { zip_error_t error; zip_error_init_with_code(&error, err); fprintf(stderr, "%s: cannot open zip archive '%s': %s\en", progname, name, zip_error_strerror(&error)); zip_error_fini(&error); return -1; } .Ed .Sh ERRORS The archive specified by .Ar path is opened unless: .Bl -tag -width Er .It Bq Er ZIP_ER_EXISTS The file specified by .Ar path exists and .Dv ZIP_EXCL is set. .It Bq Er ZIP_ER_INCONS Inconsistencies were found in the file specified by .Ar path . This error is often caused by specifying .Dv ZIP_CHECKCONS but can also happen without it. .It Bq Er ZIP_ER_INVAL The .Ar path argument is .Dv NULL . .It Bq Er ZIP_ER_MEMORY Required memory could not be allocated. .It Bq Er ZIP_ER_NOENT The file specified by .Ar path does not exist and .Dv ZIP_CREATE is not set. .It Bq Er ZIP_ER_NOZIP The file specified by .Ar path is not a zip archive. .It Bq Er ZIP_ER_OPEN The file specified by .Ar path could not be opened. .It Bq Er ZIP_ER_READ A read error occurred; see .Va errno for details. .It Bq Er ZIP_ER_SEEK The file specified by .Ar path does not allow seeks. .El For newly created archives, .Fn zip_open does not try to create the file; this is done when calling .Xr zip_close 3 and any errors, like missing write permissions, will be reported then. .Sh SEE ALSO .Xr libzip 3 , .Xr zip_close 3 , .Xr zip_error_strerror 3 , .Xr zip_fdopen 3 , .Xr zip_source 5 .Sh HISTORY .Fn zip_open and .Fn zip_open_from_source were added in libzip 1.0. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_register_cancel_callback_with_state.html ================================================ ================================================ FILE: external/libzip/man/zip_register_cancel_callback_with_state.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_register_cancel_callback_with_state.mdoc -- allow cancelling during zip_close .\" Copyright (C) 2021-2022 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_REGISTER_CANCEL_CALLBACK_WITH_STATE" "3" "June 18, 2022" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_register_cancel_callback_with_state\fR \- allow cancelling during zip_close .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fItypedef int (*zip_cancel_callback)(zip_t *, void *);\fR .sp \fIvoid\fR .br .PD 0 .HP 4n \fBzip_register_cancel_callback_with_state\fR(\fIzip_t\ *archive\fR, \fIzip_cancel_callback\ callback\fR, \fIvoid\ (*ud_free)(void\ *)\fR, \fIvoid\ *ud\fR); .PD .SH "DESCRIPTION" This function can be used to cancel writing of a zip archive during zip_close(3). .PP The \fBzip_register_cancel_callback_with_state\fR() function registers a callback function \fIcallback\fR for the zip archive \fIarchive\fR. The \fIud_free\fR function is called during cleanup for deleting the userdata supplied in \fIud\fR. .PP The callback function is called during zip_close(3) in regular intervals (after every zip archive entry that's completely written to disk, and while writing data for entries) with zip archive \fIarchive\fR and the user-provided user-data \fIud\fR as arguments. When the callback function returns a non-zero value, writing is cancelled and zip_close(3) returns an error. .PP The callback function should be fast, since it will be called often. .SH "SEE ALSO" libzip(3), zip_close(3), zip_register_progress_callback_with_state(3) .SH "HISTORY" \fBzip_register_cancel_callback_with_state\fR() was added in libzip 1.6.0. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_register_cancel_callback_with_state.mdoc ================================================ .\" zip_register_cancel_callback_with_state.mdoc -- allow cancelling during zip_close .\" Copyright (C) 2021-2022 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd June 18, 2022 .Dt ZIP_REGISTER_CANCEL_CALLBACK_WITH_STATE 3 .Os .Sh NAME .Nm zip_register_cancel_callback_with_state .Nd allow cancelling during zip_close .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Vt typedef int (*zip_cancel_callback)(zip_t *, void *); .Ft void .Fn zip_register_cancel_callback_with_state "zip_t *archive" "zip_cancel_callback callback" "void (*ud_free)(void *)" "void *ud" .Sh DESCRIPTION This function can be used to cancel writing of a zip archive during .Xr zip_close 3 . .Pp The .Fn zip_register_cancel_callback_with_state function registers a callback function .Ar callback for the zip archive .Ar archive . The .Ar ud_free function is called during cleanup for deleting the userdata supplied in .Ar ud . .Pp The callback function is called during .Xr zip_close 3 in regular intervals (after every zip archive entry that's completely written to disk, and while writing data for entries) with zip archive .Ar archive and the user-provided user-data .Ar ud as arguments. When the callback function returns a non-zero value, writing is cancelled and .Xr zip_close 3 returns an error. .Pp The callback function should be fast, since it will be called often. .Sh SEE ALSO .Xr libzip 3 , .Xr zip_close 3 , .Xr zip_register_progress_callback_with_state 3 .Sh HISTORY .Fn zip_register_cancel_callback_with_state was added in libzip 1.6.0. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_register_progress_callback.html ================================================ ================================================ FILE: external/libzip/man/zip_register_progress_callback.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_register_progress_callback.mdoc -- provide updates during zip_close .\" Copyright (C) 2016-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_REGISTER_PROGRESS_CALLBACK" "3" "December 18, 2017" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_register_progress_callback\fR \- provide updates during zip_close (obsolete interface) .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fItypedef void (*zip_progress_callback_t)(double);\fR .sp \fIvoid\fR .br .PD 0 .HP 4n \fBzip_register_progress_callback\fR(\fIzip_t\ *archive\fR, \fIzip_progress_callback_t\ progress_callback\fR); .PD .SH "DESCRIPTION" The function \fBzip_register_progress_callback\fR() is the obsolete version of zip_register_progress_callback_with_state(3). .PP The \fBzip_register_progress_callback\fR() function registers a callback function \fIprogress_callback\fR for the zip archive \fIarchive\fR. This function is called during zip_close(3) after every zip archive entry that's completely written to disk. The value is a \fIdouble\fR in the range from 0.0 to 1.0. This can be used to provide progress indicators for user interfaces. .SH "SEE ALSO" libzip(3), zip_close(3) .SH "HISTORY" \fBzip_register_progress_callback\fR() was added in libzip 1.2.0. It was deprecated in libzip 1.3.0, use \fBzip_register_progress_callback_with_state\fR() instead. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_register_progress_callback.mdoc ================================================ .\" zip_register_progress_callback.mdoc -- provide updates during zip_close .\" Copyright (C) 2016-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd December 18, 2017 .Dt ZIP_REGISTER_PROGRESS_CALLBACK 3 .Os .Sh NAME .Nm zip_register_progress_callback .Nd provide updates during zip_close (obsolete interface) .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Vt typedef void (*zip_progress_callback_t)(double); .Ft void .Fn zip_register_progress_callback "zip_t *archive" "zip_progress_callback_t progress_callback" .Sh DESCRIPTION The function .Fn zip_register_progress_callback is the obsolete version of .Xr zip_register_progress_callback_with_state 3 . .Pp The .Fn zip_register_progress_callback function registers a callback function .Ar progress_callback for the zip archive .Ar archive . This function is called during .Xr zip_close 3 after every zip archive entry that's completely written to disk. The value is a .Vt double in the range from 0.0 to 1.0. This can be used to provide progress indicators for user interfaces. .Sh SEE ALSO .Xr libzip 3 , .Xr zip_close 3 .Sh HISTORY .Fn zip_register_progress_callback was added in libzip 1.2.0. It was deprecated in libzip 1.3.0, use .Fn zip_register_progress_callback_with_state instead. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_register_progress_callback_with_state.html ================================================ ================================================ FILE: external/libzip/man/zip_register_progress_callback_with_state.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_register_progress_callback_with_state.mdoc -- provide updates during zip_close .\" Copyright (C) 2017-2021 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_REGISTER_PROGRESS_CALLBACK_WITH_STATE" "3" "December 18, 2017" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_register_progress_callback_with_state\fR \- provide updates during zip_close .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fItypedef void (*zip_progress_callback)(zip_t *, double, void *);\fR .sp \fIvoid\fR .br .PD 0 .HP 4n \fBzip_register_progress_callback_with_state\fR(\fIzip_t\ *archive\fR, \fIdouble\ precision\fR, \fIzip_progress_callback\ callback\fR, \fIvoid\ (*ud_free)(void\ *)\fR, \fIvoid\ *ud\fR); .PD .SH "DESCRIPTION" The \fBzip_register_progress_callback_with_state\fR() function registers a callback function \fIcallback\fR for the zip archive \fIarchive\fR. The \fIprecision\fR argument is a double in the range from 0.00 to 1.0 that defines the smallest change for which the callback should be called (to avoid too frequent calls). The \fIud_free\fR function is called during cleanup for deleting the userdata supplied in \fIud\fR. .PP The callback function is called during zip_close(3) in regular intervals (after every zip archive entry that's completely written to disk, and while writing data for entries) with zip archive \fIarchive\fR, the current progression state as a \fIdouble\fR, and the user-provided user-data \fIud\fR as arguments. The progression state is a \fIdouble\fR in the range from 0.0 to 1.0. This can be used to provide progress indicators for user interfaces. .SH "SEE ALSO" libzip(3), zip_close(3), zip_register_cancel_callback_with_state(3) .SH "HISTORY" \fBzip_register_progress_callback_with_state\fR() was added in libzip 1.3.0. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_register_progress_callback_with_state.mdoc ================================================ .\" zip_register_progress_callback_with_state.mdoc -- provide updates during zip_close .\" Copyright (C) 2017-2021 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd December 18, 2017 .Dt ZIP_REGISTER_PROGRESS_CALLBACK_WITH_STATE 3 .Os .Sh NAME .Nm zip_register_progress_callback_with_state .Nd provide updates during zip_close .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Vt typedef void (*zip_progress_callback)(zip_t *, double, void *); .Ft void .Fn zip_register_progress_callback_with_state "zip_t *archive" "double precision" "zip_progress_callback callback" "void (*ud_free)(void *)" "void *ud" .Sh DESCRIPTION The .Fn zip_register_progress_callback_with_state function registers a callback function .Ar callback for the zip archive .Ar archive . The .Ar precision argument is a double in the range from 0.00 to 1.0 that defines the smallest change for which the callback should be called (to avoid too frequent calls). The .Ar ud_free function is called during cleanup for deleting the userdata supplied in .Ar ud . .Pp The callback function is called during .Xr zip_close 3 in regular intervals (after every zip archive entry that's completely written to disk, and while writing data for entries) with zip archive .Ar archive , the current progression state as a .Vt double , and the user-provided user-data .Ar ud as arguments. The progression state is a .Vt double in the range from 0.0 to 1.0. This can be used to provide progress indicators for user interfaces. .Sh SEE ALSO .Xr libzip 3 , .Xr zip_close 3 , .Xr zip_register_cancel_callback_with_state 3 .Sh HISTORY .Fn zip_register_progress_callback_with_state was added in libzip 1.3.0. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_rename.html ================================================ ================================================ FILE: external/libzip/man/zip_rename.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_rename.mdoc -- rename file in zip archive .\" Copyright (C) 2003-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_RENAME" "3" "December 18, 2017" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_rename\fR \- rename file in zip archive (obsolete interface) .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIint\fR .br .PD 0 .HP 4n \fBzip_rename\fR(\fIzip_t\ *archive\fR, \fIzip_uint64_t\ index\fR, \fIconst\ char\ *name\fR); .PD .SH "DESCRIPTION" \fBzip_rename\fR() is the obsolete version of zip_file_rename(3). It is the same as calling zip_file_rename(3) with an empty flags argument. .SH "SEE ALSO" libzip(3), zip_file_rename(3) .SH "HISTORY" \fBzip_rename\fR() was added in libzip 0.6. In libzip 0.10 the type of \fIindex\fR was changed from \fIint\fR to \fIzip_uint64_t\fR. It was deprecated in libzip 0.11, use \fBzip_file_rename\fR() instead. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_rename.mdoc ================================================ .\" zip_rename.mdoc -- rename file in zip archive .\" Copyright (C) 2003-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd December 18, 2017 .Dt ZIP_RENAME 3 .Os .Sh NAME .Nm zip_rename .Nd rename file in zip archive (obsolete interface) .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft int .Fn zip_rename "zip_t *archive" "zip_uint64_t index" "const char *name" .Sh DESCRIPTION .Fn zip_rename is the obsolete version of .Xr zip_file_rename 3 . It is the same as calling .Xr zip_file_rename 3 with an empty flags argument. .Sh SEE ALSO .Xr libzip 3 , .Xr zip_file_rename 3 .Sh HISTORY .Fn zip_rename was added in libzip 0.6. In libzip 0.10 the type of .Ar index was changed from .Vt int to .Vt zip_uint64_t . It was deprecated in libzip 0.11, use .Fn zip_file_rename instead. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_set_archive_comment.html ================================================ ================================================ FILE: external/libzip/man/zip_set_archive_comment.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_set_archive_comment.mdoc -- set zip archive comment .\" Copyright (C) 2006-2021 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_SET_ARCHIVE_COMMENT" "3" "December 18, 2017" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_set_archive_comment\fR \- set zip archive comment .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIint\fR .br .PD 0 .HP 4n \fBzip_set_archive_comment\fR(\fIzip_t\ *archive\fR, \fIconst\ char\ *comment\fR, \fIzip_uint16_t\ len\fR); .PD .SH "DESCRIPTION" The \fBzip_set_archive_comment\fR() function sets the comment for the entire zip archive. If \fIcomment\fR is \fRNULL\fR and \fIlen\fR is 0, the archive comment will be removed. \fIcomment\fR must be encoded in ASCII or UTF-8. .SH "RETURN VALUES" Upon successful completion 0 is returned. Otherwise, \-1 is returned and the error information in \fIarchive\fR is set to indicate the error. .SH "ERRORS" \fBzip_set_archive_comment\fR() fails if: .TP 19n [\fRZIP_ER_INVAL\fR] \fIlen\fR is less than 0 or longer than the maximum comment length in a zip file (65535), or \fIcomment\fR is not a valid UTF-8 encoded string. .TP 19n [\fRZIP_ER_MEMORY\fR] Required memory could not be allocated. .SH "SEE ALSO" libzip(3), zip_file_get_comment(3), zip_file_set_comment(3), zip_get_archive_comment(3) .SH "HISTORY" \fBzip_set_archive_comment\fR() was added in libzip 0.7. In libzip 0.11 the type of \fIlen\fR was changed from \fIint\fR to \fIzip_uint16_t\fR. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_set_archive_comment.mdoc ================================================ .\" zip_set_archive_comment.mdoc -- set zip archive comment .\" Copyright (C) 2006-2021 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd December 18, 2017 .Dt ZIP_SET_ARCHIVE_COMMENT 3 .Os .Sh NAME .Nm zip_set_archive_comment .Nd set zip archive comment .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft int .Fn zip_set_archive_comment "zip_t *archive" "const char *comment" "zip_uint16_t len" .Sh DESCRIPTION The .Fn zip_set_archive_comment function sets the comment for the entire zip archive. If .Ar comment is .Dv NULL and .Ar len is 0, the archive comment will be removed. .Ar comment must be encoded in ASCII or UTF-8. .Sh RETURN VALUES Upon successful completion 0 is returned. Otherwise, \-1 is returned and the error information in .Ar archive is set to indicate the error. .Sh ERRORS .Fn zip_set_archive_comment fails if: .Bl -tag -width Er .It Bq Er ZIP_ER_INVAL .Ar len is less than 0 or longer than the maximum comment length in a zip file (65535), or .Ar comment is not a valid UTF-8 encoded string. .It Bq Er ZIP_ER_MEMORY Required memory could not be allocated. .El .Sh SEE ALSO .Xr libzip 3 , .Xr zip_file_get_comment 3 , .Xr zip_file_set_comment 3 , .Xr zip_get_archive_comment 3 .Sh HISTORY .Fn zip_set_archive_comment was added in libzip 0.7. In libzip 0.11 the type of .Ar len was changed from .Vt int to .Vt zip_uint16_t . .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_set_archive_flag.html ================================================ ================================================ FILE: external/libzip/man/zip_set_archive_flag.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_set_archive_flag.mdoc -- set zip archive flag .\" Copyright (C) 2008-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_SET_ARCHIVE_FLAG" "3" "July 19, 2023" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_set_archive_flag\fR \- set zip archive flag .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIint\fR .br .PD 0 .HP 4n \fBzip_set_archive_flag\fR(\fIzip_t\ *archive\fR, \fIzip_flags_t\ flag\fR, \fIint\ value\fR); .PD .SH "DESCRIPTION" The \fBzip_set_archive_flag\fR() function sets the flag \fIflag\fR for the archive \fIarchive\fR to the value \fIvalue\fR. .PP Supported flags are: .TP 20n \fRZIP_AFL_CREATE_OR_KEEP_FILE_FOR_EMPTY_ARCHIVE\fR If this flag is cleared, the archive file will be removed if the archive is empty. If it is set, an empty archive will be created, which is not recommended by the zip specification. .TP 20n \fRZIP_AFL_RDONLY\fR If this flag is set, no modification to the archive are allowed. This flag can only be cleared if it was manually set with \fBzip_set_archive_flag\fR, not if the archive was opened read-only. .TP 20n \fRZIP_AFL_WANT_TORRENTZIP\fR If this flag is set, the archive will be written in torrentzip format. .SH "RETURN VALUES" Upon successful completion 0 is returned, and \-1 if an error occurred. .SH "SEE ALSO" libzip(3), zip_get_archive_flag(3) .SH "HISTORY" \fBzip_set_archive_flag\fR() was added in libzip 0.9. In libzip 0.11 the type of \fIflag\fR was changed from \fIint\fR to \fIzip_flags_t\fR. \fRZIP_AFL_CREATE_OR_KEEP_FILE_FOR_EMPTY_ARCHIVE\fR and \fRZIP_AFL_WANT_TORRENTZIP\fR were added in libzip 1.10.0. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_set_archive_flag.mdoc ================================================ .\" zip_set_archive_flag.mdoc -- set zip archive flag .\" Copyright (C) 2008-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd July 19, 2023 .Dt ZIP_SET_ARCHIVE_FLAG 3 .Os .Sh NAME .Nm zip_set_archive_flag .Nd set zip archive flag .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft int .Fn zip_set_archive_flag "zip_t *archive" "zip_flags_t flag" "int value" .Sh DESCRIPTION The .Fn zip_set_archive_flag function sets the flag .Ar flag for the archive .Ar archive to the value .Ar value . .Pp Supported flags are: .Bl -tag -width XZIPXAFLXRDONLYXXX .It Dv ZIP_AFL_CREATE_OR_KEEP_FILE_FOR_EMPTY_ARCHIVE If this flag is cleared, the archive file will be removed if the archive is empty. If it is set, an empty archive will be created, which is not recommended by the zip specification. .It Dv ZIP_AFL_RDONLY If this flag is set, no modification to the archive are allowed. This flag can only be cleared if it was manually set with .Nm , not if the archive was opened read-only. .It Dv ZIP_AFL_WANT_TORRENTZIP If this flag is set, the archive will be written in torrentzip format. .El .Sh RETURN VALUES Upon successful completion 0 is returned, and \-1 if an error occurred. .Sh SEE ALSO .Xr libzip 3 , .Xr zip_get_archive_flag 3 .Sh HISTORY .Fn zip_set_archive_flag was added in libzip 0.9. In libzip 0.11 the type of .Ar flag was changed from .Vt int to .Vt zip_flags_t . .Dv ZIP_AFL_CREATE_OR_KEEP_FILE_FOR_EMPTY_ARCHIVE and .Dv ZIP_AFL_WANT_TORRENTZIP were added in libzip 1.10.0. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_set_default_password.html ================================================ ================================================ FILE: external/libzip/man/zip_set_default_password.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_set_default_password.mdoc -- set default password for zip .\" Copyright (C) 2011-2021 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP files. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_SET_DEFAULT_PASSWORD" "3" "September 15, 2020" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_set_default_password\fR \- set default password for encrypted files in zip .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIint\fR .br .PD 0 .HP 4n \fBzip_set_default_password\fR(\fIzip_t\ *archive\fR, \fIconst\ char\ *password\fR); .PD .SH "DESCRIPTION" The \fBzip_set_default_password\fR() function sets the default password used when accessing encrypted files. If \fIpassword\fR is \fRNULL\fR or the empty string, the default password is unset. .PP If you prefer a different password for single files, use zip_fopen_encrypted(3) instead of zip_fopen(3). Usually, however, the same password is used for every file in an zip archive. .PP The password is not verified when calling this function. See the \fICAVEATS\fR section in zip_fopen_encrypted(3) for more details about password handling. .SH "RETURN VALUES" Upon successful completion 0 is returned. Otherwise, \-1 is returned and the error information in \fIarchive\fR is set to indicate the error. .SH "ERRORS" \fBzip_set_default_password\fR() fails if: .TP 19n [\fRZIP_ER_MEMORY\fR] Required memory could not be allocated. .SH "SEE ALSO" libzip(3), zip_fopen(3), zip_fopen_encrypted(3) .SH "HISTORY" \fBzip_set_default_password\fR() was added in libzip 0.10. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_set_default_password.mdoc ================================================ .\" zip_set_default_password.mdoc -- set default password for zip .\" Copyright (C) 2011-2021 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP files. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd September 15, 2020 .Dt ZIP_SET_DEFAULT_PASSWORD 3 .Os .Sh NAME .Nm zip_set_default_password .Nd set default password for encrypted files in zip .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft int .Fn zip_set_default_password "zip_t *archive" "const char *password" .Sh DESCRIPTION The .Fn zip_set_default_password function sets the default password used when accessing encrypted files. If .Ar password is .Dv NULL or the empty string, the default password is unset. .Pp If you prefer a different password for single files, use .Xr zip_fopen_encrypted 3 instead of .Xr zip_fopen 3 . Usually, however, the same password is used for every file in an zip archive. .Pp The password is not verified when calling this function. See the .Sx CAVEATS section in .Xr zip_fopen_encrypted 3 for more details about password handling. .Sh RETURN VALUES Upon successful completion 0 is returned. Otherwise, \-1 is returned and the error information in .Ar archive is set to indicate the error. .Sh ERRORS .Fn zip_set_default_password fails if: .Bl -tag -width Er .It Bq Er ZIP_ER_MEMORY Required memory could not be allocated. .El .Sh SEE ALSO .Xr libzip 3 , .Xr zip_fopen 3 , .Xr zip_fopen_encrypted 3 .Sh HISTORY .Fn zip_set_default_password was added in libzip 0.10. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_set_file_comment.html ================================================ ================================================ FILE: external/libzip/man/zip_set_file_comment.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_set_file_comment.mdoc -- set comment for file in zip .\" Copyright (C) 2006-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP files. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_SET_FILE_COMMENT" "3" "December 18, 2017" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_set_file_comment\fR \- set comment for file in zip (obsolete interface) .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIint\fR .br .PD 0 .HP 4n \fBzip_set_file_comment\fR(\fIzip_t\ *archive\fR, \fIzip_uint64_t\ index\fR, \fIconst\ char\ *comment\fR, \fIint\ len\fR); .PD .SH "DESCRIPTION" The \fBzip_set_file_comment\fR() function is the obsolete version of zip_file_set_comment(3). The only differences are the type of the \fIlen\fR argument and the additional \fIflags\fR argument. \fBzip_set_file_comment\fR() is the same as calling zip_file_set_comment(3) with an empty \fIflags\fR argument. .SH "SEE ALSO" libzip(3), zip_file_set_comment(3) .SH "HISTORY" \fBzip_set_file_comment\fR() was added in libzip 0.7. In libzip 0.10 the type of \fIindex\fR was changed from \fIint\fR to \fIzip_uint64_t\fR. It was deprecated in libzip 0.11, use \fBzip_file_set_comment\fR() instead. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_set_file_comment.mdoc ================================================ .\" zip_set_file_comment.mdoc -- set comment for file in zip .\" Copyright (C) 2006-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP files. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd December 18, 2017 .Dt ZIP_SET_FILE_COMMENT 3 .Os .Sh NAME .Nm zip_set_file_comment .Nd set comment for file in zip (obsolete interface) .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft int .Fn zip_set_file_comment "zip_t *archive" "zip_uint64_t index" "const char *comment" "int len" .Sh DESCRIPTION The .Fn zip_set_file_comment function is the obsolete version of .Xr zip_file_set_comment 3 . The only differences are the type of the .Ar len argument and the additional .Ar flags argument. .Fn zip_set_file_comment is the same as calling .Xr zip_file_set_comment 3 with an empty .Ar flags argument. .Sh SEE ALSO .Xr libzip 3 , .Xr zip_file_set_comment 3 .Sh HISTORY .Fn zip_set_file_comment was added in libzip 0.7. In libzip 0.10 the type of .Ar index was changed from .Vt int to .Vt zip_uint64_t . It was deprecated in libzip 0.11, use .Fn zip_file_set_comment instead. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_set_file_compression.html ================================================ ================================================ FILE: external/libzip/man/zip_set_file_compression.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_set_file_compression.mdoc -- set compression method and its flags .\" Copyright (C) 2012-2021 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP files. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_SET_FILE_COMPRESSION" "3" "February 2, 2023" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_set_file_compression\fR \- set compression method for file in zip .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIint\fR .br .PD 0 .HP 4n \fBzip_set_file_compression\fR(\fIzip_t\ *archive\fR, \fIzip_uint64_t\ index\fR, \fIzip_int32_t\ comp\fR, \fIzip_uint32_t\ comp_flags\fR); .PD .SH "DESCRIPTION" The \fBzip_set_file_compression\fR() function sets the compression method for the file at position \fIindex\fR in the zip archive to \fIcomp\fR with the compression method specific \fIcomp_flags\fR. The \fIcomp\fR is the same as returned by zip_stat(3). For the \fIcomp\fR argument, currently only the following values are supported: .TP 19n \fRZIP_CM_DEFAULT\fR default compression; currently the same as \fRZIP_CM_DEFLATE\fR, but \fIflags\fR are ignored. .TP 19n \fRZIP_CM_STORE\fR Store the file uncompressed. .TP 19n \fRZIP_CM_BZIP2\fR Compress the file using the bzip2(1) algorithm. .TP 19n \fRZIP_CM_DEFLATE\fR Deflate the file with the zlib(3) algorithm and default options. .TP 19n \fRZIP_CM_XZ\fR Use the xz(1) algorithm for compression .TP 19n \fRZIP_CM_ZSTD\fR Use the zstd(1) algorithm for compression .PP \fINOTE\fR: Only the deflate and store methods can be assumed to be universally supported. .PP The \fIcomp_flags\fR argument defines the compression level. This value is dependent on the compression algorithm. In general, lower numbers mean faster de/compression and higher numbers mean slower de/compression. For \fRZIP_CM_BZIP\fR, \fRZIP_CM_DEFLATE\fR, and \fRZIP_CM_XZ\fR 1 is the fastest compression and 9 the best, 0 chooses the default. For \fRZIP_CM_ZSTD\fR possible values are ZSTD_minCLevel(3) to ZSTD_maxCLevel(3); negative values must be cast to \fIzip_uint32_t\fR. .PP Further compression method specific flags might be added over time. .PP The current compression method for a file in a zip archive can be determined using zip_stat(3). .SH "RETURN VALUES" Upon successful completion 0 is returned. Otherwise, \-1 is returned and the error information in \fIarchive\fR is set to indicate the error. .SH "ERRORS" \fBzip_set_file_compression\fR() fails if: .TP 19n [\fRZIP_ER_COMPNOTSUPP\fR] Unsupported compression method requested. .TP 19n [\fRZIP_ER_INVAL\fR] \fIindex\fR is not a valid file index in \fIarchive\fR, or the argument combination is invalid. .TP 19n [\fRZIP_ER_RDONLY\fR] Read-only zip file, no changes allowed. .SH "SEE ALSO" libzip(3), zip_compression_method_supported(3), zip_stat(3) .SH "HISTORY" \fBzip_set_file_compression\fR() was added in libzip 0.11. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_set_file_compression.mdoc ================================================ .\" zip_set_file_compression.mdoc -- set compression method and its flags .\" Copyright (C) 2012-2021 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP files. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd February 2, 2023 .Dt ZIP_SET_FILE_COMPRESSION 3 .Os .Sh NAME .Nm zip_set_file_compression .Nd set compression method for file in zip .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft int .Fn zip_set_file_compression "zip_t *archive" "zip_uint64_t index" "zip_int32_t comp" "zip_uint32_t comp_flags" .Sh DESCRIPTION The .Fn zip_set_file_compression function sets the compression method for the file at position .Ar index in the zip archive to .Ar comp with the compression method specific .Ar comp_flags . The .Ar comp is the same as returned by .Xr zip_stat 3 . For the .Ar comp argument, currently only the following values are supported: .Bl -tag -width ZIP_CM_DEFLATE_XX .It Dv ZIP_CM_DEFAULT default compression; currently the same as .Dv ZIP_CM_DEFLATE , but .Ar flags are ignored. .It Dv ZIP_CM_STORE Store the file uncompressed. .It Dv ZIP_CM_BZIP2 Compress the file using the .Xr bzip2 1 algorithm. .It Dv ZIP_CM_DEFLATE Deflate the file with the .Xr zlib 3 algorithm and default options. .It Dv ZIP_CM_XZ Use the .Xr xz 1 algorithm for compression .It Dv ZIP_CM_ZSTD Use the .Xr zstd 1 algorithm for compression .El .Pp .Em NOTE : Only the deflate and store methods can be assumed to be universally supported. .Pp The .Ar comp_flags argument defines the compression level. This value is dependent on the compression algorithm. In general, lower numbers mean faster de/compression and higher numbers mean slower de/compression. For .Dv ZIP_CM_BZIP , .Dv ZIP_CM_DEFLATE , and .Dv ZIP_CM_XZ 1 is the fastest compression and 9 the best, 0 chooses the default. For .Dv ZIP_CM_ZSTD possible values are .Xr ZSTD_minCLevel 3 to .Xr ZSTD_maxCLevel 3 ; negative values must be cast to .Ft zip_uint32_t . .Pp Further compression method specific flags might be added over time. .Pp The current compression method for a file in a zip archive can be determined using .Xr zip_stat 3 . .Sh RETURN VALUES Upon successful completion 0 is returned. Otherwise, \-1 is returned and the error information in .Ar archive is set to indicate the error. .Sh ERRORS .Fn zip_set_file_compression fails if: .Bl -tag -width Er .It Bq Er ZIP_ER_COMPNOTSUPP Unsupported compression method requested. .It Bq Er ZIP_ER_INVAL .Ar index is not a valid file index in .Ar archive , or the argument combination is invalid. .It Bq Er ZIP_ER_RDONLY Read-only zip file, no changes allowed. .El .Sh SEE ALSO .Xr libzip 3 , .Xr zip_compression_method_supported 3 , .Xr zip_stat 3 .Sh HISTORY .Fn zip_set_file_compression was added in libzip 0.11. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_source.html ================================================ ================================================ FILE: external/libzip/man/zip_source.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_source.mdoc -- description of zip data source .\" Copyright (C) 2014-2021 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_SOURCE" "5" "May 5, 2025" "NiH" "File Formats Manual" .nh .if n .ad l .SH "NAME" \fBzip_source\fR \- zip data source structure .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIzip_source_t *source\fR; .SH "DESCRIPTION" A \fIzip_source_t\fR represents a data source (or destination when used for writing). libzip(3) uses it for adding or replacing file contents for a file in a zip archive. If the source supports seeking, it can also be used to open zip archives from. .PP Data can come from a file on disk (zip_source_file(3), zip_source_file_create(3), zip_source_filep(3), or zip_source_filep_create(3)), memory (zip_source_buffer(3), zip_source_buffer_create(3), zip_source_buffer_fragment(3), or zip_source_buffer_fragment_create(3)), a file inside an archive (zip_source_zip(3)), or provided via a callback function (zip_source_function(3) or zip_source_function_create(3)). zip_source_window(3) or zip_source_window_create(3) can be used restrict access to a part of the contained data. .PP It can also be used as a filter to process the data provided by an underlying \fIzip_source_t\fR (e.g., to compress it or compute a checksum), created with zip_source_layered(3) or zip_source_layered_create(3)). .PP Sources are freed with zip_source_free(3). .PP Sources must support reading, and can optionally support seeking and writing. .PP \fIzip_source_t\fR is reference counted, and created with a reference count of 1. zip_open_from_source(3), zip_file_add(3), and zip_file_replace(3) will take ownership of the passed source (decrement the reference count when they are done using it), so zip_source_free(3) only needs to be called when these functions return an error. The underlying data (file or buffer) must remain valid until the archive is closed. Use zip_source_keep(3) to increase the reference count, for example if you need the source after zip_close(3). .SH "SEE ALSO" libzip(3), zip_source_buffer(3), zip_source_file(3), zip_source_filep(3), zip_source_free(3), zip_source_function(3), zip_source_keep(3), zip_source_window(3), zip_source_zip(3) .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_source.mdoc ================================================ .\" zip_source.mdoc -- description of zip data source .\" Copyright (C) 2014-2021 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd May 5, 2025 .Dt ZIP_SOURCE 5 .Os .Sh NAME .Nm zip_source .Nd zip data source structure .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Vt zip_source_t *source ; .Sh DESCRIPTION A .Vt zip_source_t represents a data source (or destination when used for writing). .Xr libzip 3 uses it for adding or replacing file contents for a file in a zip archive. If the source supports seeking, it can also be used to open zip archives from. .Pp Data can come from a file on disk .Xr ( zip_source_file 3 , .Xr zip_source_file_create 3 , .Xr zip_source_filep 3 , or .Xr zip_source_filep_create 3 ) , memory .Xr ( zip_source_buffer 3 , .Xr zip_source_buffer_create 3 , .Xr zip_source_buffer_fragment 3 , or .Xr zip_source_buffer_fragment_create 3 ) , a file inside an archive .Xr ( zip_source_zip 3 ) , or provided via a callback function .Xr ( zip_source_function 3 or .Xr zip_source_function_create 3 ) . .Xr zip_source_window 3 or .Xr zip_source_window_create 3 can be used restrict access to a part of the contained data. .Pp It can also be used as a filter to process the data provided by an underlying .Vt zip_source_t (e.g., to compress it or compute a checksum), created with .Xr zip_source_layered 3 or .Xr zip_source_layered_create 3 ) . .Pp Sources are freed with .Xr zip_source_free 3 . .Pp Sources must support reading, and can optionally support seeking and writing. .Pp .Vt zip_source_t is reference counted, and created with a reference count of 1. .Xr zip_open_from_source 3 , .Xr zip_file_add 3 , and .Xr zip_file_replace 3 will take ownership of the passed source (decrement the reference count when they are done using it), so .Xr zip_source_free 3 only needs to be called when these functions return an error. The underlying data (file or buffer) must remain valid until the archive is closed. Use .Xr zip_source_keep 3 to increase the reference count, for example if you need the source after .Xr zip_close 3 . .Sh SEE ALSO .Xr libzip 3 , .Xr zip_source_buffer 3 , .Xr zip_source_file 3 , .Xr zip_source_filep 3 , .Xr zip_source_free 3 , .Xr zip_source_function 3 , .Xr zip_source_keep 3 , .Xr zip_source_window 3 , .Xr zip_source_zip 3 .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_source_begin_write.html ================================================ ================================================ FILE: external/libzip/man/zip_source_begin_write.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_source_begin_write.mdoc -- prepare zip source for writing .\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_SOURCE_BEGIN_WRITE" "3" "December 18, 2017" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_source_begin_write\fR, \fBzip_source_begin_write_cloning\fR \- prepare zip source for writing .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIint\fR .br .PD 0 .HP 4n \fBzip_source_begin_write\fR(\fIzip_source_t\ *source\fR); .PD .PP \fIint\fR .br .PD 0 .HP 4n \fBzip_source_begin_write_cloning\fR(\fIzip_source_t\ *source\fR, \fIzip_uint64_t\ offset\fR); .PD .SH "DESCRIPTION" The functions \fBzip_source_begin_write\fR() and \fBzip_source_begin_write_cloning\fR() prepare \fIsource\fR for writing. Usually this involves creating temporary files or allocating buffers. .PP \fBzip_source_begin_write_cloning\fR() preserves the first \fIoffset\fR bytes of the original file. This is done efficiently, and writes to \fIsource\fR won't overwrite the original data until \fBzip_commit_write\fR() is called. .SH "RETURN VALUES" Upon successful completion 0 is returned. Otherwise, \-1 is returned and the error information in \fIsource\fR is set to indicate the error. .SH "SEE ALSO" libzip(3), zip_source(5), zip_source_commit_write(3), zip_source_rollback_write(3), zip_source_seek_write(3), zip_source_tell_write(3), zip_source_write(3) .SH "HISTORY" \fBzip_source_begin_write\fR() was added in libzip 1.0. .PP \fBzip_source_begin_write_cloning\fR() was added in libzip 1.4.0. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_source_begin_write.mdoc ================================================ .\" zip_source_begin_write.mdoc -- prepare zip source for writing .\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd December 18, 2017 .Dt ZIP_SOURCE_BEGIN_WRITE 3 .Os .Sh NAME .Nm zip_source_begin_write , .Nm zip_source_begin_write_cloning .Nd prepare zip source for writing .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft int .Fn zip_source_begin_write "zip_source_t *source" .Ft int .Fn zip_source_begin_write_cloning "zip_source_t *source" "zip_uint64_t offset" .Sh DESCRIPTION The functions .Fn zip_source_begin_write and .Fn zip_source_begin_write_cloning prepare .Fa source for writing. Usually this involves creating temporary files or allocating buffers. .Pp .Fn zip_source_begin_write_cloning preserves the first .Ar offset bytes of the original file. This is done efficiently, and writes to .Ar source won't overwrite the original data until .Fn zip_commit_write is called. .Sh RETURN VALUES Upon successful completion 0 is returned. Otherwise, \-1 is returned and the error information in .Ar source is set to indicate the error. .Sh SEE ALSO .Xr libzip 3 , .Xr zip_source 5 , .Xr zip_source_commit_write 3 , .Xr zip_source_rollback_write 3 , .Xr zip_source_seek_write 3 , .Xr zip_source_tell_write 3 , .Xr zip_source_write 3 .Sh HISTORY .Fn zip_source_begin_write was added in libzip 1.0. .Pp .Fn zip_source_begin_write_cloning was added in libzip 1.4.0. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_source_buffer.html ================================================ ================================================ FILE: external/libzip/man/zip_source_buffer.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_source_buffer.mdoc -- create zip data source from buffer .\" Copyright (C) 2004-2021 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_SOURCE_BUFFER" "3" "December 18, 2017" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_source_buffer\fR, \fBzip_source_buffer_create\fR \- create zip data source from buffer .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIzip_source_t *\fR .br .PD 0 .HP 4n \fBzip_source_buffer\fR(\fIzip_t\ *archive\fR, \fIconst\ void\ *data\fR, \fIzip_uint64_t\ len\fR, \fIint\ freep\fR); .PD .PP \fIzip_source_t *\fR .br .PD 0 .HP 4n \fBzip_source_buffer_create\fR(\fIconst\ void\ *data\fR, \fIzip_uint64_t\ len\fR, \fIint\ freep\fR, \fIzip_error_t\ *error\fR); .PD .SH "DESCRIPTION" The functions \fBzip_source_buffer\fR() and \fBzip_source_buffer_create\fR() create a zip source from the buffer \fIdata\fR of size \fIlen\fR. If \fIfreep\fR is non-zero, the buffer will be freed when it is no longer needed. \fIdata\fR must remain valid for the lifetime of the created source. .PP The source can be used to open a zip archive from. .SH "RETURN VALUES" Upon successful completion, the created source is returned. Otherwise, \fRNULL\fR is returned and the error code in \fIarchive\fR or \fIerror\fR is set to indicate the error. .SH "ERRORS" \fBzip_source_buffer\fR() and \fBzip_source_buffer_create\fR() fail if: .TP 19n [\fRZIP_ER_INVAL\fR] \fIlen\fR is greater than zero and \fIdata\fR is \fRNULL\fR. .TP 19n [\fRZIP_ER_MEMORY\fR] Required memory could not be allocated. .SH "SEE ALSO" libzip(3), zip_file_add(3), zip_file_replace(3), zip_open_from_source(3), zip_source(5) .SH "HISTORY" \fBzip_source_buffer\fR() and \fBzip_source_buffer_create\fR() were added in libzip 1.0. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_source_buffer.mdoc ================================================ .\" zip_source_buffer.mdoc -- create zip data source from buffer .\" Copyright (C) 2004-2021 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd December 18, 2017 .Dt ZIP_SOURCE_BUFFER 3 .Os .Sh NAME .Nm zip_source_buffer , .Nm zip_source_buffer_create .Nd create zip data source from buffer .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft zip_source_t * .Fn zip_source_buffer "zip_t *archive" "const void *data" "zip_uint64_t len" "int freep" .Ft zip_source_t * .Fn zip_source_buffer_create "const void *data" "zip_uint64_t len" "int freep" "zip_error_t *error" .Sh DESCRIPTION The functions .Fn zip_source_buffer and .Fn zip_source_buffer_create create a zip source from the buffer .Ar data of size .Ar len . If .Ar freep is non-zero, the buffer will be freed when it is no longer needed. .Ar data must remain valid for the lifetime of the created source. .Pp The source can be used to open a zip archive from. .Sh RETURN VALUES Upon successful completion, the created source is returned. Otherwise, .Dv NULL is returned and the error code in .Ar archive or .Ar error is set to indicate the error. .Sh ERRORS .Fn zip_source_buffer and .Fn zip_source_buffer_create fail if: .Bl -tag -width Er .It Bq Er ZIP_ER_INVAL .Ar len is greater than zero and .Ar data is .Dv NULL . .It Bq Er ZIP_ER_MEMORY Required memory could not be allocated. .El .Sh SEE ALSO .Xr libzip 3 , .Xr zip_file_add 3 , .Xr zip_file_replace 3 , .Xr zip_open_from_source 3 , .Xr zip_source 5 .Sh HISTORY .Fn zip_source_buffer and .Fn zip_source_buffer_create were added in libzip 1.0. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_source_buffer_fragment.html ================================================ ================================================ FILE: external/libzip/man/zip_source_buffer_fragment.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_source_buffer_fragment.mdoc -- create zip data source from multiple buffers .\" Copyright (C) 2004-2021 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_SOURCE_BUFFER_FRAGMENT" "3" "December 18, 2017" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_source_buffer_fragment\fR, \fBzip_source_buffer_fragment_create\fR \- create zip data source from multiple buffer .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIzip_source_t *\fR .br .PD 0 .HP 4n \fBzip_source_buffer_fragment\fR(\fIzip_t\ *archive\fR, \fIzip_buffer_fragment_t\ *fragments\fR, \fIzip_uint64_t\ nfragments\fR, \fIint\ freep\fR); .PD .PP \fIzip_source_t *\fR .br .PD 0 .HP 4n \fBzip_source_buffer_fragment_create\fR(\fIzip_buffer_fragment_t\ *fragments\fR, \fIzip_uint64_t\ nfragments\fR, \fIint\ freep\fR, \fIzip_error_t\ *error\fR); .PD .SH "DESCRIPTION" The functions \fBzip_source_buffer_fragment\fR() and \fBzip_source_buffer_fragment_create\fR() create a zip source from the data in \fIfragments\fR. \fInfragments\fR specifies the number of fragments. If \fIfreep\fR is non-zero, the data will be freed when it is no longer needed. .nf .sp .RS 0n struct zip_stat { zip_uint8_t *data; /* pointer to the actual data */ zip_uint64_t length; /* length of this fragment */ }; .RE .fi .PP The data \fIfragments\fR point to must remain valid for the lifetime of the created source. \fIfragments\fR itself can be discarded once the source is created. .PP The source can be used to open a zip archive from. .SH "RETURN VALUES" Upon successful completion, the created source is returned. Otherwise, \fRNULL\fR is returned and the error code in \fIarchive\fR or \fIerror\fR is set to indicate the error. .SH "ERRORS" \fBzip_source_buffer\fR() and \fBzip_source_buffer_create\fR() fail if: .TP 19n [\fRZIP_ER_INVAL\fR] \fInfragments\fR is greater than zero and \fIfragments\fR is \fRNULL\fR. .TP 19n [\fRZIP_ER_MEMORY\fR] Required memory could not be allocated. .SH "SEE ALSO" libzip(3), zip_file_add(3), zip_file_replace(3), zip_open_from_source(3), zip_source(5) .SH "HISTORY" \fBzip_source_buffer_fragment\fR() and \fBzip_source_buffer_fragment_create\fR() were added in libzip 1.4.0. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_source_buffer_fragment.mdoc ================================================ .\" zip_source_buffer_fragment.mdoc -- create zip data source from multiple buffers .\" Copyright (C) 2004-2021 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd December 18, 2017 .Dt ZIP_SOURCE_BUFFER_FRAGMENT 3 .Os .Sh NAME .Nm zip_source_buffer_fragment , .Nm zip_source_buffer_fragment_create .Nd create zip data source from multiple buffer .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft zip_source_t * .Fn zip_source_buffer_fragment "zip_t *archive" "zip_buffer_fragment_t *fragments" "zip_uint64_t nfragments" "int freep" .Ft zip_source_t * .Fn zip_source_buffer_fragment_create "zip_buffer_fragment_t *fragments" "zip_uint64_t nfragments" "int freep" "zip_error_t *error" .Sh DESCRIPTION The functions .Fn zip_source_buffer_fragment and .Fn zip_source_buffer_fragment_create create a zip source from the data in .Ar fragments . .Ar nfragments specifies the number of fragments. If .Ar freep is non-zero, the data will be freed when it is no longer needed. .Bd -literal struct zip_stat { zip_uint8_t *data; /* pointer to the actual data */ zip_uint64_t length; /* length of this fragment */ }; .Ed .Pp The data .Ar fragments point to must remain valid for the lifetime of the created source. .Ar fragments itself can be discarded once the source is created. .Pp The source can be used to open a zip archive from. .Sh RETURN VALUES Upon successful completion, the created source is returned. Otherwise, .Dv NULL is returned and the error code in .Ar archive or .Ar error is set to indicate the error. .Sh ERRORS .Fn zip_source_buffer and .Fn zip_source_buffer_create fail if: .Bl -tag -width Er .It Bq Er ZIP_ER_INVAL .Ar nfragments is greater than zero and .Ar fragments is .Dv NULL . .It Bq Er ZIP_ER_MEMORY Required memory could not be allocated. .El .Sh SEE ALSO .Xr libzip 3 , .Xr zip_file_add 3 , .Xr zip_file_replace 3 , .Xr zip_open_from_source 3 , .Xr zip_source 5 .Sh HISTORY .Fn zip_source_buffer_fragment and .Fn zip_source_buffer_fragment_create were added in libzip 1.4.0. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_source_close.html ================================================ ================================================ FILE: external/libzip/man/zip_source_close.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_source_close.mdoc -- close zip source (open for reading) .\" Copyright (C) 2014-2021 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_SOURCE_CLOSE" "3" "December 18, 2017" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_source_close\fR \- close zip_source (which was open for reading) .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIint\fR .br .PD 0 .HP 4n \fBzip_source_close\fR(\fIzip_source_t\ *source\fR); .PD .SH "DESCRIPTION" The function \fBzip_source_close\fR() closes \fIsource\fR, indicating that no more data will be read. .SH "RETURN VALUES" Upon successful completion 0 is returned. Otherwise, \-1 is returned and the error information in \fIsource\fR is set to indicate the error. .SH "SEE ALSO" libzip(3), zip_source(5), zip_source_free(3), zip_source_open(3) .SH "HISTORY" \fBzip_source_close\fR() was added in libzip 1.0. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_source_close.mdoc ================================================ .\" zip_source_close.mdoc -- close zip source (open for reading) .\" Copyright (C) 2014-2021 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd December 18, 2017 .Dt ZIP_SOURCE_CLOSE 3 .Os .Sh NAME .Nm zip_source_close .Nd close zip_source (which was open for reading) .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft int .Fn zip_source_close "zip_source_t *source" .Sh DESCRIPTION The function .Fn zip_source_close closes .Fa source , indicating that no more data will be read. .Sh RETURN VALUES Upon successful completion 0 is returned. Otherwise, \-1 is returned and the error information in .Ar source is set to indicate the error. .Sh SEE ALSO .Xr libzip 3 , .Xr zip_source 5 , .Xr zip_source_free 3 , .Xr zip_source_open 3 .Sh HISTORY .Fn zip_source_close was added in libzip 1.0. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_source_commit_write.html ================================================ ================================================ FILE: external/libzip/man/zip_source_commit_write.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_source_commit_write.mdoc -- finalize changes to zip source .\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_SOURCE_COMMIT_WRITE" "3" "December 18, 2017" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_source_commit_write\fR \- finalize changes to zip source .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIint\fR .br .PD 0 .HP 4n \fBzip_source_commit_write\fR(\fIzip_source_t\ *source\fR); .PD .SH "DESCRIPTION" The function \fBzip_source_commit_write\fR() finishes writing data to \fIsource\fR and replaces the original with the newly written data. .SH "RETURN VALUES" Upon successful completion 0 is returned. Otherwise, \-1 is returned and the error information in \fIsource\fR is set to indicate the error. .SH "SEE ALSO" libzip(3), zip_source(5), zip_source_begin_write(3), zip_source_rollback_write(3), zip_source_seek_write(3), zip_source_tell_write(3), zip_source_write(3) .SH "HISTORY" \fBzip_source_commit_write\fR() was added in libzip 1.0. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_source_commit_write.mdoc ================================================ .\" zip_source_commit_write.mdoc -- finalize changes to zip source .\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd December 18, 2017 .Dt ZIP_SOURCE_COMMIT_WRITE 3 .Os .Sh NAME .Nm zip_source_commit_write .Nd finalize changes to zip source .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft int .Fn zip_source_commit_write "zip_source_t *source" .Sh DESCRIPTION The function .Fn zip_source_commit_write finishes writing data to .Fa source and replaces the original with the newly written data. .Sh RETURN VALUES Upon successful completion 0 is returned. Otherwise, \-1 is returned and the error information in .Ar source is set to indicate the error. .Sh SEE ALSO .Xr libzip 3 , .Xr zip_source 5 , .Xr zip_source_begin_write 3 , .Xr zip_source_rollback_write 3 , .Xr zip_source_seek_write 3 , .Xr zip_source_tell_write 3 , .Xr zip_source_write 3 .Sh HISTORY .Fn zip_source_commit_write was added in libzip 1.0. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_source_error.html ================================================ ================================================ FILE: external/libzip/man/zip_source_error.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_source_error.mdoc -- get zip_error for data source .\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_SOURCE_ERROR" "3" "December 18, 2017" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_source_error\fR \- get zip error for data source .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIzip_error_t *\fR .br .PD 0 .HP 4n \fBzip_source_error\fR(\fIzip_source_t\ *source\fR); .PD .SH "DESCRIPTION" The \fBzip_source_error\fR() function returns the zip error for the data source \fIsource\fR. .SH "SEE ALSO" libzip(3), zip_error_code_system(3), zip_error_code_zip(3) .SH "HISTORY" \fBzip_source_error\fR() was added in libzip 1.0. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_source_error.mdoc ================================================ .\" zip_source_error.mdoc -- get zip_error for data source .\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd December 18, 2017 .Dt ZIP_SOURCE_ERROR 3 .Os .Sh NAME .Nm zip_source_error .Nd get zip error for data source .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft zip_error_t * .Fn zip_source_error "zip_source_t *source" .Sh DESCRIPTION The .Fn zip_source_error function returns the zip error for the data source .Ar source . .Sh SEE ALSO .Xr libzip 3 , .Xr zip_error_code_system 3 , .Xr zip_error_code_zip 3 .Sh HISTORY .Fn zip_source_error was added in libzip 1.0. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_source_file.html ================================================ ================================================ FILE: external/libzip/man/zip_source_file.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_source_file.mdoc -- create data source from a file .\" Copyright (C) 2004-2021 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_SOURCE_FILE" "3" "June 30, 2023" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_source_file\fR, \fBzip_source_file_create\fR \- create data source from a file .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIzip_source_t *\fR .br .PD 0 .HP 4n \fBzip_source_file\fR(\fIzip_t\ *archive\fR, \fIconst\ char\ *fname\fR, \fIzip_uint64_t\ start\fR, \fIzip_int64_t\ len\fR); .PD .PP \fIzip_source_t *\fR .br .PD 0 .HP 4n \fBzip_source_file_create\fR(\fIconst\ char\ *fname\fR, \fIzip_uint64_t\ start\fR, \fIzip_int64_t\ len\fR, \fIzip_error_t\ *error\fR); .PD .SH "DESCRIPTION" The functions \fBzip_source_file\fR() and \fBzip_source_file_create\fR() create a zip source from a file. They open \fIfname\fR and read \fIlen\fR bytes from offset \fIstart\fR from it. .PP When passing \fRZIP_LENGTH_TO_END\fR (or \-1, which is deprecated) as \fIlen\fR, \fBzip_source_file\fR determines the file size when it is called and uses that as the expected file size. If the file size grows between creating and reading from the source, the additional data is ignored. If the file shrinks, \fBlibzip\fR treats it as an error (\fRZIP_ER_DATA_LENGTH\fR). .PP When passing \fRZIP_LENGTH_UNCHECKED\fR as \fIlen\fR, \fBzip_source_file\fR assumes the file's size is unknown. Reading from the source returns as much data as is there at that time (usually when calling zip_close(3)). .PP \fBlibzip\fR can do various optimizations if the size of a source is known when it's created, so \fRZIP_LENGTH_TO_END\fR is preferable. If you deal with files that are likely to change while you are processing them, you can use the less efficient \fRZIP_LENGTH_UNCHECKED\fR. .PP If the file supports seek, the source can be used to open a zip archive from. .PP The file is opened and read when the data from the source is used, usually by \fBzip_close\fR() or \fBzip_open_from_source\fR(). .SH "RETURN VALUES" Upon successful completion, the created source is returned. Otherwise, \fRNULL\fR is returned and the error code in \fIarchive\fR or \fIerror\fR is set to indicate the error. .SH "ERRORS" \fBzip_source_file\fR() and \fBzip_source_file_create\fR() fail if: .TP 19n [\fRZIP_ER_INVAL\fR] \fIfname\fR, \fIstart\fR, or \fIlen\fR are invalid. .TP 19n [\fRZIP_ER_MEMORY\fR] Required memory could not be allocated. .TP 19n [\fRZIP_ER_OPEN\fR] Opening \fIfname\fR failed. .SH "SEE ALSO" libzip(3), zip_file_add(3), zip_file_replace(3), zip_source(5) .SH "HISTORY" \fBzip_source_file\fR() and \fBzip_source_file_create\fR() were added in libzip 1.0. .PP \fRZIP_LENGTH_TO_END\fR and \fRZIP_LENGTH_UNCHECKED\fR were added in libzip 1.10.1. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_source_file.mdoc ================================================ .\" zip_source_file.mdoc -- create data source from a file .\" Copyright (C) 2004-2021 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd June 30, 2023 .Dt ZIP_SOURCE_FILE 3 .Os .Sh NAME .Nm zip_source_file , .Nm zip_source_file_create .Nd create data source from a file .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft zip_source_t * .Fn zip_source_file "zip_t *archive" "const char *fname" "zip_uint64_t start" "zip_int64_t len" .Ft zip_source_t * .Fn zip_source_file_create "const char *fname" "zip_uint64_t start" "zip_int64_t len" "zip_error_t *error" .Sh DESCRIPTION The functions .Fn zip_source_file and .Fn zip_source_file_create create a zip source from a file. They open .Ar fname and read .Ar len bytes from offset .Ar start from it. .Pp When passing .Dv ZIP_LENGTH_TO_END (or \-1, which is deprecated) as .Ar len , .Nm determines the file size when it is called and uses that as the expected file size. If the file size grows between creating and reading from the source, the additional data is ignored. If the file shrinks, .Nm libzip treats it as an error .Dv ( ZIP_ER_DATA_LENGTH ) . .Pp When passing .Dv ZIP_LENGTH_UNCHECKED as .Ar len , .Nm assumes the file's size is unknown. Reading from the source returns as much data as is there at that time (usually when calling .Xr zip_close 3 ) . .Pp .Nm libzip can do various optimizations if the size of a source is known when it's created, so .Dv ZIP_LENGTH_TO_END is preferable. If you deal with files that are likely to change while you are processing them, you can use the less efficient .Dv ZIP_LENGTH_UNCHECKED . .Pp If the file supports seek, the source can be used to open a zip archive from. .Pp The file is opened and read when the data from the source is used, usually by .Fn zip_close or .Fn zip_open_from_source . .Sh RETURN VALUES Upon successful completion, the created source is returned. Otherwise, .Dv NULL is returned and the error code in .Ar archive or .Ar error is set to indicate the error. .Sh ERRORS .Fn zip_source_file and .Fn zip_source_file_create fail if: .Bl -tag -width Er .It Bq Er ZIP_ER_INVAL .Ar fname , .Ar start , or .Ar len are invalid. .It Bq Er ZIP_ER_MEMORY Required memory could not be allocated. .It Bq Er ZIP_ER_OPEN Opening .Ar fname failed. .El .Sh SEE ALSO .Xr libzip 3 , .Xr zip_file_add 3 , .Xr zip_file_replace 3 , .Xr zip_source 5 .Sh HISTORY .Fn zip_source_file and .Fn zip_source_file_create were added in libzip 1.0. .Pp .Dv ZIP_LENGTH_TO_END and .Dv ZIP_LENGTH_UNCHECKED were added in libzip 1.10.1. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_source_filep.html ================================================ ================================================ FILE: external/libzip/man/zip_source_filep.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_source_filep.mdoc -- create data source from a file stream .\" Copyright (C) 2004-2021 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_SOURCE_FILEP" "3" "June 30, 2023" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_source_filep\fR, \fBzip_source_filep_create\fR \- create data source from FILE * .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIzip_source_t *\fR .br .PD 0 .HP 4n \fBzip_source_filep\fR(\fIzip_t\ *archive\fR, \fIFILE\ *file\fR, \fIzip_uint64_t\ start\fR, \fIzip_int64_t\ len\fR); .PD .PP \fIzip_source_t *\fR .br .PD 0 .HP 4n \fBzip_source_filep_create\fR(\fIFILE\ *file\fR, \fIzip_uint64_t\ start\fR, \fIzip_int64_t\ len\fR, \fIzip_error_t\ *error\fR); .PD .SH "DESCRIPTION" The functions \fBzip_source_filep\fR() and \fBzip_source_filep_create\fR() create a zip source from a file stream. They read \fIlen\fR bytes from offset \fIstart\fR from the open file stream \fIfile\fR. For a description of the \fIlen\fR argument, see zip_source_file(3). .PP If the file stream supports seeking, the source can be used to open a read-only zip archive from. .PP The file stream is closed when the source is being freed, usually by zip_close(3). .SH "RETURN VALUES" Upon successful completion, the created source is returned. Otherwise, \fRNULL\fR is returned and the error code in \fIarchive\fR or \fIerror\fR is set to indicate the error. .SH "ERRORS" \fBzip_source_filep\fR() fails if: .TP 19n [\fRZIP_ER_INVAL\fR] \fIfile\fR, \fIstart\fR, or \fIlen\fR are invalid. .TP 19n [\fRZIP_ER_MEMORY\fR] Required memory could not be allocated. .SH "SEE ALSO" libzip(3), zip_file_add(3), zip_file_replace(3), zip_source(5), zip_source_file(3) .SH "HISTORY" \fBzip_source_filep\fR() and \fBzip_source_filep_create\fR() were added in libzip 1.0. .PP \fRZIP_LENGTH_TO_END\fR and \fRZIP_LENGTH_UNCHECKED\fR were added in libzip 1.10.1. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_source_filep.mdoc ================================================ .\" zip_source_filep.mdoc -- create data source from a file stream .\" Copyright (C) 2004-2021 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd June 30, 2023 .Dt ZIP_SOURCE_FILEP 3 .Os .Sh NAME .Nm zip_source_filep , .Nm zip_source_filep_create .Nd create data source from FILE * .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft zip_source_t * .Fn zip_source_filep "zip_t *archive" "FILE *file" "zip_uint64_t start" "zip_int64_t len" .Ft zip_source_t * .Fn zip_source_filep_create "FILE *file" "zip_uint64_t start" "zip_int64_t len" "zip_error_t *error" .Sh DESCRIPTION The functions .Fn zip_source_filep and .Fn zip_source_filep_create create a zip source from a file stream. They read .Ar len bytes from offset .Ar start from the open file stream .Ar file . For a description of the .Ar len argument, see .Xr zip_source_file 3 . .Pp If the file stream supports seeking, the source can be used to open a read-only zip archive from. .Pp The file stream is closed when the source is being freed, usually by .Xr zip_close 3 . .Sh RETURN VALUES Upon successful completion, the created source is returned. Otherwise, .Dv NULL is returned and the error code in .Ar archive or .Ar error is set to indicate the error. .Sh ERRORS .Fn zip_source_filep fails if: .Bl -tag -width Er .It Bq Er ZIP_ER_INVAL .Ar file , .Ar start , or .Ar len are invalid. .It Bq Er ZIP_ER_MEMORY Required memory could not be allocated. .El .Sh SEE ALSO .Xr libzip 3 , .Xr zip_file_add 3 , .Xr zip_file_replace 3 , .Xr zip_source 5 , .Xr zip_source_file 3 .Sh HISTORY .Fn zip_source_filep and .Fn zip_source_filep_create were added in libzip 1.0. .Pp .Dv ZIP_LENGTH_TO_END and .Dv ZIP_LENGTH_UNCHECKED were added in libzip 1.10.1. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_source_free.html ================================================ ================================================ FILE: external/libzip/man/zip_source_free.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_source_free.mdoc -- free zip data source .\" Copyright (C) 2004-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_SOURCE_FREE" "3" "December 18, 2017" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_source_free\fR \- free zip data source .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIvoid\fR .br .PD 0 .HP 4n \fBzip_source_free\fR(\fIzip_source_t\ *source\fR); .PD .SH "DESCRIPTION" The function \fBzip_source_free\fR() decrements the reference count of \fIsource\fR and frees it if the reference count drops to 0. If \fIsource\fR is \fRNULL\fR, it does nothing. .PP \fINOTE\fR: This function should not be called on a \fIsource\fR after it was used successfully in a zip_open_from_source(3), zip_file_add(3), or zip_file_replace(3) call. .SH "SEE ALSO" libzip(3), zip_source(5), zip_source_keep(3) .SH "HISTORY" \fBzip_source_free\fR() was added in libzip 0.6. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_source_free.mdoc ================================================ .\" zip_source_free.mdoc -- free zip data source .\" Copyright (C) 2004-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd December 18, 2017 .Dt ZIP_SOURCE_FREE 3 .Os .Sh NAME .Nm zip_source_free .Nd free zip data source .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft void .Fn zip_source_free "zip_source_t *source" .Sh DESCRIPTION The function .Fn zip_source_free decrements the reference count of .Ar source and frees it if the reference count drops to 0. If .Ar source is .Dv NULL , it does nothing. .Pp .Em NOTE : This function should not be called on a .Ar source after it was used successfully in a .Xr zip_open_from_source 3 , .Xr zip_file_add 3 , or .Xr zip_file_replace 3 call. .Sh SEE ALSO .Xr libzip 3 , .Xr zip_source 5 , .Xr zip_source_keep 3 .Sh HISTORY .Fn zip_source_free was added in libzip 0.6. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_source_function.html ================================================ ================================================ FILE: external/libzip/man/zip_source_function.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_source_function.mdoc -- create data source from function .\" Copyright (C) 2004-2022 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_SOURCE_FUNCTION" "3" "January 5, 2023" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_source_function\fR, \fBzip_source_function_create\fR \- create data source from function .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIzip_source_t *\fR .br .PD 0 .HP 4n \fBzip_source_function\fR(\fIzip_t\ *archive\fR, \fIzip_source_callback\ fn\fR, \fIvoid\ *userdata\fR); .PD .PP \fIzip_source_t *\fR .br .PD 0 .HP 4n \fBzip_source_function_create\fR(\fIzip_source_callback\ fn\fR, \fIvoid\ *userdata\fR, \fIzip_error_t\ *error\fR); .PD .SH "DESCRIPTION" The functions \fBzip_source_function\fR() and \fBzip_source_function_create\fR() create a zip source from the user-provided function \fIfn\fR, which must be of the following type: .PP \fItypedef zip_int64_t\fR \fB\fR(*\fPzip_source_callback\fR)\fP\fR(\fIvoid\ *userdata\fR, \fIvoid\ *data\fR, \fIzip_uint64_t\ len\fR, \fIzip_source_cmd_t\ cmd\fR) .PP \fIarchive\fR or \fIerror\fR are used for reporting errors and can be \fRNULL\fR. .PP When called by the library, the first argument is the \fIuserdata\fR argument supplied to the function. The next two arguments are a buffer \fIdata\fR of size \fIlen\fR when data is passed in or expected to be returned, or else \fRNULL\fR and 0. The last argument, \fIcmd\fR, specifies which action the function should perform. .PP Depending on the uses, there are three useful sets of commands to be supported by a \fBzip_source_callback\fR(): .TP 24n read source Providing streamed data (for file data added to archives). Must support \fRZIP_SOURCE_OPEN\fR, \fRZIP_SOURCE_READ\fR, \fRZIP_SOURCE_CLOSE\fR, \fRZIP_SOURCE_STAT\fR, and \fRZIP_SOURCE_ERROR\fR. .sp If your source uses any allocated memory (including \fIuserdata\fR) it should also implement \fRZIP_SOURCE_FREE\fR to avoid memory leaks. .TP 24n seekable read source Same as previous, but from a source allowing reading from arbitrary offsets (also for read-only zip archive). Must additionally support \fRZIP_SOURCE_SEEK\fR, \fRZIP_SOURCE_TELL\fR, and \fRZIP_SOURCE_SUPPORTS\fR. .TP 24n read/write source Same as previous, but additionally allowing writing (also for writable zip archives). Must additionally support \fRZIP_SOURCE_BEGIN_WRITE\fR, \fRZIP_SOURCE_COMMIT_WRITE\fR, \fRZIP_SOURCE_ROLLBACK_WRITE\fR, \fRZIP_SOURCE_SEEK_WRITE\fR, \fRZIP_SOURCE_TELL_WRITE\fR, and \fRZIP_SOURCE_REMOVE\fR. .sp On top of the above, supporting the pseudo-command \fRZIP_SOURCE_SUPPORTS_REOPEN\fR allows calling \fBzip_source_open\fR() again after calling \fBzip_source_close\fR(). .SS "\fRZIP_SOURCE_ACCEPT_EMPTY\fR" Return 1 if an empty source should be accepted as a valid zip archive. This is the default if this command is not supported by a source. File system backed sources should return 0. .SS "\fRZIP_SOURCE_BEGIN_WRITE\fR" Prepare the source for writing. Use this to create any temporary file(s). .SS "\fRZIP_SOURCE_BEGIN_WRITE_CLONING\fR" Prepare the source for writing, keeping the first \fIlen\fR bytes of the original file. Only implement this command if it is more efficient than copying the data, and if it does not destructively overwrite the original file (you still have to be able to execute \fRZIP_SOURCE_ROLLBACK_WRITE\fR). .PP The next write should happen at byte \fIoffset\fR. .SS "\fRZIP_SOURCE_CLOSE\fR" Reading is done. .SS "\fRZIP_SOURCE_COMMIT_WRITE\fR" Finish writing to the source. Replace the original data with the newly written data. Clean up temporary files or internal buffers. Subsequently opening and reading from the source should return the newly written data. .SS "\fRZIP_SOURCE_ERROR\fR" Get error information. \fIdata\fR points to an array of two ints, which should be filled with the libzip error code and the corresponding system error code for the error that occurred. See zip_errors(3) for details on the error codes. If the source stores error information in a zip_error_t, use zip_error_to_data(3) and return its return value. Otherwise, return 2 * sizeof(int). .SS "\fRZIP_SOURCE_FREE\fR" Clean up and free all resources, including \fIuserdata\fR. The callback function will not be called again. .SS "\fRZIP_SOURCE_GET_FILE_ATTRIBUTES\fR" Provide information about various data. Then the data should be put in the appropriate entry in the passed \fIzip_file_attributes_t\fR argument, and the appropriate \fRZIP_FILE_ATTRIBUTES_*\fR value must be or'ed into the \fIvalid\fR member to denote that the corresponding data has been provided. A \fIzip_file_attributes_t\fR structure can be initialized using zip_file_attributes_init(3). .TP 12n ASCII mode If a file is a plaintext file in ASCII. Can be used by extraction tools to automatically convert line endings (part of the internal file attributes). Member \fIascii\fR, flag \fRZIP_FILE_ATTRIBUTES_ASCII\fR. .TP 12n General Purpose Bit Flags (limited to Compression Flags) The general purpose bit flag in the zip in the local and central directory headers contain information about the compression method. Member \fIgeneral_purpose_bit_flags\fR and \fIgeneral_purpose_bit_mask\fR to denote which members have been set; flag \fRZIP_FILE_ATTRIBUTES_GENERAL_PURPOSE_BIT_FLAGS\fR. .TP 12n External File Attributes The external file attributes (usually operating system-specific). Member \fIexternal_file_attributes\fR, flag \fRZIP_FILE_ATTRIBUTES_EXTERNAL_FILE_ATTRIBUTES\fR. .TP 12n Version Needed A minimum version needed required to unpack this entry (in the usual "major * 10 + minor" format). Member \fIversion_needed\fR, flag \fRZIP_FILE_ATTRIBUTES_VERSION_NEEDED\fR. .TP 12n Operating System One of the operating systems as defined by the \fRZIP_OPSYS_*\fR variables (see \fIzip.h\fR). This value affects the interpretation of the external file attributes. Member \fIhost_system\fR, flag \fRZIP_FILE_ATTRIBUTES_HOST_SYSTEM\fR. .SS "\fRZIP_SOURCE_OPEN\fR" Prepare for reading. .SS "\fRZIP_SOURCE_READ\fR" Read data into the buffer \fIdata\fR of size \fIlen\fR. Return the number of bytes placed into \fIdata\fR on success, and zero for end-of-file. .SS "\fRZIP_SOURCE_REMOVE\fR" Remove the underlying file. This is called if a zip archive is empty when closed. .SS "\fRZIP_SOURCE_ROLLBACK_WRITE\fR" Abort writing to the source. Discard written data. Clean up temporary files or internal buffers. Subsequently opening and reading from the source should return the original data. .SS "\fRZIP_SOURCE_SEEK\fR" Specify position to read next byte from, like fseek(3). Use ZIP_SOURCE_GET_ARGS(3) to decode the arguments into the following struct: .nf .sp .RS 0n struct zip_source_args_seek { zip_int64_t offset; int whence; }; .RE .fi .PP If the size of the source's data is known, use zip_source_seek_compute_offset(3) to validate the arguments and compute the new offset. .SS "\fRZIP_SOURCE_SEEK_WRITE\fR" Specify position to write next byte to, like fseek(3). See \fRZIP_SOURCE_SEEK\fR for details. .SS "\fRZIP_SOURCE_STAT\fR" Get meta information for the input data. \fIdata\fR points to an allocated \fIstruct zip_stat\fR, which should be initialized using zip_stat_init(3) and then filled in. .PP For uncompressed, unencrypted data, all information is optional. However, fill in as much information as is readily available. .PP If the data is compressed, \fRZIP_STAT_COMP_METHOD\fR, \fRZIP_STAT_SIZE\fR, and \fRZIP_STAT_CRC\fR must be filled in. .PP If the data is encrypted, \fRZIP_STAT_ENCRYPTION_METHOD\fR, \fRZIP_STAT_COMP_METHOD\fR, \fRZIP_STAT_SIZE\fR, and \fRZIP_STAT_CRC\fR must be filled in. .PP Information only available after the source has been read (e.g., size) can be omitted in an earlier call. \fINOTE\fR: \fBzip_source_function\fR() may be called with this argument even after being called with \fRZIP_SOURCE_CLOSE\fR. .PP Return sizeof(struct zip_stat) on success. .SS "\fRZIP_SOURCE_SUPPORTS\fR" Return bitmap specifying which commands are supported. Use zip_source_make_command_bitmap(3). If this command is not implemented, the source is assumed to be a read source without seek support. .SS "\fRZIP_SOURCE_TELL\fR" Return the current read offset in the source, like ftell(3). .SS "\fRZIP_SOURCE_TELL_WRITE\fR" Return the current write offset in the source, like ftell(3). .SS "\fRZIP_SOURCE_WRITE\fR" Write data to the source. Return number of bytes written. .SS "\fRZIP_SOURCE_SUPPORTS_REOPEN\fR" This command is never actually invoked, support for it signals the ability to handle multiple open/read/close cycles. .SS "Return Values" Commands should return \-1 on error. \fRZIP_SOURCE_ERROR\fR will be called to retrieve the error code. On success, commands return 0, unless specified otherwise in the description above. .SS "Calling Conventions" The library will always issue \fRZIP_SOURCE_OPEN\fR before issuing \fRZIP_SOURCE_READ\fR, \fRZIP_SOURCE_SEEK\fR, or \fRZIP_SOURCE_TELL\fR. When it no longer wishes to read from this source, it will issue \fRZIP_SOURCE_CLOSE\fR. If the library wishes to read the data again, it will issue \fRZIP_SOURCE_OPEN\fR a second time. If the function is unable to provide the data again, it should return \-1. .PP \fRZIP_SOURCE_BEGIN_WRITE\fR or \fRZIP_SOURCE_BEGIN_WRITE_CLONING\fR will be called before \fRZIP_SOURCE_WRITE\fR, \fRZIP_SOURCE_SEEK_WRITE\fR, or \fRZIP_SOURCE_TELL_WRITE\fR. When writing is complete, either \fRZIP_SOURCE_COMMIT_WRITE\fR or \fRZIP_SOURCE_ROLLBACK_WRITE\fR will be called. .PP \fRZIP_SOURCE_ACCEPT_EMPTY\fR, \fRZIP_SOURCE_GET_FILE_ATTRIBUTES\fR, and \fRZIP_SOURCE_STAT\fR can be issued at any time. .PP \fRZIP_SOURCE_ERROR\fR will only be issued in response to the function returning \-1. .PP \fRZIP_SOURCE_FREE\fR will be the last command issued; if \fRZIP_SOURCE_OPEN\fR was called and succeeded, \fRZIP_SOURCE_CLOSE\fR will be called before \fRZIP_SOURCE_FREE\fR, and similarly for \fRZIP_SOURCE_BEGIN_WRITE\fR or \fRZIP_SOURCE_BEGIN_WRITE_CLONING\fR and \fRZIP_SOURCE_COMMIT_WRITE\fR or \fRZIP_SOURCE_ROLLBACK_WRITE\fR. .SH "RETURN VALUES" Upon successful completion, the created source is returned. Otherwise, \fRNULL\fR is returned and the error code in \fIarchive\fR or \fIerror\fR is set to indicate the error (unless it is \fRNULL\fR). .SH "ERRORS" \fBzip_source_function\fR() fails if: .TP 19n [\fRZIP_ER_MEMORY\fR] Required memory could not be allocated. .SH "SEE ALSO" libzip(3), zip_file_add(3), zip_file_attributes_init(3), zip_file_replace(3), zip_source(5), zip_stat_init(3) .SH "HISTORY" \fBzip_source_function\fR() and \fBzip_source_function_create\fR() were added in libzip 1.0. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_source_function.mdoc ================================================ .\" zip_source_function.mdoc -- create data source from function .\" Copyright (C) 2004-2022 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd January 5, 2023 .Dt ZIP_SOURCE_FUNCTION 3 .Os .Sh NAME .Nm zip_source_function , .Nm zip_source_function_create .Nd create data source from function .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft zip_source_t * .Fn zip_source_function "zip_t *archive" "zip_source_callback fn" "void *userdata" .Ft zip_source_t * .Fn zip_source_function_create "zip_source_callback fn" "void *userdata" "zip_error_t *error" .Sh DESCRIPTION The functions .Fn zip_source_function and .Fn zip_source_function_create create a zip source from the user-provided function .Ar fn , which must be of the following type: .Pp .Ft typedef zip_int64_t .Fo \fR(*\fPzip_source_callback\fR)\fP .Fa "void *userdata" "void *data" "zip_uint64_t len" "zip_source_cmd_t cmd" .Fc .Pp .Ar archive or .Ar error are used for reporting errors and can be .Dv NULL . .Pp When called by the library, the first argument is the .Ar userdata argument supplied to the function. The next two arguments are a buffer .Ar data of size .Ar len when data is passed in or expected to be returned, or else .Dv NULL and 0. The last argument, .Ar cmd , specifies which action the function should perform. .Pp Depending on the uses, there are three useful sets of commands to be supported by a .Fn zip_source_callback : .Bl -tag -width seekable-read-sourceXX .It read source Providing streamed data (for file data added to archives). Must support .Dv ZIP_SOURCE_OPEN , .Dv ZIP_SOURCE_READ , .Dv ZIP_SOURCE_CLOSE , .Dv ZIP_SOURCE_STAT , and .Dv ZIP_SOURCE_ERROR . .Pp If your source uses any allocated memory (including .Ar userdata ) it should also implement .Dv ZIP_SOURCE_FREE to avoid memory leaks. .It seekable read source Same as previous, but from a source allowing reading from arbitrary offsets (also for read-only zip archive). Must additionally support .Dv ZIP_SOURCE_SEEK , .Dv ZIP_SOURCE_TELL , and .Dv ZIP_SOURCE_SUPPORTS . .It read/write source Same as previous, but additionally allowing writing (also for writable zip archives). Must additionally support .Dv ZIP_SOURCE_BEGIN_WRITE , .Dv ZIP_SOURCE_COMMIT_WRITE , .Dv ZIP_SOURCE_ROLLBACK_WRITE , .Dv ZIP_SOURCE_SEEK_WRITE , .Dv ZIP_SOURCE_TELL_WRITE , and .Dv ZIP_SOURCE_REMOVE . .Pp On top of the above, supporting the pseudo-command .Dv ZIP_SOURCE_SUPPORTS_REOPEN allows calling .Fn zip_source_open again after calling .Fn zip_source_close . .El .Ss Dv ZIP_SOURCE_ACCEPT_EMPTY Return 1 if an empty source should be accepted as a valid zip archive. This is the default if this command is not supported by a source. File system backed sources should return 0. .Ss Dv ZIP_SOURCE_BEGIN_WRITE Prepare the source for writing. Use this to create any temporary file(s). .Ss Dv ZIP_SOURCE_BEGIN_WRITE_CLONING Prepare the source for writing, keeping the first .Ar len bytes of the original file. Only implement this command if it is more efficient than copying the data, and if it does not destructively overwrite the original file (you still have to be able to execute .Dv ZIP_SOURCE_ROLLBACK_WRITE ) . .Pp The next write should happen at byte .Ar offset . .Ss Dv ZIP_SOURCE_CLOSE Reading is done. .Ss Dv ZIP_SOURCE_COMMIT_WRITE Finish writing to the source. Replace the original data with the newly written data. Clean up temporary files or internal buffers. Subsequently opening and reading from the source should return the newly written data. .Ss Dv ZIP_SOURCE_ERROR Get error information. .Ar data points to an array of two ints, which should be filled with the libzip error code and the corresponding system error code for the error that occurred. See .Xr zip_errors 3 for details on the error codes. If the source stores error information in a zip_error_t, use .Xr zip_error_to_data 3 and return its return value. Otherwise, return 2 * sizeof(int). .Ss Dv ZIP_SOURCE_FREE Clean up and free all resources, including .Ar userdata . The callback function will not be called again. .Ss Dv ZIP_SOURCE_GET_FILE_ATTRIBUTES Provide information about various data. Then the data should be put in the appropriate entry in the passed .Vt zip_file_attributes_t argument, and the appropriate .Dv ZIP_FILE_ATTRIBUTES_* value must be or'ed into the .Ar valid member to denote that the corresponding data has been provided. A .Vt zip_file_attributes_t structure can be initialized using .Xr zip_file_attributes_init 3 . .Bl -tag -width 10n .It ASCII mode If a file is a plaintext file in ASCII. Can be used by extraction tools to automatically convert line endings (part of the internal file attributes). Member .Ar ascii , flag .Dv ZIP_FILE_ATTRIBUTES_ASCII . .It General Purpose Bit Flags (limited to Compression Flags) The general purpose bit flag in the zip in the local and central directory headers contain information about the compression method. Member .Ar general_purpose_bit_flags and .Ar general_purpose_bit_mask to denote which members have been set; flag .Dv ZIP_FILE_ATTRIBUTES_GENERAL_PURPOSE_BIT_FLAGS . .It External File Attributes The external file attributes (usually operating system-specific). Member .Ar external_file_attributes , flag .Dv ZIP_FILE_ATTRIBUTES_EXTERNAL_FILE_ATTRIBUTES . .It Version Needed A minimum version needed required to unpack this entry (in the usual "major * 10 + minor" format). Member .Ar version_needed , flag .Dv ZIP_FILE_ATTRIBUTES_VERSION_NEEDED . .It Operating System One of the operating systems as defined by the .Dv ZIP_OPSYS_* variables (see .Pa zip.h ) . This value affects the interpretation of the external file attributes. Member .Ar host_system , flag .Dv ZIP_FILE_ATTRIBUTES_HOST_SYSTEM . .El .Ss Dv ZIP_SOURCE_OPEN Prepare for reading. .Ss Dv ZIP_SOURCE_READ Read data into the buffer .Ar data of size .Ar len . Return the number of bytes placed into .Ar data on success, and zero for end-of-file. .Ss Dv ZIP_SOURCE_REMOVE Remove the underlying file. This is called if a zip archive is empty when closed. .Ss Dv ZIP_SOURCE_ROLLBACK_WRITE Abort writing to the source. Discard written data. Clean up temporary files or internal buffers. Subsequently opening and reading from the source should return the original data. .Ss Dv ZIP_SOURCE_SEEK Specify position to read next byte from, like .Xr fseek 3 . Use .Xr ZIP_SOURCE_GET_ARGS 3 to decode the arguments into the following struct: .Bd -literal struct zip_source_args_seek { zip_int64_t offset; int whence; }; .Ed .Pp If the size of the source's data is known, use .Xr zip_source_seek_compute_offset 3 to validate the arguments and compute the new offset. .Ss Dv ZIP_SOURCE_SEEK_WRITE Specify position to write next byte to, like .Xr fseek 3 . See .Dv ZIP_SOURCE_SEEK for details. .Ss Dv ZIP_SOURCE_STAT Get meta information for the input data. .Ar data points to an allocated .Vt struct zip_stat , which should be initialized using .Xr zip_stat_init 3 and then filled in. .Pp For uncompressed, unencrypted data, all information is optional. However, fill in as much information as is readily available. .Pp If the data is compressed, .Dv ZIP_STAT_COMP_METHOD , .Dv ZIP_STAT_SIZE , and .Dv ZIP_STAT_CRC must be filled in. .Pp If the data is encrypted, .Dv ZIP_STAT_ENCRYPTION_METHOD , .Dv ZIP_STAT_COMP_METHOD , .Dv ZIP_STAT_SIZE , and .Dv ZIP_STAT_CRC must be filled in. .Pp Information only available after the source has been read (e.g., size) can be omitted in an earlier call. .Em NOTE : .Fn zip_source_function may be called with this argument even after being called with .Dv ZIP_SOURCE_CLOSE . .Pp Return sizeof(struct zip_stat) on success. .Ss Dv ZIP_SOURCE_SUPPORTS Return bitmap specifying which commands are supported. Use .Xr zip_source_make_command_bitmap 3 . If this command is not implemented, the source is assumed to be a read source without seek support. .Ss Dv ZIP_SOURCE_TELL Return the current read offset in the source, like .Xr ftell 3 . .Ss Dv ZIP_SOURCE_TELL_WRITE Return the current write offset in the source, like .Xr ftell 3 . .Ss Dv ZIP_SOURCE_WRITE Write data to the source. Return number of bytes written. .Ss Dv ZIP_SOURCE_SUPPORTS_REOPEN This command is never actually invoked, support for it signals the ability to handle multiple open/read/close cycles. .Ss Return Values Commands should return \-1 on error. .Dv ZIP_SOURCE_ERROR will be called to retrieve the error code. On success, commands return 0, unless specified otherwise in the description above. .Ss Calling Conventions The library will always issue .Dv ZIP_SOURCE_OPEN before issuing .Dv ZIP_SOURCE_READ , .Dv ZIP_SOURCE_SEEK , or .Dv ZIP_SOURCE_TELL . When it no longer wishes to read from this source, it will issue .Dv ZIP_SOURCE_CLOSE . If the library wishes to read the data again, it will issue .Dv ZIP_SOURCE_OPEN a second time. If the function is unable to provide the data again, it should return \-1. .Pp .Dv ZIP_SOURCE_BEGIN_WRITE or .Dv ZIP_SOURCE_BEGIN_WRITE_CLONING will be called before .Dv ZIP_SOURCE_WRITE , .Dv ZIP_SOURCE_SEEK_WRITE , or .Dv ZIP_SOURCE_TELL_WRITE . When writing is complete, either .Dv ZIP_SOURCE_COMMIT_WRITE or .Dv ZIP_SOURCE_ROLLBACK_WRITE will be called. .Pp .Dv ZIP_SOURCE_ACCEPT_EMPTY , .Dv ZIP_SOURCE_GET_FILE_ATTRIBUTES , and .Dv ZIP_SOURCE_STAT can be issued at any time. .Pp .Dv ZIP_SOURCE_ERROR will only be issued in response to the function returning \-1. .Pp .Dv ZIP_SOURCE_FREE will be the last command issued; if .Dv ZIP_SOURCE_OPEN was called and succeeded, .Dv ZIP_SOURCE_CLOSE will be called before .Dv ZIP_SOURCE_FREE , and similarly for .Dv ZIP_SOURCE_BEGIN_WRITE or .Dv ZIP_SOURCE_BEGIN_WRITE_CLONING and .Dv ZIP_SOURCE_COMMIT_WRITE or .Dv ZIP_SOURCE_ROLLBACK_WRITE . .Sh RETURN VALUES Upon successful completion, the created source is returned. Otherwise, .Dv NULL is returned and the error code in .Ar archive or .Ar error is set to indicate the error (unless it is .Dv NULL ) . .Sh ERRORS .Fn zip_source_function fails if: .Bl -tag -width Er .It Bq Er ZIP_ER_MEMORY Required memory could not be allocated. .El .Sh SEE ALSO .Xr libzip 3 , .Xr zip_file_add 3 , .Xr zip_file_attributes_init 3 , .Xr zip_file_replace 3 , .Xr zip_source 5 , .Xr zip_stat_init 3 .Sh HISTORY .Fn zip_source_function and .Fn zip_source_function_create were added in libzip 1.0. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_source_is_deleted.html ================================================ ================================================ FILE: external/libzip/man/zip_source_is_deleted.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_source_is_deleted.mdoc -- check if zip source is deleted .\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_SOURCE_IS_DELETED" "3" "December 18, 2017" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_source_is_deleted\fR \- check if zip_source is deleted .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIint\fR .br .PD 0 .HP 4n \fBzip_source_is_deleted\fR(\fIzip_source_t\ *source\fR); .PD .SH "DESCRIPTION" The function \fBzip_source_is_deleted\fR() returns whether the zip_source was deleted. This can for example happen when all entries are removed from a zip archive. .SH "RETURN VALUES" \fBzip_source_is_deleted\fR() returns 1 if the zip_source is deleted and 0 otherwise. .SH "SEE ALSO" libzip(3), zip_source(5) .SH "HISTORY" \fBzip_source_is_deleted\fR() was added in libzip 1.0. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_source_is_deleted.mdoc ================================================ .\" zip_source_is_deleted.mdoc -- check if zip source is deleted .\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd December 18, 2017 .Dt ZIP_SOURCE_IS_DELETED 3 .Os .Sh NAME .Nm zip_source_is_deleted .Nd check if zip_source is deleted .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft int .Fn zip_source_is_deleted "zip_source_t *source" .Sh DESCRIPTION The function .Fn zip_source_is_deleted returns whether the zip_source was deleted. This can for example happen when all entries are removed from a zip archive. .Sh RETURN VALUES .Fn zip_source_is_deleted returns 1 if the zip_source is deleted and 0 otherwise. .Sh SEE ALSO .Xr libzip 3 , .Xr zip_source 5 .Sh HISTORY .Fn zip_source_is_deleted was added in libzip 1.0. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_source_is_seekable.html ================================================ ================================================ FILE: external/libzip/man/zip_source_is_seekable.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_source_seek.mdoc -- set read offset in source .\" Copyright (C) 2023 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_SOURCE_IS_SEEKABLE" "3" "March 10, 2023" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_source_is_seekable\fR \- check if a source supports seeking .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIint\fR .br .PD 0 .HP 4n \fBzip_source_is_seekable\fR(\fIzip_source_t\ *source\fR); .PD .SH "DESCRIPTION" The function \fBzip_source_is_seekable\fR() checks if \fIsource\fR supports seeking via zip_source_seek(3). .SH "RETURN VALUES" If the source supports seeking, 1 is returned. Otherwise, 0 is returned. .SH "SEE ALSO" libzip(3), zip_source(5), zip_source_seek(3) .SH "HISTORY" \fBzip_source_is_seekable\fR() was added in libzip 1.10.0. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_source_is_seekable.mdoc ================================================ .\" zip_source_seek.mdoc -- set read offset in source .\" Copyright (C) 2023 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd March 10, 2023 .Dt ZIP_SOURCE_IS_SEEKABLE 3 .Os .Sh NAME .Nm zip_source_is_seekable .Nd check if a source supports seeking .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft int .Fn zip_source_is_seekable "zip_source_t *source" .Sh DESCRIPTION The function .Fn zip_source_is_seekable checks if .Fa source supports seeking via .Xr zip_source_seek 3 . .Sh RETURN VALUES If the source supports seeking, 1 is returned. Otherwise, 0 is returned. .Sh SEE ALSO .Xr libzip 3 , .Xr zip_source 5 , .Xr zip_source_seek 3 .Sh HISTORY .Fn zip_source_is_seekable was added in libzip 1.10.0. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_source_keep.html ================================================ ================================================ FILE: external/libzip/man/zip_source_keep.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_source_keep.mdoc -- increment reference count of zip data source .\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_SOURCE_KEEP" "3" "December 18, 2017" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_source_keep\fR \- increment reference count of zip data source .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIvoid\fR .br .PD 0 .HP 4n \fBzip_source_keep\fR(\fIzip_source_t\ *source\fR); .PD .SH "DESCRIPTION" The function \fBzip_source_keep\fR() increments the reference count of \fIsource\fR. .SH "SEE ALSO" libzip(3), zip_source(5), zip_source_free(3) .SH "HISTORY" \fBzip_source_keep\fR() was added in libzip 1.0. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_source_keep.mdoc ================================================ .\" zip_source_keep.mdoc -- increment reference count of zip data source .\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd December 18, 2017 .Dt ZIP_SOURCE_KEEP 3 .Os .Sh NAME .Nm zip_source_keep .Nd increment reference count of zip data source .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft void .Fn zip_source_keep "zip_source_t *source" .Sh DESCRIPTION The function .Fn zip_source_keep increments the reference count of .Ar source . .Sh SEE ALSO .Xr libzip 3 , .Xr zip_source 5 , .Xr zip_source_free 3 .Sh HISTORY .Fn zip_source_keep was added in libzip 1.0. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_source_layered.html ================================================ ================================================ FILE: external/libzip/man/zip_source_layered.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_source_layered.mdoc -- create layered source from function .\" Copyright (C) 2004-2022 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_SOURCE_LAYERED" "3" "January 20, 2023" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_source_layered\fR, \fBzip_source_layered_create\fR \- create layered data source from function .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIzip_source_t *\fR .br .PD 0 .HP 4n \fBzip_source_layered\fR(\fIzip_t\ *archive\fR, \fIzip_source_t\ *source\fR, \fIzip_source_layered_callback\ fn\fR, \fIvoid\ *userdata\fR); .PD .PP \fIzip_source_t *\fR .br .PD 0 .HP 4n \fBzip_source_layered_create\fR(\fIzip_source_t\ *source\fR, \fIzip_source_layered_callback\ fn\fR, \fIvoid\ *userdata\fR, \fIzip_error_t\ *error\fR); .PD .SH "DESCRIPTION" The functions \fBzip_source_layered\fR() and \fBzip_source_layered_create\fR() create a layered zip source from the user-provided function \fIfn\fR, which must be of the following type: .PP \fItypedef zip_int64_t\fR \fB\fR(*\zip_source_layered_callback\fR)\fP\fR(\fIzip_source_t\ *source\fR, \fIvoid\ *userdata\fR, \fIvoid\ *data\fR, \fIzip_uint64_t\ length\fR, \fIzip_source_cmd_t\ cmd\fR) .PP \fIarchive\fR or \fIerror\fR are used for reporting errors and can be \fRNULL\fR. .PP When called by the library, the first argument is the \fIsource\fR of the lower layer, the second argument is the \fIuserdata\fR argument supplied to the function. The next two arguments are a buffer \fIdata\fR of size \fIlength\fR when data is passed in or expected to be returned, or else \fRNULL\fR and 0. The last argument, \fIcmd\fR, specifies which action the function should perform. .PP See zip_source_function(3) for a description of the commands. .PP A layered source transforms the data or metadata of the source below in some way. Layered sources can't support writing and are not sufficient to cleanly add support for additional compression or encryption methods. This may be revised in a later release of libzip. .PP On success, the layered source takes ownership of \fIsource\fR. The caller should not free it. .PP The interaction with the lower layer depends on the command: .SS "\fRZIP_SOURCE_ACCEPT_EMPTY\fR" If the layered source supports this command, the lower layer is not called automatically. Otherwise, the return value of the lower source is used. .SS "\fRZIP_SOURCE_CLOSE\fR" The lower layer is closed after the callback returns. .SS "\fRZIP_SOURCE_ERROR\fR" The lower layer is not called automatically. If you need to retrieve error information from the lower layer, use zip_error_set_from_source(3) or zip_source_pass_to_lower_layer(3). .SS "\fRZIP_SOURCE_FREE\fR" The lower layer is freed after the callback returns. .SS "\fRZIP_SOURCE_GET_FILE_ATTRIBUTES\fR" The attributes of the lower layer are merged with the attributes returned by the callback: information set by the callback wins over the lower layer, with the following exceptions: the higher \fIversion_needed\fR is used, and \fIgeneral_purpose_bit_flags\fR are only overwritten if the corresponding bit is set in \fIgeneral_purpose_bit_mask\fR. .SS "\fRZIP_SOURCE_OPEN\fR" The lower layer is opened before the callback is called. .SS "\fRZIP_SOURCE_READ\fR" The lower layer is not called automatically. .SS "\fRZIP_SOURCE_SEEK\fR" The lower layer is not called automatically. .SS "\fRZIP_SOURCE_STAT\fR" \fIdata\fR contains the stat information from the lower layer when the callback is called. .SS "\fRZIP_SOURCE_SUPPORTS\fR" \fIdata\fR contains the bitmap of commands supported by the lower layer when the callback is called. Since layered sources can't support writing, all commands related to writing are stripped from the returned support bitmap. .SS "\fRZIP_SOURCE_TELL\fR" The lower layer is not called automatically. .SH "RETURN VALUES" Upon successful completion, the created source is returned. Otherwise, \fRNULL\fR is returned and the error code in \fIarchive\fR or \fIerror\fR is set to indicate the error (unless it is \fRNULL\fR). .SH "ERRORS" \fBzip_source_layered\fR() fails if: .TP 19n [\fRZIP_ER_MEMORY\fR] Required memory could not be allocated. .SH "SEE ALSO" libzip(3), zip_file_add(3), zip_file_attributes_init(3), zip_file_replace(3), zip_source(5), zip_source_function(3), zip_source_pass_to_lower_layer(3) .SH "HISTORY" \fBzip_source_layered\fR() and \fBzip_source_layered_create\fR() were added in libzip 1.10. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_source_layered.mdoc ================================================ .\" zip_source_layered.mdoc -- create layered source from function .\" Copyright (C) 2004-2022 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd January 20, 2023 .Dt ZIP_SOURCE_LAYERED 3 .Os .Sh NAME .Nm zip_source_layered , .Nm zip_source_layered_create .Nd create layered data source from function .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft zip_source_t * .Fn zip_source_layered "zip_t *archive" "zip_source_t *source" "zip_source_layered_callback fn" "void *userdata" .Ft zip_source_t * .Fn zip_source_layered_create "zip_source_t *source" "zip_source_layered_callback fn" "void *userdata" "zip_error_t *error" .Sh DESCRIPTION The functions .Fn zip_source_layered and .Fn zip_source_layered_create create a layered zip source from the user-provided function .Ar fn , which must be of the following type: .Pp .Ft typedef zip_int64_t .Fo \fR(*\zip_source_layered_callback\fR)\fP .Fa "zip_source_t *source" "void *userdata" "void *data" "zip_uint64_t length" "zip_source_cmd_t cmd" .Fc .Pp .Ar archive or .Ar error are used for reporting errors and can be .Dv NULL . .Pp When called by the library, the first argument is the .Ar source of the lower layer, the second argument is the .Ar userdata argument supplied to the function. The next two arguments are a buffer .Ar data of size .Ar length when data is passed in or expected to be returned, or else .Dv NULL and 0. The last argument, .Ar cmd , specifies which action the function should perform. .Pp See .Xr zip_source_function 3 for a description of the commands. .Pp A layered source transforms the data or metadata of the source below in some way. Layered sources can't support writing and are not sufficient to cleanly add support for additional compression or encryption methods. This may be revised in a later release of libzip. .Pp On success, the layered source takes ownership of .Ar source . The caller should not free it. .Pp The interaction with the lower layer depends on the command: .Ss Dv ZIP_SOURCE_ACCEPT_EMPTY If the layered source supports this command, the lower layer is not called automatically. Otherwise, the return value of the lower source is used. .Ss Dv ZIP_SOURCE_CLOSE The lower layer is closed after the callback returns. .Ss Dv ZIP_SOURCE_ERROR The lower layer is not called automatically. If you need to retrieve error information from the lower layer, use .Xr zip_error_set_from_source 3 or .Xr zip_source_pass_to_lower_layer 3 . .Ss Dv ZIP_SOURCE_FREE The lower layer is freed after the callback returns. .Ss Dv ZIP_SOURCE_GET_FILE_ATTRIBUTES The attributes of the lower layer are merged with the attributes returned by the callback: information set by the callback wins over the lower layer, with the following exceptions: the higher .Ar version_needed is used, and .Ar general_purpose_bit_flags are only overwritten if the corresponding bit is set in .Ar general_purpose_bit_mask . .Ss Dv ZIP_SOURCE_OPEN The lower layer is opened before the callback is called. .Ss Dv ZIP_SOURCE_READ The lower layer is not called automatically. .Ss Dv ZIP_SOURCE_SEEK The lower layer is not called automatically. .Ss Dv ZIP_SOURCE_STAT .Ar data contains the stat information from the lower layer when the callback is called. .Ss Dv ZIP_SOURCE_SUPPORTS .Ar data contains the bitmap of commands supported by the lower layer when the callback is called. Since layered sources can't support writing, all commands related to writing are stripped from the returned support bitmap. .Ss Dv ZIP_SOURCE_TELL The lower layer is not called automatically. .Sh RETURN VALUES Upon successful completion, the created source is returned. Otherwise, .Dv NULL is returned and the error code in .Ar archive or .Ar error is set to indicate the error (unless it is .Dv NULL ) . .Sh ERRORS .Fn zip_source_layered fails if: .Bl -tag -width Er .It Bq Er ZIP_ER_MEMORY Required memory could not be allocated. .El .Sh SEE ALSO .Xr libzip 3 , .Xr zip_file_add 3 , .Xr zip_file_attributes_init 3 , .Xr zip_file_replace 3 , .Xr zip_source 5 , .Xr zip_source_function 3 , .Xr zip_source_pass_to_lower_layer 3 .Sh HISTORY .Fn zip_source_layered and .Fn zip_source_layered_create were added in libzip 1.10. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_source_make_command_bitmap.html ================================================ ================================================ FILE: external/libzip/man/zip_source_make_command_bitmap.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_source_make_command_bitmap -- create bitmap of supported source operations .\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_SOURCE_MAKE_COMMAND_BITMAP" "3" "December 18, 2017" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_source_make_command_bitmap\fR \- create bitmap of supported source operations .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIzip_int64_t\fR .br .PD 0 .HP 4n \fBzip_source_make_command_bitmap\fR(\fIzip_source_cmd_t\ command\fR, \fI...\fR); .PD .SH "DESCRIPTION" The \fBzip_source_make_command_bitmap\fR() function returns a bitmap of source commands suitable as return value for \fRZIP_SOURCE_SUPPORTS\fR. It includes all the commands from the argument list, which must be terminated by \-1. .SH "SEE ALSO" libzip(3), zip_source_function(3) .SH "HISTORY" \fBzip_source_make_command_bitmap\fR() was added in libzip 1.0. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_source_make_command_bitmap.mdoc ================================================ .\" zip_source_make_command_bitmap -- create bitmap of supported source operations .\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd December 18, 2017 .Dt ZIP_SOURCE_MAKE_COMMAND_BITMAP 3 .Os .Sh NAME .Nm zip_source_make_command_bitmap .Nd create bitmap of supported source operations .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft zip_int64_t .Fn zip_source_make_command_bitmap "zip_source_cmd_t command" "..." .Sh DESCRIPTION The .Fn zip_source_make_command_bitmap function returns a bitmap of source commands suitable as return value for .Dv ZIP_SOURCE_SUPPORTS . It includes all the commands from the argument list, which must be terminated by \-1. .Sh SEE ALSO .Xr libzip 3 , .Xr zip_source_function 3 .Sh HISTORY .Fn zip_source_make_command_bitmap was added in libzip 1.0. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_source_open.html ================================================ ================================================ FILE: external/libzip/man/zip_source_open.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_source_open.mdoc -- open zip source for reading .\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_SOURCE_OPEN" "3" "December 18, 2017" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_source_open\fR \- open zip_source for reading .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIint\fR .br .PD 0 .HP 4n \fBzip_source_open\fR(\fIzip_source_t\ *source\fR); .PD .SH "DESCRIPTION" The function \fBzip_source_open\fR() opens \fIsource\fR for reading. .SH "RETURN VALUES" Upon successful completion 0 is returned. Otherwise, \-1 is returned and the error information in \fIsource\fR is set to indicate the error. .SH "SEE ALSO" libzip(3), zip_source(5), zip_source_begin_write(3), zip_source_close(3), zip_source_read(3), zip_source_seek(3), zip_source_tell(3) .SH "HISTORY" \fBzip_source_open\fR() was added in libzip 1.0. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_source_open.mdoc ================================================ .\" zip_source_open.mdoc -- open zip source for reading .\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd December 18, 2017 .Dt ZIP_SOURCE_OPEN 3 .Os .Sh NAME .Nm zip_source_open .Nd open zip_source for reading .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft int .Fn zip_source_open "zip_source_t *source" .Sh DESCRIPTION The function .Fn zip_source_open opens .Fa source for reading. .Sh RETURN VALUES Upon successful completion 0 is returned. Otherwise, \-1 is returned and the error information in .Ar source is set to indicate the error. .Sh SEE ALSO .Xr libzip 3 , .Xr zip_source 5 , .Xr zip_source_begin_write 3 , .Xr zip_source_close 3 , .Xr zip_source_read 3 , .Xr zip_source_seek 3 , .Xr zip_source_tell 3 .Sh HISTORY .Fn zip_source_open was added in libzip 1.0. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_source_pass_to_lower_layer.mdoc ================================================ .\" zip_source_pass_to_lower_layer.mdoc -- pass command to lower layer .\" Copyright (C) 2022 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd December 5, 2022 .Dt ZIP_SOURCE_PASS_TO_LOWER_LAYER 3 .Os .Sh NAME .Nm zip_source_pass_to_lower_layer .Nd pass command to lower layer .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft zip_int64_t .Fn zip_source_pass_to_lower_layer "zip_source_t *source" "void *data" "zip_uint64_t length" "zip_source_cmd_t command" .Sh DESCRIPTION The functions .Fn zip_source_pass_to_lower_layer is used in a layered source callback to pass commands for which you don't want to change the result to the lower layer. You can use it in the .Dv default case of the callback. .Sh RETURN VALUES The return value is meant to be returned by the callback. .Sh SEE ALSO .Xr libzip 3 , .Xr zip_source 5 , .Xr zip_source_layered 3 .Sh HISTORY .Fn zip_source_pass_to_lower_layer was added in libzip 1.10. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_source_read.html ================================================ ================================================ FILE: external/libzip/man/zip_source_read.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_source_read.mdoc -- read data from zip source .\" Copyright (C) 2014-2022 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_SOURCE_READ" "3" "September 28, 2021" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_source_read\fR \- read data from zip source .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIzip_int64_t\fR .br .PD 0 .HP 4n \fBzip_source_read\fR(\fIzip_source_t\ *source\fR, \fIvoid\ *data\fR, \fIzip_uint64_t\ len\fR); .PD .SH "DESCRIPTION" The function \fBzip_source_read\fR() reads up to \fIlen\fR bytes of data from \fIsource\fR at the current read offset into the buffer \fIdata\fR. .PP The zip source \fIsource\fR has to be opened for reading by calling zip_source_open(3) first. .SH "RETURN VALUES" Upon successful completion the number of bytes read is returned. When \fBzip_source_read\fR() is called after reaching the end of the file, 0 is returned. Otherwise, \-1 is returned and the error information in \fIsource\fR is set to indicate the error. .SH "SEE ALSO" libzip(3), zip_source(5), zip_source_seek(3), zip_source_tell(3), zip_source_write(3) .SH "HISTORY" \fBzip_source_read\fR() was added in libzip 1.0. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_source_read.mdoc ================================================ .\" zip_source_read.mdoc -- read data from zip source .\" Copyright (C) 2014-2022 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd September 28, 2021 .Dt ZIP_SOURCE_READ 3 .Os .Sh NAME .Nm zip_source_read .Nd read data from zip source .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft zip_int64_t .Fn zip_source_read "zip_source_t *source" "void *data" "zip_uint64_t len" .Sh DESCRIPTION The function .Fn zip_source_read reads up to .Ar len bytes of data from .Ar source at the current read offset into the buffer .Ar data . .Pp The zip source .Ar source has to be opened for reading by calling .Xr zip_source_open 3 first. .Sh RETURN VALUES Upon successful completion the number of bytes read is returned. When .Fn zip_source_read is called after reaching the end of the file, 0 is returned. Otherwise, \-1 is returned and the error information in .Ar source is set to indicate the error. .Sh SEE ALSO .Xr libzip 3 , .Xr zip_source 5 , .Xr zip_source_seek 3 , .Xr zip_source_tell 3 , .Xr zip_source_write 3 .Sh HISTORY .Fn zip_source_read was added in libzip 1.0. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_source_rollback_write.html ================================================ ================================================ FILE: external/libzip/man/zip_source_rollback_write.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_source_rollback_write.mdoc -- undo changes to zip source .\" Copyright (C) 2014-2022 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_SOURCE_ROLLBACK_WRITE" "3" "November 3, 2021" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_source_rollback_write\fR \- undo changes to zip source .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIvoid\fR .br .PD 0 .HP 4n \fBzip_source_rollback_write\fR(\fIzip_source_t\ *source\fR); .PD .SH "DESCRIPTION" The function \fBzip_source_rollback_write\fR() reverts changes written to \fIsource\fR, restoring the data before zip_source_begin_write(3) was called. Usually this removes temporary files or frees buffers. .SH "SEE ALSO" libzip(3), zip_source(5), zip_source_begin_write(3), zip_source_commit_write(3), zip_source_seek_write(3), zip_source_tell_write(3), zip_source_write(3) .SH "HISTORY" \fBzip_source_rollback_write\fR() was added in libzip 1.0. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_source_rollback_write.mdoc ================================================ .\" zip_source_rollback_write.mdoc -- undo changes to zip source .\" Copyright (C) 2014-2022 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd November 3, 2021 .Dt ZIP_SOURCE_ROLLBACK_WRITE 3 .Os .Sh NAME .Nm zip_source_rollback_write .Nd undo changes to zip source .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft void .Fn zip_source_rollback_write "zip_source_t *source" .Sh DESCRIPTION The function .Fn zip_source_rollback_write reverts changes written to .Fa source , restoring the data before .Xr zip_source_begin_write 3 was called. Usually this removes temporary files or frees buffers. .Sh SEE ALSO .Xr libzip 3 , .Xr zip_source 5 , .Xr zip_source_begin_write 3 , .Xr zip_source_commit_write 3 , .Xr zip_source_seek_write 3 , .Xr zip_source_tell_write 3 , .Xr zip_source_write 3 .Sh HISTORY .Fn zip_source_rollback_write was added in libzip 1.0. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_source_seek.html ================================================ ================================================ FILE: external/libzip/man/zip_source_seek.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_source_seek.mdoc -- set read offset in source .\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_SOURCE_SEEK" "3" "March 10, 2023" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_source_seek\fR \- set read offset in zip source .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIint\fR .br .PD 0 .HP 4n \fBzip_source_seek\fR(\fIzip_source_t\ *source\fR, \fIzip_int64_t\ offset\fR, \fIint\ whence\fR); .PD .SH "DESCRIPTION" The function \fBzip_source_seek\fR() sets the current read offset for \fIsource\fR. Just like in fseek(3), depending on the \fIwhence\fR argument, the \fIoffset\fR is counted relative from: .RS 6n .TP 12n \fRSEEK_SET\fR start of file .TP 12n \fRSEEK_CUR\fR current read offset in file .TP 12n \fRSEEK_END\fR end of file .RE .SH "RETURN VALUES" Upon successful completion 0 is returned. Otherwise, \-1 is returned and the error information in \fIsource\fR is set to indicate the error. .SH "SEE ALSO" libzip(3), zip_source(5), zip_source_is_seekable(3), zip_source_read(3), zip_source_tell(3) .SH "HISTORY" \fBzip_source_seek\fR() was added in libzip 1.0. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_source_seek.mdoc ================================================ .\" zip_source_seek.mdoc -- set read offset in source .\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd March 10, 2023 .Dt ZIP_SOURCE_SEEK 3 .Os .Sh NAME .Nm zip_source_seek .Nd set read offset in zip source .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft int .Fn zip_source_seek "zip_source_t *source" "zip_int64_t offset" "int whence" .Sh DESCRIPTION The function .Fn zip_source_seek sets the current read offset for .Fa source . Just like in .Xr fseek 3 , depending on the .Ar whence argument, the .Ar offset is counted relative from: .Bl -tag -width SEEK_CURXX -offset indent .It Dv SEEK_SET start of file .It Dv SEEK_CUR current read offset in file .It Dv SEEK_END end of file .El .Sh RETURN VALUES Upon successful completion 0 is returned. Otherwise, \-1 is returned and the error information in .Ar source is set to indicate the error. .Sh SEE ALSO .Xr libzip 3 , .Xr zip_source 5 , .Xr zip_source_is_seekable 3 , .Xr zip_source_read 3 , .Xr zip_source_tell 3 .Sh HISTORY .Fn zip_source_seek was added in libzip 1.0. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_source_seek_compute_offset.html ================================================ ================================================ FILE: external/libzip/man/zip_source_seek_compute_offset.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_source_seek_compute_offset.mdoc - validate arguments and compute offset .\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_SOURCE_SEEK_COMPUTE_OFFSET" "3" "December 18, 2017" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_source_seek_compute_offset\fR \- validate arguments and compute offset .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIzip_int64_t\fR .br .PD 0 .HP 4n \fBzip_source_seek_compute_offset\fR(\fIzip_uint64_t\ offset\fR, \fIzip_uint64_t\ length\fR, \fIvoid\ *data\fR, \fIzip_uint64_t\ data_length\fR, \fIzip_error_t\ *error\fR); .PD .SH "DESCRIPTION" Use this function to compute the offset for a \fRZIP_SOURCE_SEEK\fR or \fRZIP_SOURCE_SEEK_WRITE\fR command. \fIdata\fR and \fIdata_length\fR are the arguments to the source callback, \fIoffset\fR is the current offset and \fIlength\fR is the length of the source data or, for \fRZIP_SOURCE_SEEK_WRITE\fR, the amount of data written. .SH "RETURN VALUES" On success, it returns the new offset, on error it returns \-1 and sets \fIerror\fR. .SH "ERRORS" \fBzip_source_seek_compute_offset\fR() fails if: .TP 19n [\fRZIP_ER_INVAL\fR] One of the arguments is invalid or the seek would place the offset outside the data. .SH "SEE ALSO" zip_source_function(3) .SH "HISTORY" \fBzip_source_seek_compute_offset\fR() was added in libzip 1.0. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_source_seek_compute_offset.mdoc ================================================ .\" zip_source_seek_compute_offset.mdoc - validate arguments and compute offset .\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd December 18, 2017 .Dt ZIP_SOURCE_SEEK_COMPUTE_OFFSET 3 .Os .Sh NAME .Nm zip_source_seek_compute_offset .Nd validate arguments and compute offset .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft zip_int64_t .Fn zip_source_seek_compute_offset "zip_uint64_t offset" "zip_uint64_t length" "void *data" "zip_uint64_t data_length" "zip_error_t *error" .Sh DESCRIPTION Use this function to compute the offset for a .Dv ZIP_SOURCE_SEEK or .Dv ZIP_SOURCE_SEEK_WRITE command. .Ar data and .Ar data_length are the arguments to the source callback, .Ar offset is the current offset and .Ar length is the length of the source data or, for .Dv ZIP_SOURCE_SEEK_WRITE , the amount of data written. .Sh RETURN VALUES On success, it returns the new offset, on error it returns \-1 and sets .Ar error . .Sh ERRORS .Fn zip_source_seek_compute_offset fails if: .Bl -tag -width Er .It Bq Er ZIP_ER_INVAL One of the arguments is invalid or the seek would place the offset outside the data. .El .Sh SEE ALSO .Xr zip_source_function 3 .Sh HISTORY .Fn zip_source_seek_compute_offset was added in libzip 1.0. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_source_seek_write.html ================================================ ================================================ FILE: external/libzip/man/zip_source_seek_write.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_source_seek_write.mdoc -- set write offset in source .\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_SOURCE_SEEK_WRITE" "3" "December 18, 2017" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_source_seek_write\fR \- set write offset in zip source .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIint\fR .br .PD 0 .HP 4n \fBzip_source_seek_write\fR(\fIzip_source_t\ *source\fR, \fIzip_int64_t\ offset\fR, \fIint\ whence\fR); .PD .SH "DESCRIPTION" The function \fBzip_source_seek_write\fR() sets the current write offset for \fIsource\fR. Just like in fseek(3), depending on the \fIwhence\fR argument, the \fIoffset\fR is counted relative from: .RS 6n .TP 12n \fRSEEK_SET\fR start of file .TP 12n \fRSEEK_CUR\fR current write offset in file .TP 12n \fRSEEK_END\fR end of file .RE .SH "RETURN VALUES" Upon successful completion 0 is returned. Otherwise, \-1 is returned and the error information in \fIsource\fR is set to indicate the error. .SH "SEE ALSO" libzip(3), zip_source(5), zip_source_begin_write(3), zip_source_commit_write(3), zip_source_rollback_write(3), zip_source_tell_write(3), zip_source_write(3) .SH "HISTORY" \fBzip_source_seek_write\fR() was added in libzip 1.0. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_source_seek_write.mdoc ================================================ .\" zip_source_seek_write.mdoc -- set write offset in source .\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd December 18, 2017 .Dt ZIP_SOURCE_SEEK_WRITE 3 .Os .Sh NAME .Nm zip_source_seek_write .Nd set write offset in zip source .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft int .Fn zip_source_seek_write "zip_source_t *source" "zip_int64_t offset" "int whence" .Sh DESCRIPTION The function .Fn zip_source_seek_write sets the current write offset for .Fa source . Just like in .Xr fseek 3 , depending on the .Ar whence argument, the .Ar offset is counted relative from: .Bl -tag -width SEEK_CURXX -offset indent .It Dv SEEK_SET start of file .It Dv SEEK_CUR current write offset in file .It Dv SEEK_END end of file .El .Sh RETURN VALUES Upon successful completion 0 is returned. Otherwise, \-1 is returned and the error information in .Ar source is set to indicate the error. .Sh SEE ALSO .Xr libzip 3 , .Xr zip_source 5 , .Xr zip_source_begin_write 3 , .Xr zip_source_commit_write 3 , .Xr zip_source_rollback_write 3 , .Xr zip_source_tell_write 3 , .Xr zip_source_write 3 .Sh HISTORY .Fn zip_source_seek_write was added in libzip 1.0. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_source_stat.html ================================================ ================================================ FILE: external/libzip/man/zip_source_stat.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_source_stat.mdoc -- get information about zip source .\" Copyright (C) 2014-2021 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_SOURCE_STAT" "3" "December 18, 2017" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_source_stat\fR \- get information about zip_source .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIint\fR .br .PD 0 .HP 4n \fBzip_source_stat\fR(\fIzip_source_t\ *source\fR, \fIzip_stat_t\ *sb\fR); .PD .SH "DESCRIPTION" The \fBzip_source_stat\fR() function obtains information about the zip source \fIsource\fR .PP The \fIsb\fR argument is a pointer to a \fIstruct zip_source_stat\fR (shown below), into which information about the zip source is placed. .nf .sp .RS 0n struct zip_source_stat { zip_uint64_t valid; /* which fields have valid values */ const char *name; /* name of the file */ zip_uint64_t index; /* index within archive */ zip_uint64_t size; /* size of file (uncompressed) */ zip_uint64_t comp_size; /* size of file (compressed) */ time_t mtime; /* modification time */ zip_uint32_t crc; /* crc of file data */ zip_uint16_t comp_method; /* compression method used */ zip_uint16_t encryption_method; /* encryption method used */ zip_uint32_t flags; /* reserved for future use */ }; .RE .fi The structure pointed to by \fIsb\fR must be initialized with \fBzip_stat_init\fR(\fI3\fR) before calling \fBzip_source_stat\fR(). .PP The \fIvalid\fR field of the structure specifies which other fields are valid. Check if the flag defined by the following defines are in \fIvalid\fR before accessing the fields: .RS 6n .PD 0 .TP 30n \fRZIP_STAT_NAME\fR \fIname\fR .TP 30n \fRZIP_STAT_INDEX\fR \fIindex\fR .TP 30n \fRZIP_STAT_SIZE\fR \fIsize\fR .TP 30n \fRZIP_STAT_COMP_SIZE\fR \fIcomp_size\fR .TP 30n \fRZIP_STAT_MTIME\fR \fImtime\fR .TP 30n \fRZIP_STAT_CRC\fR \fIcrc\fR .TP 30n \fRZIP_STAT_COMP_METHOD\fR \fIcomp_method\fR .TP 30n \fRZIP_STAT_ENCRYPTION_METHOD\fR \fIencryption_method\fR .TP 30n \fRZIP_STAT_FLAGS\fR \fIflags\fR .RE .PD .PP \fINOTE\fR: Some fields may only be filled out after all data has been read from the source, for example the \fIcrc\fR or \fIsize\fR fields. .SH "RETURN VALUES" Upon successful completion 0 is returned. Otherwise, \-1 is returned and the error information in \fIsource\fR is set to indicate the error. .SH "SEE ALSO" libzip(3), zip_source(5) .SH "HISTORY" \fBzip_source_stat\fR() was added in libzip 1.0. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_source_stat.mdoc ================================================ .\" zip_source_stat.mdoc -- get information about zip source .\" Copyright (C) 2014-2021 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd December 18, 2017 .Dt ZIP_SOURCE_STAT 3 .Os .Sh NAME .Nm zip_source_stat .Nd get information about zip_source .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft int .Fn zip_source_stat "zip_source_t *source" "zip_stat_t *sb" .Sh DESCRIPTION The .Fn zip_source_stat function obtains information about the zip source .Ar source .Pp The .Ar sb argument is a pointer to a .Ft struct zip_source_stat (shown below), into which information about the zip source is placed. .Bd -literal struct zip_source_stat { zip_uint64_t valid; /* which fields have valid values */ const char *name; /* name of the file */ zip_uint64_t index; /* index within archive */ zip_uint64_t size; /* size of file (uncompressed) */ zip_uint64_t comp_size; /* size of file (compressed) */ time_t mtime; /* modification time */ zip_uint32_t crc; /* crc of file data */ zip_uint16_t comp_method; /* compression method used */ zip_uint16_t encryption_method; /* encryption method used */ zip_uint32_t flags; /* reserved for future use */ }; .Ed The structure pointed to by .Ar sb must be initialized with .Fn zip_stat_init 3 before calling .Fn zip_source_stat . .Pp The .Ar valid field of the structure specifies which other fields are valid. Check if the flag defined by the following defines are in .Ar valid before accessing the fields: .Bl -tag -width ZIP_STAT_ENCRYPTION_METHODXX -compact -offset indent .It Dv ZIP_STAT_NAME .Ar name .It Dv ZIP_STAT_INDEX .Ar index .It Dv ZIP_STAT_SIZE .Ar size .It Dv ZIP_STAT_COMP_SIZE .Ar comp_size .It Dv ZIP_STAT_MTIME .Ar mtime .It Dv ZIP_STAT_CRC .Ar crc .It Dv ZIP_STAT_COMP_METHOD .Ar comp_method .It Dv ZIP_STAT_ENCRYPTION_METHOD .Ar encryption_method .It Dv ZIP_STAT_FLAGS .Ar flags .El .Pp .Em NOTE : Some fields may only be filled out after all data has been read from the source, for example the .Ar crc or .Ar size fields. .Sh RETURN VALUES Upon successful completion 0 is returned. Otherwise, \-1 is returned and the error information in .Ar source is set to indicate the error. .Sh SEE ALSO .Xr libzip 3 , .Xr zip_source 5 .Sh HISTORY .Fn zip_source_stat was added in libzip 1.0. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_source_tell.html ================================================ ================================================ FILE: external/libzip/man/zip_source_tell.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_source_tell.mdoc -- report current read offset in source .\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_SOURCE_TELL" "3" "December 18, 2017" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_source_tell\fR \- report current read offset in zip source .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIzip_int64_t\fR .br .PD 0 .HP 4n \fBzip_source_tell\fR(\fIzip_source_t\ *source\fR); .PD .SH "DESCRIPTION" The function \fBzip_source_tell\fR() returns the current read offset for \fIsource\fR. The return value can be passed to zip_source_seek(3) with \fIwhence\fR set to \fRSEEK_SET\fR to return to the same location in the source. .SH "RETURN VALUES" Upon successful completion the current read offset is returned. Otherwise, \-1 is returned and the error information in \fIsource\fR is set to indicate the error. .SH "SEE ALSO" libzip(3), zip_source(5), zip_source_read(3), zip_source_tell_write(3) .SH "HISTORY" \fBzip_source_tell\fR() was added in libzip 1.0. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_source_tell.mdoc ================================================ .\" zip_source_tell.mdoc -- report current read offset in source .\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd December 18, 2017 .Dt ZIP_SOURCE_TELL 3 .Os .Sh NAME .Nm zip_source_tell .Nd report current read offset in zip source .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft zip_int64_t .Fn zip_source_tell "zip_source_t *source" .Sh DESCRIPTION The function .Fn zip_source_tell returns the current read offset for .Fa source . The return value can be passed to .Xr zip_source_seek 3 with .Ar whence set to .Dv SEEK_SET to return to the same location in the source. .Sh RETURN VALUES Upon successful completion the current read offset is returned. Otherwise, \-1 is returned and the error information in .Ar source is set to indicate the error. .Sh SEE ALSO .Xr libzip 3 , .Xr zip_source 5 , .Xr zip_source_read 3 , .Xr zip_source_tell_write 3 .Sh HISTORY .Fn zip_source_tell was added in libzip 1.0. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_source_tell_write.html ================================================ ================================================ FILE: external/libzip/man/zip_source_tell_write.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_source_tell_write.mdoc -- report current write offset in source .\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_SOURCE_TELL_WRITE" "3" "December 18, 2017" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_source_tell_write\fR \- report current write offset in zip source .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIzip_int64_t\fR .br .PD 0 .HP 4n \fBzip_source_tell_write\fR(\fIzip_source_t\ *source\fR); .PD .SH "DESCRIPTION" The function \fBzip_source_tell_write\fR() returns the current write offset for \fIsource\fR. The return value can be passed to zip_source_seek_write(3) with \fIwhence\fR set to \fRSEEK_SET\fR to return to the same location in the source. .SH "RETURN VALUES" Upon successful completion the current write offset is returned. Otherwise, \-1 is returned and the error information in \fIsource\fR is set to indicate the error. .SH "SEE ALSO" libzip(3), zip_source(5), zip_source_begin_write(3), zip_source_commit_write(3), zip_source_rollback_write(3), zip_source_tell(3), zip_source_write(3) .SH "HISTORY" \fBzip_source_tell_write\fR() was added in libzip 1.0. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_source_tell_write.mdoc ================================================ .\" zip_source_tell_write.mdoc -- report current write offset in source .\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd December 18, 2017 .Dt ZIP_SOURCE_TELL_WRITE 3 .Os .Sh NAME .Nm zip_source_tell_write .Nd report current write offset in zip source .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft zip_int64_t .Fn zip_source_tell_write "zip_source_t *source" .Sh DESCRIPTION The function .Fn zip_source_tell_write returns the current write offset for .Fa source . The return value can be passed to .Xr zip_source_seek_write 3 with .Ar whence set to .Dv SEEK_SET to return to the same location in the source. .Sh RETURN VALUES Upon successful completion the current write offset is returned. Otherwise, \-1 is returned and the error information in .Ar source is set to indicate the error. .Sh SEE ALSO .Xr libzip 3 , .Xr zip_source 5 , .Xr zip_source_begin_write 3 , .Xr zip_source_commit_write 3 , .Xr zip_source_rollback_write 3 , .Xr zip_source_tell 3 , .Xr zip_source_write 3 .Sh HISTORY .Fn zip_source_tell_write was added in libzip 1.0. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_source_win32a.html ================================================ ================================================ FILE: external/libzip/man/zip_source_win32a.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_source_win32a.mdoc -- create data source using a win32 ANSI name .\" Copyright (C) 2015-2021 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_SOURCE_WIN32A" "3" "June 30, 2023" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_source_win32a\fR, \fBzip_source_win32a_create\fR \- create data source from a Windows ANSI file name .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIzip_source_t *\fR .br .PD 0 .HP 4n \fBzip_source_win32a\fR(\fIzip_t\ *archive\fR, \fIconst\ char\ *fname\fR, \fIzip_uint64_t\ start\fR, \fIzip_int64_t\ len\fR); .PD .PP \fIzip_source_t *\fR .br .PD 0 .HP 4n \fBzip_source_win32a_create\fR(\fIconst\ char\ *fname\fR, \fIzip_uint64_t\ start\fR, \fIzip_int64_t\ len\fR, \fIzip_error_t\ *error\fR); .PD .SH "DESCRIPTION" The functions \fBzip_source_win32a\fR() and \fBzip_source_win32a_create\fR() create a zip source on Windows using a Windows ANSI name. They open \fIfname\fR and read \fIlen\fR bytes from offset \fIstart\fR from it. For a description of the \fIlen\fR argument, see zip_source_file(3). .PP If the file supports seek, the source can be used to open a zip archive from. .PP The file is opened and read when the data from the source is used, usually by \fBzip_close\fR() or \fBzip_open_from_source\fR(). .SH "RETURN VALUES" Upon successful completion, the created source is returned. Otherwise, \fRNULL\fR is returned and the error code in \fIarchive\fR or \fIerror\fR is set to indicate the error. .SH "ERRORS" \fBzip_source_win32a\fR() and \fBzip_source_win32a_create\fR() fail if: .TP 19n [\fRZIP_ER_INVAL\fR] \fIfname\fR, \fIstart\fR, or \fIlen\fR are invalid. .TP 19n [\fRZIP_ER_MEMORY\fR] Required memory could not be allocated. .TP 19n [\fRZIP_ER_OPEN\fR] Opening \fIfname\fR failed. .SH "SEE ALSO" libzip(3), zip_file_add(3), zip_file_replace(3), zip_source(5), zip_source_file(3), zip_source_win32handle(3), zip_source_win32w(3) .SH "HISTORY" \fBzip_source_win32a\fR() and \fBzip_source_win32a_create\fR() were added in libzip 1.0. .PP \fRZIP_LENGTH_TO_END\fR and \fRZIP_LENGTH_UNCHECKED\fR were added in libzip 1.10.1. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_source_win32a.mdoc ================================================ .\" zip_source_win32a.mdoc -- create data source using a win32 ANSI name .\" Copyright (C) 2015-2021 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd June 30, 2023 .Dt ZIP_SOURCE_WIN32A 3 .Os .Sh NAME .Nm zip_source_win32a , .Nm zip_source_win32a_create .Nd create data source from a Windows ANSI file name .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft zip_source_t * .Fn zip_source_win32a "zip_t *archive" "const char *fname" "zip_uint64_t start" "zip_int64_t len" .Ft zip_source_t * .Fn zip_source_win32a_create "const char *fname" "zip_uint64_t start" "zip_int64_t len" "zip_error_t *error" .Sh DESCRIPTION The functions .Fn zip_source_win32a and .Fn zip_source_win32a_create create a zip source on Windows using a Windows ANSI name. They open .Ar fname and read .Ar len bytes from offset .Ar start from it. For a description of the .Ar len argument, see .Xr zip_source_file 3 . .Pp If the file supports seek, the source can be used to open a zip archive from. .Pp The file is opened and read when the data from the source is used, usually by .Fn zip_close or .Fn zip_open_from_source . .Sh RETURN VALUES Upon successful completion, the created source is returned. Otherwise, .Dv NULL is returned and the error code in .Ar archive or .Ar error is set to indicate the error. .Sh ERRORS .Fn zip_source_win32a and .Fn zip_source_win32a_create fail if: .Bl -tag -width Er .It Bq Er ZIP_ER_INVAL .Ar fname , .Ar start , or .Ar len are invalid. .It Bq Er ZIP_ER_MEMORY Required memory could not be allocated. .It Bq Er ZIP_ER_OPEN Opening .Ar fname failed. .El .Sh SEE ALSO .Xr libzip 3 , .Xr zip_file_add 3 , .Xr zip_file_replace 3 , .Xr zip_source 5 , .Xr zip_source_file 3 , .Xr zip_source_win32handle 3 , .Xr zip_source_win32w 3 .Sh HISTORY .Fn zip_source_win32a and .Fn zip_source_win32a_create were added in libzip 1.0. .Pp .Dv ZIP_LENGTH_TO_END and .Dv ZIP_LENGTH_UNCHECKED were added in libzip 1.10.1. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_source_win32handle.html ================================================ ================================================ FILE: external/libzip/man/zip_source_win32handle.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_source_handle.mdoc -- create data source from a Windows file handle .\" Copyright (C) 2015-2021 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_SOURCE_WIN32HANDLE" "3" "May 14, 2024" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_source_win32handle\fR, \fBzip_source_win32handle_create\fR \- create data source from a Windows file handle .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIzip_source_t *\fR .br .PD 0 .HP 4n \fBzip_source_win32handle\fR(\fIzip_t\ *archive\fR, \fIHANDLE\ h\fR, \fIzip_uint64_t\ start\fR, \fIzip_int64_t\ len\fR); .PD .PP \fIzip_source_t *\fR .br .PD 0 .HP 4n \fBzip_source_win32handle_create\fR(\fIHANDLE\ h\fR, \fIzip_uint64_t\ start\fR, \fIzip_int64_t\ len\fR, \fIzip_error_t\ *error\fR); .PD .SH "DESCRIPTION" The functions \fBzip_source_win32handle\fR() and \fBzip_source_win32handle_create\fR() create a zip source from a Windows file handle. They read \fIlen\fR bytes from offset \fIstart\fR from it. If \fIlen\fR is 0 or \-1, the whole file (starting from \fIstart\fR) is used. .PP If the file supports seek, the source can be used to open a zip archive from. .PP The file is opened and read when the data from the source is used, usually by \fBzip_close\fR() or \fBzip_open_from_source\fR(). .SH "RETURN VALUES" Upon successful completion, the created source is returned. Otherwise, \fRNULL\fR is returned and the error code in \fIarchive\fR or \fIerror\fR is set to indicate the error. .SH "ERRORS" \fBzip_source_w32handle\fR() and \fBzip_source_w32handle_create\fR() fail if: .TP 19n [\fRZIP_ER_INVAL\fR] \fIh\fR, \fIstart\fR, or \fIlen\fR are invalid. .TP 19n [\fRZIP_ER_MEMORY\fR] Required memory could not be allocated. .SH "SEE ALSO" libzip(3), zip_file_add(3), zip_file_replace(3), zip_source(5), zip_source_win32a(3), zip_source_win32w(3) .SH "HISTORY" \fBzip_source_win32handle\fR() and \fBzip_source_win32handle_create\fR() were added in libzip 1.0. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_source_win32handle.mdoc ================================================ .\" zip_source_handle.mdoc -- create data source from a Windows file handle .\" Copyright (C) 2015-2021 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd May 14, 2024 .Dt ZIP_SOURCE_WIN32HANDLE 3 .Os .Sh NAME .Nm zip_source_win32handle , .Nm zip_source_win32handle_create .Nd create data source from a Windows file handle .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft zip_source_t * .Fn zip_source_win32handle "zip_t *archive" "HANDLE h" "zip_uint64_t start" "zip_int64_t len" .Ft zip_source_t * .Fn zip_source_win32handle_create "HANDLE h" "zip_uint64_t start" "zip_int64_t len" "zip_error_t *error" .Sh DESCRIPTION The functions .Fn zip_source_win32handle and .Fn zip_source_win32handle_create create a zip source from a Windows file handle. They read .Ar len bytes from offset .Ar start from it. If .Ar len is 0 or \-1, the whole file (starting from .Ar start ) is used. .Pp If the file supports seek, the source can be used to open a zip archive from. .Pp The file is opened and read when the data from the source is used, usually by .Fn zip_close or .Fn zip_open_from_source . .Sh RETURN VALUES Upon successful completion, the created source is returned. Otherwise, .Dv NULL is returned and the error code in .Ar archive or .Ar error is set to indicate the error. .Sh ERRORS .Fn zip_source_w32handle and .Fn zip_source_w32handle_create fail if: .Bl -tag -width Er .It Bq Er ZIP_ER_INVAL .Ar h , .Ar start , or .Ar len are invalid. .It Bq Er ZIP_ER_MEMORY Required memory could not be allocated. .El .Sh SEE ALSO .Xr libzip 3 , .Xr zip_file_add 3 , .Xr zip_file_replace 3 , .Xr zip_source 5 , .Xr zip_source_win32a 3 , .Xr zip_source_win32w 3 .Sh HISTORY .Fn zip_source_win32handle and .Fn zip_source_win32handle_create were added in libzip 1.0. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_source_win32w.html ================================================ ================================================ FILE: external/libzip/man/zip_source_win32w.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_source_win32w.mdoc -- create data source using a win32 Unicode name .\" Copyright (C) 2015-2021 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_SOURCE_WIN32W" "3" "June 30, 2023" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_source_win32w\fR, \fBzip_source_win32w_create\fR \- create data source from a Windows Unicode file name .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIzip_source_t *\fR .br .PD 0 .HP 4n \fBzip_source_win32w\fR(\fIzip_t\ *archive\fR, \fIconst\ wchar_t\ *fname\fR, \fIzip_uint64_t\ start\fR, \fIzip_int64_t\ len\fR); .PD .PP \fIzip_source_t *\fR .br .PD 0 .HP 4n \fBzip_source_win32w_create\fR(\fIconst\ wchar_t\ *fname\fR, \fIzip_uint64_t\ start\fR, \fIzip_int64_t\ len\fR, \fIzip_error_t\ *error\fR); .PD .SH "DESCRIPTION" The functions \fBzip_source_win32w\fR() and \fBzip_source_win32w_create\fR() create a zip source on Windows using a Windows Unicode name. They open \fIfname\fR and read \fIlen\fR bytes from offset \fIstart\fR from it. For a description of the \fIlen\fR argument, see zip_source_file(3). .PP If the file supports seek, the source can be used to open a zip archive from. .PP The file is opened and read when the data from the source is used, usually by \fBzip_close\fR() or \fBzip_open_from_source\fR(). .SH "RETURN VALUES" Upon successful completion, the created source is returned. Otherwise, \fRNULL\fR is returned and the error code in \fIarchive\fR or \fIerror\fR is set to indicate the error. .SH "ERRORS" \fBzip_source_win32w\fR() and \fBzip_source_win32w_create\fR() fail if: .TP 19n [\fRZIP_ER_INVAL\fR] \fIfname\fR, \fIstart\fR, or \fIlen\fR are invalid. .TP 19n [\fRZIP_ER_MEMORY\fR] Required memory could not be allocated. .TP 19n [\fRZIP_ER_OPEN\fR] Opening \fIfname\fR failed. .SH "SEE ALSO" libzip(3), zip_file_add(3), zip_file_replace(3), zip_source(5), zip_source_file(3), zip_source_win32a(3), zip_source_win32handle(3) .SH "HISTORY" \fBzip_source_win32w\fR() was added in libzip 1.0. .PP \fRZIP_LENGTH_TO_END\fR and \fRZIP_LENGTH_UNCHECKED\fR were added in libzip 1.10.1. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_source_win32w.mdoc ================================================ .\" zip_source_win32w.mdoc -- create data source using a win32 Unicode name .\" Copyright (C) 2015-2021 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd June 30, 2023 .Dt ZIP_SOURCE_WIN32W 3 .Os .Sh NAME .Nm zip_source_win32w , .Nm zip_source_win32w_create .Nd create data source from a Windows Unicode file name .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft zip_source_t * .Fn zip_source_win32w "zip_t *archive" "const wchar_t *fname" "zip_uint64_t start" "zip_int64_t len" .Ft zip_source_t * .Fn zip_source_win32w_create "const wchar_t *fname" "zip_uint64_t start" "zip_int64_t len" "zip_error_t *error" .Sh DESCRIPTION The functions .Fn zip_source_win32w and .Fn zip_source_win32w_create create a zip source on Windows using a Windows Unicode name. They open .Ar fname and read .Ar len bytes from offset .Ar start from it. For a description of the .Ar len argument, see .Xr zip_source_file 3 . .Pp If the file supports seek, the source can be used to open a zip archive from. .Pp The file is opened and read when the data from the source is used, usually by .Fn zip_close or .Fn zip_open_from_source . .Sh RETURN VALUES Upon successful completion, the created source is returned. Otherwise, .Dv NULL is returned and the error code in .Ar archive or .Ar error is set to indicate the error. .Sh ERRORS .Fn zip_source_win32w and .Fn zip_source_win32w_create fail if: .Bl -tag -width Er .It Bq Er ZIP_ER_INVAL .Ar fname , .Ar start , or .Ar len are invalid. .It Bq Er ZIP_ER_MEMORY Required memory could not be allocated. .It Bq Er ZIP_ER_OPEN Opening .Ar fname failed. .El .Sh SEE ALSO .Xr libzip 3 , .Xr zip_file_add 3 , .Xr zip_file_replace 3 , .Xr zip_source 5 , .Xr zip_source_file 3 , .Xr zip_source_win32a 3 , .Xr zip_source_win32handle 3 .Sh HISTORY .Fn zip_source_win32w was added in libzip 1.0. .Pp .Dv ZIP_LENGTH_TO_END and .Dv ZIP_LENGTH_UNCHECKED were added in libzip 1.10.1. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_source_window_create.html ================================================ ================================================ FILE: external/libzip/man/zip_source_window_create.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_source_window_create.mdoc -- create zip data source overlay .\" Copyright (C) 2021 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_SOURCE_WINDOW_CREATE" "3" "April 29, 2021" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_source_window_create\fR \- create zip data source overlay .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIzip_source_t *\fR .br .PD 0 .HP 4n \fBzip_source_window_create\fR(\fIzip_source_t\ *source\fR, \fIzip_uint64_t\ start\fR, \fIzip_int64_t\ len\fR, \fIzip_error_t\ *error\fR); .PD .SH "DESCRIPTION" The \fBzip_source_window_create\fR() function create a zip source from an underlying zip source, restricting access to a particular window starting at byte \fIstart\fR and having size \fIlen\fR. If \fIlen\fR is \-1, the window spans to the end of the underlying source. .PP \fBzip_source_window\fR() and \fBzip_source_window_create\fR() don't take ownership of \fIsource\fR. The caller is responsible for freeing it. (This is different to other layered sources.) .SH "RETURN VALUES" Upon successful completion, the created source is returned. Otherwise, \fRNULL\fR is returned and the error code in \fIerror\fR is set to indicate the error. .SH "ERRORS" \fBzip_source_window_create\fR() fails if: .TP 19n [\fRZIP_ER_INVAL\fR] \fIsrc\fR is \fRNULL\fR; there is an integer overflow adding \fIstart\fR and \fIlen\fR; or \fIlen\fR is less than \-1. .TP 19n [\fRZIP_ER_MEMORY\fR] Required memory could not be allocated. .SH "SEE ALSO" libzip(3), zip_source(5) .SH "HISTORY" \fBzip_source_window_create\fR() was added in libzip 1.8.0. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_source_window_create.mdoc ================================================ .\" zip_source_window_create.mdoc -- create zip data source overlay .\" Copyright (C) 2021 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd April 29, 2021 .Dt ZIP_SOURCE_WINDOW_CREATE 3 .Os .Sh NAME .Nm zip_source_window_create .Nd create zip data source overlay .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft zip_source_t * .Fn zip_source_window_create "zip_source_t *source" "zip_uint64_t start" "zip_int64_t len" "zip_error_t *error" .Sh DESCRIPTION The .Fn zip_source_window_create function create a zip source from an underlying zip source, restricting access to a particular window starting at byte .Ar start and having size .Ar len . If .Ar len is \-1, the window spans to the end of the underlying source. .Pp .Fn zip_source_window and .Fn zip_source_window_create don't take ownership of .Ar source . The caller is responsible for freeing it. (This is different to other layered sources.) .Sh RETURN VALUES Upon successful completion, the created source is returned. Otherwise, .Dv NULL is returned and the error code in .Ar error is set to indicate the error. .Sh ERRORS .Fn zip_source_window_create fails if: .Bl -tag -width Er .It Bq Er ZIP_ER_INVAL .Ar src is .Dv NULL ; there is an integer overflow adding .Ar start and .Ar len ; or .Ar len is less than \-1. .It Bq Er ZIP_ER_MEMORY Required memory could not be allocated. .El .Sh SEE ALSO .Xr libzip 3 , .Xr zip_source 5 .Sh HISTORY .Fn zip_source_window_create was added in libzip 1.8.0. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_source_write.html ================================================ ================================================ FILE: external/libzip/man/zip_source_write.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_source_write.mdoc -- write data to zip source .\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_SOURCE_WRITE" "3" "December 18, 2017" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_source_write\fR \- write data to zip source .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIzip_int64_t\fR .br .PD 0 .HP 4n \fBzip_source_write\fR(\fIzip_source_t\ *source\fR, \fIconst\ void\ *data\fR, \fIzip_uint64_t\ len\fR); .PD .SH "DESCRIPTION" The function \fBzip_source_write\fR() writes \fIlen\fR bytes from the buffer \fIdata\fR to the zip source \fIsource\fR at the current write offset. .PP The zip source \fIsource\fR has to be prepared for writing by calling zip_source_begin_write(3) first. .SH "RETURN VALUES" Upon successful completion the number of bytes written is returned. Otherwise, \-1 is returned and the error information in \fIsource\fR is set to indicate the error. .SH "SEE ALSO" libzip(3), zip_source(5), zip_source_begin_write(3), zip_source_commit_write(3), zip_source_rollback_write(3), zip_source_seek_write(3), zip_source_tell_write(3) .SH "HISTORY" \fBzip_source_write\fR() was added in libzip 1.0. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_source_write.mdoc ================================================ .\" zip_source_write.mdoc -- write data to zip source .\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd December 18, 2017 .Dt ZIP_SOURCE_WRITE 3 .Os .Sh NAME .Nm zip_source_write .Nd write data to zip source .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft zip_int64_t .Fn zip_source_write "zip_source_t *source" "const void *data" "zip_uint64_t len" .Sh DESCRIPTION The function .Fn zip_source_write writes .Ar len bytes from the buffer .Ar data to the zip source .Ar source at the current write offset. .Pp The zip source .Ar source has to be prepared for writing by calling .Xr zip_source_begin_write 3 first. .Sh RETURN VALUES Upon successful completion the number of bytes written is returned. Otherwise, \-1 is returned and the error information in .Ar source is set to indicate the error. .Sh SEE ALSO .Xr libzip 3 , .Xr zip_source 5 , .Xr zip_source_begin_write 3 , .Xr zip_source_commit_write 3 , .Xr zip_source_rollback_write 3 , .Xr zip_source_seek_write 3 , .Xr zip_source_tell_write 3 .Sh HISTORY .Fn zip_source_write was added in libzip 1.0. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_source_zip.html ================================================ ================================================ FILE: external/libzip/man/zip_source_zip.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_source_zip.mdoc -- create data source from zip file .\" Copyright (C) 2004-2021 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_SOURCE_ZIP" "3" "January 23, 2023" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_source_zip\fR, \fBzip_source_zip_create\fR \- create data source from zip file (obsolete interface) .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIzip_source_t *\fR .br .PD 0 .HP 4n \fBzip_source_zip\fR(\fIzip_t\ *archive\fR, \fIzip_t\ *srcarchive\fR, \fIzip_uint64_t\ srcidx\fR, \fIzip_flags_t\ flags\fR, \fIzip_uint64_t\ start\fR, \fIzip_int64_t\ len\fR); .PD .PP \fIzip_source_t *\fR .br .PD 0 .HP 4n \fBzip_source_zip_create\fR(\fIzip_t\ *srcarchive\fR, \fIzip_uint64_t\ srcidx\fR, \fIzip_flags_t\ flags\fR, \fIzip_uint64_t\ start\fR, \fIzip_int64_t\ len\fR, \fIzip_error_t\ *error\fR); .PD .SH "DESCRIPTION" The functions \fBzip_source_zip\fR() and \fBzip_source_zip_create\fR() are the obsolete versions of zip_source_zip_file(3) or zip_source_zip_file_create(3) respectively. If you want to get the compressed data of the complete file, use .RS 6n zip_source_zip_file(za, source_archive, source_index, ZIP_FL_COMPRESSED, 0, -1, NULL) .RE .PP The functions \fBzip_source_zip\fR() and \fBzip_source_zip_create\fR() create a zip source from a file in a zip archive. The \fIsrcarchive\fR argument is the (open) zip archive containing the source zip file at index \fIsrcidx\fR. \fIlen\fR bytes from offset \fIstart\fR will be used in the zip_source. If \fIlen\fR is 0 or \-1, the rest of the file, starting from \fIstart\fR, is used. If \fIstart\fR is zero and \fIlen\fR is \-1, the whole file will be copied without decompressing it. .PP Supported flags are: .TP 14n \fRZIP_FL_UNCHANGED\fR Try to get the original data without any changes that may have been made to \fIsrcarchive\fR after opening it. .SH "RETURN VALUES" Upon successful completion, the created source is returned. Otherwise, \fRNULL\fR is returned and the error code in \fIarchive\fR or \fIerror\fR is set to indicate the error. .SH "ERRORS" \fBzip_source_zip\fR() and \fBzip_source_zip_create\fR() fail if: .TP 19n [\fRZIP_ER_CHANGED\fR] Unchanged data was requested, but it is not available. .TP 19n [\fRZIP_ER_INVAL\fR] \fIsrcarchive\fR, \fIsrcidx\fR, \fIstart\fR, or \fIlen\fR are invalid. .TP 19n [\fRZIP_ER_MEMORY\fR] Required memory could not be allocated. .PD 0 .PP Additionally, it can return all error codes from \fBzip_stat_index\fR() and \fBzip_fopen_index\fR(). .PD .SH "SEE ALSO" libzip(3), zip_file_add(3), zip_file_replace(3), zip_source(5) .SH "HISTORY" \fBzip_source_zip\fR() was added in libzip 1.0. \fBzip_source_zip_create\fR() was added in libzip 1.8.0. Both were deprecated in libzip 1.10.0. Use \fBzip_source_zip_file\fR() or \fBzip_source_zip_file_create\fR() instead. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_source_zip.mdoc ================================================ .\" zip_source_zip.mdoc -- create data source from zip file .\" Copyright (C) 2004-2021 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd January 23, 2023 .Dt ZIP_SOURCE_ZIP 3 .Os .Sh NAME .Nm zip_source_zip , .Nm zip_source_zip_create .Nd create data source from zip file (obsolete interface) .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft zip_source_t * .Fn zip_source_zip "zip_t *archive" "zip_t *srcarchive" "zip_uint64_t srcidx" "zip_flags_t flags" "zip_uint64_t start" "zip_int64_t len" .Ft zip_source_t * .Fn zip_source_zip_create "zip_t *srcarchive" "zip_uint64_t srcidx" "zip_flags_t flags" "zip_uint64_t start" "zip_int64_t len" "zip_error_t *error" .Sh DESCRIPTION The functions .Fn zip_source_zip and .Fn zip_source_zip_create are the obsolete versions of .Xr zip_source_zip_file 3 or .Xr zip_source_zip_file_create 3 respectively. If you want to get the compressed data of the complete file, use .Dl zip_source_zip_file(za, source_archive, source_index, ZIP_FL_COMPRESSED, 0, -1, NULL) .Pp The functions .Fn zip_source_zip and .Fn zip_source_zip_create create a zip source from a file in a zip archive. The .Ar srcarchive argument is the (open) zip archive containing the source zip file at index .Ar srcidx . .Ar len bytes from offset .Ar start will be used in the zip_source. If .Ar len is 0 or \-1, the rest of the file, starting from .Ar start , is used. If .Ar start is zero and .Ar len is \-1, the whole file will be copied without decompressing it. .Pp Supported flags are: .Bl -tag -width Dv .It Dv ZIP_FL_UNCHANGED Try to get the original data without any changes that may have been made to .Ar srcarchive after opening it. .El .Sh RETURN VALUES Upon successful completion, the created source is returned. Otherwise, .Dv NULL is returned and the error code in .Ar archive or .Ar error is set to indicate the error. .Sh ERRORS .Fn zip_source_zip and .Fn zip_source_zip_create fail if: .Bl -tag -width Er .It Bq Er ZIP_ER_CHANGED Unchanged data was requested, but it is not available. .It Bq Er ZIP_ER_INVAL .Ar srcarchive , .Ar srcidx , .Ar start , or .Ar len are invalid. .It Bq Er ZIP_ER_MEMORY Required memory could not be allocated. .El Additionally, it can return all error codes from .Fn zip_stat_index and .Fn zip_fopen_index . .Sh SEE ALSO .Xr libzip 3 , .Xr zip_file_add 3 , .Xr zip_file_replace 3 , .Xr zip_source 5 .Sh HISTORY .Fn zip_source_zip was added in libzip 1.0. .Fn zip_source_zip_create was added in libzip 1.8.0. Both were deprecated in libzip 1.10.0. Use .Fn zip_source_zip_file or .Fn zip_source_zip_file_create instead. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_source_zip_file.html ================================================ ================================================ FILE: external/libzip/man/zip_source_zip_file.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_source_zip_file.mdoc -- create data source from zip file .\" Copyright (C) 2004-2021 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_SOURCE_ZIP_FILE" "3" "March 10, 2023" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_source_zip_file\fR, \fBzip_source_zip_file_create\fR \- create data source from zip file .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIzip_source_t *\fR .br .PD 0 .HP 4n \fBzip_source_zip_file\fR(\fIzip_t\ *archive\fR, \fIzip_t\ *srcarchive\fR, \fIzip_uint64_t\ srcidx\fR, \fIzip_flags_t\ flags\fR, \fIzip_uint64_t\ start\fR, \fIzip_int64_t\ length\fR, \fIconst\ char\ *password\fR); .PD .PP \fIzip_source_t *\fR .br .PD 0 .HP 4n \fBzip_source_zip_file_create\fR(\fIzip_t\ *srcarchive\fR, \fIzip_uint64_t\ srcidx\fR, \fIzip_flags_t\ flags\fR, \fIzip_uint64_t\ start\fR, \fIzip_int64_t\ length\fR, \fIconst\ char\ *password\fR, \fIzip_error_t\ *error\fR); .PD .SH "DESCRIPTION" The functions \fBzip_source_zip_file\fR() and \fBzip_source_zip_file_create\fR() create a zip source from a file in a zip archive. The \fIsrcarchive\fR argument is the (open) zip archive containing the source zip file at index \fIsrcidx\fR. \fIlength\fR bytes from offset \fIstart\fR will be used in the zip_source. If \fIlength\fR is \-1, the rest of the file, starting from \fIstart\fR, is used. .PP If you intend to copy a file from one archive to another, using the flag \fRZIP_FL_COMPRESSED\fR is more efficient, as it avoids recompressing the file data. .PP Supported flags are: .TP 22n \fRZIP_FL_COMPRESSED\fR Get the compressed data. This is only supported if the complete file data is requested (\fIstart\fR == 0 and \fIlength\fR == \-1). This is not supported for changed data. Default is uncompressed. .TP 22n \fRZIP_FL_ENCRYPTED\fR Get the encrypted data. (This flag implies \fRZIP_FL_COMPRESSED\fR.) This is only supported if the complete file data is requested (\fIstart\fR == 0 and \fIlength\fR == \-1). Default is decrypted. .TP 22n \fRZIP_FL_UNCHANGED\fR Try to get the original data without any changes that may have been made to \fIsrcarchive\fR after opening it. .SH "RETURN VALUES" Upon successful completion, the created source is returned. Otherwise, \fRNULL\fR is returned and the error code in \fIarchive\fR or \fIerror\fR is set to indicate the error. .SH "ERRORS" \fBzip_source_zip_file\fR() and \fBzip_source_zip_file_create\fR() fail if: .TP 19n [\fRZIP_ER_CHANGED\fR] Unchanged data was requested, but it is not available. .TP 19n [\fRZIP_ER_INVAL\fR] \fIsrcarchive\fR, \fIsrcidx\fR, \fIstart\fR, or \fIlength\fR are invalid. .TP 19n [\fRZIP_ER_MEMORY\fR] Required memory could not be allocated. .PD 0 .PP Additionally, it can return all error codes from \fBzip_stat_index\fR() and \fBzip_fopen_index\fR(). .PD .SH "SEE ALSO" libzip(3), zip_file_add(3), zip_file_replace(3), zip_source(5) .SH "HISTORY" \fBzip_source_zip_file\fR() and \fBzip_source_zip_file_create\fR() were added in libzip 1.10.0. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_source_zip_file.mdoc ================================================ .\" zip_source_zip_file.mdoc -- create data source from zip file .\" Copyright (C) 2004-2021 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd March 10, 2023 .Dt ZIP_SOURCE_ZIP_FILE 3 .Os .Sh NAME .Nm zip_source_zip_file , .Nm zip_source_zip_file_create .Nd create data source from zip file .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft zip_source_t * .Fn zip_source_zip_file "zip_t *archive" "zip_t *srcarchive" "zip_uint64_t srcidx" "zip_flags_t flags" "zip_uint64_t start" "zip_int64_t length" "const char *password" .Ft zip_source_t * .Fn zip_source_zip_file_create "zip_t *srcarchive" "zip_uint64_t srcidx" "zip_flags_t flags" "zip_uint64_t start" "zip_int64_t length" "const char *password" "zip_error_t *error" .Sh DESCRIPTION The functions .Fn zip_source_zip_file and .Fn zip_source_zip_file_create create a zip source from a file in a zip archive. The .Ar srcarchive argument is the (open) zip archive containing the source zip file at index .Ar srcidx . .Ar length bytes from offset .Ar start will be used in the zip_source. If .Ar length is \-1, the rest of the file, starting from .Ar start , is used. .Pp If you intend to copy a file from one archive to another, using the flag .Dv ZIP_FL_COMPRESSED is more efficient, as it avoids recompressing the file data. .Pp Supported flags are: .Bl -tag -width 20n .It Dv ZIP_FL_COMPRESSED Get the compressed data. This is only supported if the complete file data is requested .Ar ( start == 0 and .Ar length == \-1). This is not supported for changed data. Default is uncompressed. .It Dv ZIP_FL_ENCRYPTED Get the encrypted data. (This flag implies .Dv ZIP_FL_COMPRESSED . ) This is only supported if the complete file data is requested .Ar ( start == 0 and .Ar length == \-1). Default is decrypted. .It Dv ZIP_FL_UNCHANGED Try to get the original data without any changes that may have been made to .Ar srcarchive after opening it. .El .Sh RETURN VALUES Upon successful completion, the created source is returned. Otherwise, .Dv NULL is returned and the error code in .Ar archive or .Ar error is set to indicate the error. .Sh ERRORS .Fn zip_source_zip_file and .Fn zip_source_zip_file_create fail if: .Bl -tag -width Er .It Bq Er ZIP_ER_CHANGED Unchanged data was requested, but it is not available. .It Bq Er ZIP_ER_INVAL .Ar srcarchive , .Ar srcidx , .Ar start , or .Ar length are invalid. .It Bq Er ZIP_ER_MEMORY Required memory could not be allocated. .El Additionally, it can return all error codes from .Fn zip_stat_index and .Fn zip_fopen_index . .Sh SEE ALSO .Xr libzip 3 , .Xr zip_file_add 3 , .Xr zip_file_replace 3 , .Xr zip_source 5 .Sh HISTORY .Fn zip_source_zip_file and .Fn zip_source_zip_file_create were added in libzip 1.10.0. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_stat.html ================================================ ================================================ FILE: external/libzip/man/zip_stat.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_stat.mdoc -- get information about file .\" Copyright (C) 2003-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_STAT" "3" "December 18, 2017" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_stat\fR, \fBzip_stat_index\fR \- get information about file .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIint\fR .br .PD 0 .HP 4n \fBzip_stat\fR(\fIzip_t\ *archive\fR, \fIconst\ char\ *fname\fR, \fIzip_flags_t\ flags\fR, \fIzip_stat_t\ *sb\fR); .PD .PP \fIint\fR .br .PD 0 .HP 4n \fBzip_stat_index\fR(\fIzip_t\ *archive\fR, \fIzip_uint64_t\ index\fR, \fIzip_flags_t\ flags\fR, \fIzip_stat_t\ *sb\fR); .PD .SH "DESCRIPTION" The \fBzip_stat\fR() function obtains information about the file named \fIfname\fR in \fIarchive\fR. The \fIflags\fR argument specifies how the name lookup should be done. Its values are described in zip_name_locate(3). Also, \fRZIP_FL_UNCHANGED\fR may be \fIor\fR'ed to it to request information about the original file in the archive, ignoring any changes made. .PP The \fBzip_stat_index\fR() function obtains information about the file at position \fIindex\fR. .PP The \fIsb\fR argument is a pointer to a \fIstruct zip_stat\fR (shown below), into which information about the file is placed. .nf .sp .RS 0n struct zip_stat { zip_uint64_t valid; /* which fields have valid values */ const char *name; /* name of the file */ zip_uint64_t index; /* index within archive */ zip_uint64_t size; /* size of file (uncompressed) */ zip_uint64_t comp_size; /* size of file (compressed) */ time_t mtime; /* modification time */ zip_uint32_t crc; /* crc of file data */ zip_uint16_t comp_method; /* compression method used */ zip_uint16_t encryption_method; /* encryption method used */ zip_uint32_t flags; /* reserved for future use */ }; .RE .fi The structure pointed to by \fIsb\fR must be allocated before calling \fBzip_stat\fR() or \fBzip_stat_index\fR(). .PP The \fIvalid\fR field of the structure specifies which other fields are valid. Check if the flag defined by the following defines are in \fIvalid\fR before accessing the fields: .RS 6n .PD 0 .TP 30n \fRZIP_STAT_NAME\fR \fIname\fR .TP 30n \fRZIP_STAT_INDEX\fR \fIindex\fR .TP 30n \fRZIP_STAT_SIZE\fR \fIsize\fR .TP 30n \fRZIP_STAT_COMP_SIZE\fR \fIcomp_size\fR .TP 30n \fRZIP_STAT_MTIME\fR \fImtime\fR .TP 30n \fRZIP_STAT_CRC\fR \fIcrc\fR .TP 30n \fRZIP_STAT_COMP_METHOD\fR \fIcomp_method\fR .TP 30n \fRZIP_STAT_ENCRYPTION_METHOD\fR \fIencryption_method\fR .TP 30n \fRZIP_STAT_FLAGS\fR \fIflags\fR .RE .PD .SH "RETURN VALUES" Upon successful completion 0 is returned. Otherwise, \-1 is returned and the error information in \fIarchive\fR is set to indicate the error. .SH "ERRORS" The function \fBzip_stat\fR() can fail for any of the errors specified for the routine zip_name_locate(3). .PP The function \fBzip_stat_index\fR() fails and sets the error information to \fRZIP_ER_INVAL\fR if \fIindex\fR is invalid. If \fRZIP_FL_UNCHANGED\fR is not set and no information can be obtained from the source callback, the error information is set to \fRZIP_ER_CHANGED\fR. .SH "SEE ALSO" libzip(3), zip_get_num_entries(3), zip_name_locate(3), zip_stat_init(3) .SH "HISTORY" \fBzip_stat\fR() was added in libzip 0.6. In libzip 0.11 the type of \fIflags\fR was changed from \fIint\fR to \fIzip_flags_t\fR. .PP \fBzip_stat_index\fR() was added in libzip 0.6. In libzip 0.10 the type of \fIindex\fR was changed from \fIint\fR to \fIzip_uint64_t\fR. In libzip 0.11 the type of \fIflags\fR was changed from \fIint\fR to \fIzip_flags_t\fR. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_stat.mdoc ================================================ .\" zip_stat.mdoc -- get information about file .\" Copyright (C) 2003-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd December 18, 2017 .Dt ZIP_STAT 3 .Os .Sh NAME .Nm zip_stat , .Nm zip_stat_index .Nd get information about file .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft int .Fn zip_stat "zip_t *archive" "const char *fname" "zip_flags_t flags" "zip_stat_t *sb" .Ft int .Fn zip_stat_index "zip_t *archive" "zip_uint64_t index" "zip_flags_t flags" "zip_stat_t *sb" .Sh DESCRIPTION The .Fn zip_stat function obtains information about the file named .Ar fname in .Ar archive . The .Ar flags argument specifies how the name lookup should be done. Its values are described in .Xr zip_name_locate 3 . Also, .Dv ZIP_FL_UNCHANGED may be .Em or Ns No 'ed to it to request information about the original file in the archive, ignoring any changes made. .Pp The .Fn zip_stat_index function obtains information about the file at position .Ar index . .Pp The .Ar sb argument is a pointer to a .Ft struct zip_stat (shown below), into which information about the file is placed. .Bd -literal struct zip_stat { zip_uint64_t valid; /* which fields have valid values */ const char *name; /* name of the file */ zip_uint64_t index; /* index within archive */ zip_uint64_t size; /* size of file (uncompressed) */ zip_uint64_t comp_size; /* size of file (compressed) */ time_t mtime; /* modification time */ zip_uint32_t crc; /* crc of file data */ zip_uint16_t comp_method; /* compression method used */ zip_uint16_t encryption_method; /* encryption method used */ zip_uint32_t flags; /* reserved for future use */ }; .Ed The structure pointed to by .Ar sb must be allocated before calling .Fn zip_stat or .Fn zip_stat_index . .Pp The .Ar valid field of the structure specifies which other fields are valid. Check if the flag defined by the following defines are in .Ar valid before accessing the fields: .Bl -tag -width ZIP_STAT_ENCRYPTION_METHODXX -compact -offset indent .It Dv ZIP_STAT_NAME .Ar name .It Dv ZIP_STAT_INDEX .Ar index .It Dv ZIP_STAT_SIZE .Ar size .It Dv ZIP_STAT_COMP_SIZE .Ar comp_size .It Dv ZIP_STAT_MTIME .Ar mtime .It Dv ZIP_STAT_CRC .Ar crc .It Dv ZIP_STAT_COMP_METHOD .Ar comp_method .It Dv ZIP_STAT_ENCRYPTION_METHOD .Ar encryption_method .It Dv ZIP_STAT_FLAGS .Ar flags .El .Sh RETURN VALUES Upon successful completion 0 is returned. Otherwise, \-1 is returned and the error information in .Ar archive is set to indicate the error. .Sh ERRORS The function .Fn zip_stat can fail for any of the errors specified for the routine .Xr zip_name_locate 3 . .Pp The function .Fn zip_stat_index fails and sets the error information to .Er ZIP_ER_INVAL if .Ar index is invalid. If .Dv ZIP_FL_UNCHANGED is not set and no information can be obtained from the source callback, the error information is set to .Er ZIP_ER_CHANGED . .Sh SEE ALSO .Xr libzip 3 , .Xr zip_get_num_entries 3 , .Xr zip_name_locate 3 , .Xr zip_stat_init 3 .Sh HISTORY .Fn zip_stat was added in libzip 0.6. In libzip 0.11 the type of .Ar flags was changed from .Vt int to .Vt zip_flags_t . .Pp .Fn zip_stat_index was added in libzip 0.6. In libzip 0.10 the type of .Ar index was changed from .Vt int to .Vt zip_uint64_t . In libzip 0.11 the type of .Ar flags was changed from .Vt int to .Vt zip_flags_t . .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_stat_init.html ================================================ ================================================ FILE: external/libzip/man/zip_stat_init.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_stat_init.mdoc -- init zip_stat structure .\" Copyright (C) 2006-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_STAT_INIT" "3" "December 18, 2017" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_stat_init\fR \- initialize zip_stat structure .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIvoid\fR .br .PD 0 .HP 4n \fBzip_stat_init\fR(\fIzip_stat_t\ *sb\fR); .PD .SH "DESCRIPTION" The \fBzip_stat_init\fR() function initializes the members of a struct zip_stat. The current members are described in zip_stat(3), but this function should be used to initialize it to make sure none are missed. The structure pointed to by \fIsb\fR must be allocated before calling \fBzip_stat_init\fR(). .PP This function should be used by functions provided to zip_source_function(3) when returning \fRZIP_SOURCE_STAT\fR information to make sure all fields are initialized. .SH "RETURN VALUES" If \fIsb\fR is valid, the function is always successful. .SH "SEE ALSO" libzip(3), zip_stat(3) .SH "HISTORY" \fBzip_stat_init\fR() was added in libzip 0.8. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_stat_init.mdoc ================================================ .\" zip_stat_init.mdoc -- init zip_stat structure .\" Copyright (C) 2006-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd December 18, 2017 .Dt ZIP_STAT_INIT 3 .Os .Sh NAME .Nm zip_stat_init .Nd initialize zip_stat structure .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft void .Fn zip_stat_init "zip_stat_t *sb" .Sh DESCRIPTION The .Fn zip_stat_init function initializes the members of a struct zip_stat. The current members are described in .Xr zip_stat 3 , but this function should be used to initialize it to make sure none are missed. The structure pointed to by .Ar sb must be allocated before calling .Fn zip_stat_init . .Pp This function should be used by functions provided to .Xr zip_source_function 3 when returning .Dv ZIP_SOURCE_STAT information to make sure all fields are initialized. .Sh RETURN VALUES If .Ar sb is valid, the function is always successful. .Sh SEE ALSO .Xr libzip 3 , .Xr zip_stat 3 .Sh HISTORY .Fn zip_stat_init was added in libzip 0.8. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_unchange.html ================================================ ================================================ FILE: external/libzip/man/zip_unchange.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_unchange.mdoc -- undo changes to file in zip archive .\" Copyright (C) 2003-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_UNCHANGE" "3" "December 18, 2017" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_unchange\fR \- undo changes to file in zip archive .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIint\fR .br .PD 0 .HP 4n \fBzip_unchange\fR(\fIzip_t\ *archive\fR, \fIzip_uint64_t\ index\fR); .PD .SH "DESCRIPTION" Changes to the file at position \fIindex\fR are reverted. .SH "RETURN VALUES" Upon successful completion 0 is returned. Otherwise, \-1 is returned and the error code in \fIarchive\fR is set to indicate the error. .SH "ERRORS" \fBzip_unchange\fR() fails if: .TP 19n [\fRZIP_ER_EXISTS\fR] Unchanging the name would result in a duplicate name in the archive. .TP 19n [\fRZIP_ER_INVAL\fR] \fIindex\fR is not a valid file index in \fIzip\fR. .SH "SEE ALSO" libzip(3), zip_unchange_all(3), zip_unchange_archive(3) .SH "HISTORY" \fBzip_unchange\fR() was added in libzip 0.6. In libzip 0.10 the type of \fIindex\fR was changed from \fIint\fR to \fIzip_uint64_t\fR. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_unchange.mdoc ================================================ .\" zip_unchange.mdoc -- undo changes to file in zip archive .\" Copyright (C) 2003-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd December 18, 2017 .Dt ZIP_UNCHANGE 3 .Os .Sh NAME .Nm zip_unchange .Nd undo changes to file in zip archive .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft int .Fn zip_unchange "zip_t *archive" "zip_uint64_t index" .Sh DESCRIPTION Changes to the file at position .Ar index are reverted. .Sh RETURN VALUES Upon successful completion 0 is returned. Otherwise, \-1 is returned and the error code in .Ar archive is set to indicate the error. .Sh ERRORS .Fn zip_unchange fails if: .Bl -tag -width Er .It Bq Er ZIP_ER_EXISTS Unchanging the name would result in a duplicate name in the archive. .It Bq Er ZIP_ER_INVAL .Ar index is not a valid file index in .Ar zip . .El .Sh SEE ALSO .Xr libzip 3 , .Xr zip_unchange_all 3 , .Xr zip_unchange_archive 3 .Sh HISTORY .Fn zip_unchange was added in libzip 0.6. In libzip 0.10 the type of .Ar index was changed from .Vt int to .Vt zip_uint64_t . .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_unchange_all.html ================================================ ================================================ FILE: external/libzip/man/zip_unchange_all.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_unchange_all.mdoc -- undo changes to all files in zip archive .\" Copyright (C) 2003-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_UNCHANGE_ALL" "3" "December 18, 2017" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_unchange_all\fR \- undo all changes in a zip archive .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIint\fR .br .PD 0 .HP 4n \fBzip_unchange_all\fR(\fIzip_t\ *archive\fR); .PD .SH "DESCRIPTION" All changes to files and global information in \fIarchive\fR are reverted. .SH "RETURN VALUES" Upon successful completion 0 is returned. Otherwise, \-1 is returned and the error code in \fIarchive\fR is set to indicate the error. .SH "SEE ALSO" libzip(3), zip_unchange(3), zip_unchange_archive(3) .SH "HISTORY" \fBzip_unchange_all\fR() was added in libzip 0.6. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_unchange_all.mdoc ================================================ .\" zip_unchange_all.mdoc -- undo changes to all files in zip archive .\" Copyright (C) 2003-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd December 18, 2017 .Dt ZIP_UNCHANGE_ALL 3 .Os .Sh NAME .Nm zip_unchange_all .Nd undo all changes in a zip archive .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft int .Fn zip_unchange_all "zip_t *archive" .Sh DESCRIPTION All changes to files and global information in .Ar archive are reverted. .Sh RETURN VALUES Upon successful completion 0 is returned. Otherwise, \-1 is returned and the error code in .Ar archive is set to indicate the error. .Sh SEE ALSO .Xr libzip 3 , .Xr zip_unchange 3 , .Xr zip_unchange_archive 3 .Sh HISTORY .Fn zip_unchange_all was added in libzip 0.6. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zip_unchange_archive.html ================================================ ================================================ FILE: external/libzip/man/zip_unchange_archive.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zip_unchange_archive.mdoc -- undo changes to all files in zip archive .\" Copyright (C) 2006-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIP_UNCHANGE_ARCHIVE" "3" "December 18, 2017" "NiH" "Library Functions Manual" .nh .if n .ad l .SH "NAME" \fBzip_unchange_archive\fR \- undo global changes to zip archive .SH "LIBRARY" libzip (-lzip) .SH "SYNOPSIS" \fB#include \fR .sp \fIint\fR .br .PD 0 .HP 4n \fBzip_unchange_archive\fR(\fIzip_t\ *archive\fR); .PD .SH "DESCRIPTION" Revert all global changes to the archive \fIarchive\fR. This reverts changes to the archive comment and global flags. .SH "RETURN VALUES" Upon successful completion 0 is returned. Otherwise, \-1 is returned and the error code in \fIarchive\fR is set to indicate the error. .SH "SEE ALSO" libzip(3), zip_unchange(3), zip_unchange_all(3) .SH "HISTORY" \fBzip_unchange_archive\fR() was added in libzip 0.7. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zip_unchange_archive.mdoc ================================================ .\" zip_unchange_archive.mdoc -- undo changes to all files in zip archive .\" Copyright (C) 2006-2017 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd December 18, 2017 .Dt ZIP_UNCHANGE_ARCHIVE 3 .Os .Sh NAME .Nm zip_unchange_archive .Nd undo global changes to zip archive .Sh LIBRARY libzip (-lzip) .Sh SYNOPSIS .In zip.h .Ft int .Fn zip_unchange_archive "zip_t *archive" .Sh DESCRIPTION Revert all global changes to the archive .Ar archive . This reverts changes to the archive comment and global flags. .Sh RETURN VALUES Upon successful completion 0 is returned. Otherwise, \-1 is returned and the error code in .Ar archive is set to indicate the error. .Sh SEE ALSO .Xr libzip 3 , .Xr zip_unchange 3 , .Xr zip_unchange_all 3 .Sh HISTORY .Fn zip_unchange_archive was added in libzip 0.7. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zipcmp.html ================================================ ================================================ FILE: external/libzip/man/zipcmp.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zipcmp.mdoc -- compare zip archives .\" Copyright (C) 2003-2024 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIPCMP" "1" "March 15, 2024" "NiH" "General Commands Manual" .nh .if n .ad l .SH "NAME" \fBzipcmp\fR \- compare contents of zip archives .SH "SYNOPSIS" .HP 7n \fBzipcmp\fR [\fB\-ChipqsTtVv\fR] \fIarchive1\ archive2\fR .SH "DESCRIPTION" \fBzipcmp\fR compares the zip archives or directories \fIarchive1\fR and \fIarchive2\fR and checks if they contain the same files, comparing their names, uncompressed sizes, and CRCs. File order and compressed size differences are ignored. .PP Supported options: .TP 5n \fB\-C\fR Check consistency of archives. Results in an error if archive is inconsistent or not valid according to the zip specification. .TP 5n \fB\-h\fR Display a short help message and exit. .TP 5n \fB\-i\fR Compare names ignoring case distinctions. .TP 5n \fB\-p\fR Enable paranoid checks. Compares extra fields, comments, and other meta data. (Automatically disabled if one of the archives is a directory.) These checks are skipped for files where the data differs. .TP 5n \fB\-q\fR Quiet mode. Compare \fB\-v\fR. .TP 5n \fB\-s\fR Print a summary of how many files where added and removed. .TP 5n \fB\-T\fR Additionally compare the time stamps of the entries. .TP 5n \fB\-t\fR Test zip files by comparing the contents to their checksums. .TP 5n \fB\-V\fR Display version information and exit. .TP 5n \fB\-v\fR Verbose mode. Print details about differences to stdout. (This is the default.) .SH "EXIT STATUS" \fBzipcmp\fR exits 0 if the two archives contain the same files, 1 if they differ, and >1 if an error occurred. .SH "SEE ALSO" zipmerge(1), ziptool(1), libzip(3) .SH "HISTORY" \fBzipcmp\fR was added in libzip 0.6. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/zipcmp.mdoc ================================================ .\" zipcmp.mdoc -- compare zip archives .\" Copyright (C) 2003-2024 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd March 15, 2024 .Dt ZIPCMP 1 .Os .Sh NAME .Nm zipcmp .Nd compare contents of zip archives .Sh SYNOPSIS .Nm .Op Fl ChipqsTtVv .Ar archive1 archive2 .Sh DESCRIPTION .Nm compares the zip archives or directories .Ar archive1 and .Ar archive2 and checks if they contain the same files, comparing their names, uncompressed sizes, and CRCs. File order and compressed size differences are ignored. .Pp Supported options: .Bl -tag -width MMM .It Fl C Check consistency of archives. Results in an error if archive is inconsistent or not valid according to the zip specification. .It Fl h Display a short help message and exit. .It Fl i Compare names ignoring case distinctions. .It Fl p Enable paranoid checks. Compares extra fields, comments, and other meta data. (Automatically disabled if one of the archives is a directory.) These checks are skipped for files where the data differs. .It Fl q Quiet mode. Compare .Fl v . .It Fl s Print a summary of how many files where added and removed. .It Fl T Additionally compare the time stamps of the entries. .It Fl t Test zip files by comparing the contents to their checksums. .It Fl V Display version information and exit. .It Fl v Verbose mode. Print details about differences to stdout. (This is the default.) .El .Sh EXIT STATUS .Nm exits 0 if the two archives contain the same files, 1 if they differ, and >1 if an error occurred. .Sh SEE ALSO .Xr zipmerge 1 , .Xr ziptool 1 , .Xr libzip 3 .Sh HISTORY .Nm was added in libzip 0.6. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/man/zipmerge.html ================================================ ================================================ FILE: external/libzip/man/zipmerge.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" zipmerge.mdoc -- merge zip archives .\" Copyright (C) 2004-2022 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIPMERGE" "1" "November 7, 2023" "NiH" "General Commands Manual" .nh .if n .ad l .SH "NAME" \fBzipmerge\fR \- merge zip archives .SH "SYNOPSIS" .HP 9n \fBzipmerge\fR [\fB\-DhIiSsV\fR] \fItarget-zip\fR \fIsource-zip\fR\ [\fIsource-zip\ ...\fR] .SH "DESCRIPTION" \fBzipmerge\fR copies files from the source zip archives \fIsource-zip\fR to the target zip archive \fItarget-zip\fR. By default, files in the source zip archives overwrite existing files of the same name in the target zip archive. By default, compressed files in the source archive are copied directly without recompression, uncompressed files are compressed using the default compression algorithm. .PP Supported options: .TP 5n \fB\-D\fR Ignore directory components in file name comparisons. This option is slow for archives with many files. .TP 5n \fB\-h\fR Display a short help message and exit. .TP 5n \fB\-I\fR Ignore case in file name comparisons This option is slow for archives with many files. .TP 5n \fB\-i\fR Ask before overwriting files. See also \fB\-s\fR. .TP 5n \fB\-k\fR Do not compress files that were uncompressed in \fIsource-zip\fR, otherwise they are compressed with the default compression method. .TP 5n \fB\-S\fR Do not overwrite files that have the same name, size, and CRC32 in both the source and target archives. .TP 5n \fB\-s\fR When \fB\-i\fR is given, do not ask before overwriting files that have the same name, size, and CRC32. .TP 5n \fB\-V\fR Display version information and exit. .SH "EXIT STATUS" \fBzipmerge\fR exits 0 on success and >1 if an error occurred. .SH "SEE ALSO" zipcmp(1), ziptool(1), libzip(3) .SH "HISTORY" \fBzipmerge\fR was added in libzip 0.6. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> .SH "CAVEATS" \fBzipmerge\fR uses one open file descriptor per zip archive. If you need to merge a lot of zip archives, check your shell's file descriptor ulimit and either increase it or run \fBzipmerge\fR multiple times with e.g. 1000 source zip archives each time. ================================================ FILE: external/libzip/man/zipmerge.mdoc ================================================ .\" zipmerge.mdoc -- merge zip archives .\" Copyright (C) 2004-2022 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd November 7, 2023 .Dt ZIPMERGE 1 .Os .Sh NAME .Nm zipmerge .Nd merge zip archives .Sh SYNOPSIS .Nm .Op Fl DhIiSsV .Ar target-zip .Ar source-zip Op Ar source-zip ... .Sh DESCRIPTION .Nm copies files from the source zip archives .Ar source-zip to the target zip archive .Ar target-zip . By default, files in the source zip archives overwrite existing files of the same name in the target zip archive. By default, compressed files in the source archive are copied directly without recompression, uncompressed files are compressed using the default compression algorithm. .Pp Supported options: .Bl -tag -width MMM .It Fl D Ignore directory components in file name comparisons. This option is slow for archives with many files. .It Fl h Display a short help message and exit. .It Fl I Ignore case in file name comparisons This option is slow for archives with many files. .It Fl i Ask before overwriting files. See also .Fl s . .It Fl k Do not compress files that were uncompressed in .Ar source-zip , otherwise they are compressed with the default compression method. .It Fl S Do not overwrite files that have the same name, size, and CRC32 in both the source and target archives. .It Fl s When .Fl i is given, do not ask before overwriting files that have the same name, size, and CRC32. .It Fl V Display version information and exit. .El .Sh EXIT STATUS .Nm exits 0 on success and >1 if an error occurred. .Sh SEE ALSO .Xr zipcmp 1 , .Xr ziptool 1 , .Xr libzip 3 .Sh HISTORY .Nm was added in libzip 0.6. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at .Sh CAVEATS .Nm uses one open file descriptor per zip archive. If you need to merge a lot of zip archives, check your shell's file descriptor ulimit and either increase it or run .Nm multiple times with e.g. 1000 source zip archives each time. ================================================ FILE: external/libzip/man/ziptool.html ================================================ ================================================ FILE: external/libzip/man/ziptool.man ================================================ .\" Automatically generated from an mdoc input file. Do not edit. .\" ziptool.mdoc -- modify zip archives in multiple ways .\" Copyright (C) 2016-2022 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .TH "ZIPTOOL" "1" "January 23, 2023" "NiH" "General Commands Manual" .nh .if n .ad l .SH "NAME" \fBziptool\fR \- modify zip archives .SH "SYNOPSIS" .HP 8n \fBziptool\fR [\fB\-ceghnrst\fR] [\fB\-l\fR\ \fIlength\fR] [\fB\-o\fR\ \fIoffset\fR] \fIzip-archive\fR \fBcommand\fR\ [\fIcommand-args\ ...\fR] [\fBcommand\fR\ [\fIcommand-args\ ...\fR]\ ...] .SH "DESCRIPTION" \fBziptool\fR modifies the zip archive \fIzip-archive\fR according to the \fIcommands\fR given. .PP Supported options: .TP 13n \fB\-c\fR Check zip archive consistency when opening it. .TP 13n \fB\-e\fR Error if archive already exists (only useful with \fB\-n\fR). .TP 13n \fB\-g\fR Guess file name encoding (for \fBstat\fR command). .TP 13n \fB\-h\fR Display help. .TP 13n \fB\-l\fR \fIlength\fR Only read \fIlength\fR bytes of archive. See also \fB\-o\fR. .TP 13n \fB\-n\fR Create archive if it doesn't exist. See also \fB\-e\fR. .TP 13n \fB\-o\fR \fIoffset\fR Start reading input archive from \fIoffset\fR. See also \fB\-l\fR. .TP 13n \fB\-r\fR Print raw file name encoding without translation (for \fBstat\fR command). .TP 13n \fB\-s\fR Follow file name convention strictly (for \fBstat\fR command). .TP 13n \fB\-t\fR Disregard current file contents, if any. \fINote\fR: use this with care, it deletes all existing file contents when you modify the archive. .SS "Commands" For all commands below, the index is zero-based. In other words, the first entry in the zip archive has index 0. .PP Supported commands and arguments are: .TP 12n \fBadd\fR \fIname content\fR Add file called \fIname\fR using the string \fIcontent\fR from the command line as data. .TP 12n \fBadd_dir\fR \fIname\fR Add directory \fIname\fR. .TP 12n \fBadd_file\fR \fIname file_to_add offset len\fR Add file \fIname\fR to archive, using \fIlen\fR bytes from the file \fIfile_to_add\fR as input data, starting at \fIoffset\fR. .TP 12n \fBadd_from_zip\fR \fIname archivename index offset len\fR Add file called \fIname\fR to archive using data from another zip archive \fIarchivename\fR using the entry with index \fIindex\fR and reading \fIlen\fR bytes from \fIoffset\fR. .TP 12n \fBcat\fR \fIindex\fR Output file contents for entry \fIindex\fR to stdout. .TP 12n \fBcount_extra\fR \fIindex flags\fR Print the number of extra fields for archive entry \fIindex\fR using \fIflags\fR. .TP 12n \fBcount_extra_by_id\fR \fIindex extra_id flags\fR Print number of extra fields of type \fIextra_id\fR for archive entry \fIindex\fR using \fIflags\fR. .TP 12n \fBdelete\fR \fIindex\fR Remove entry at \fIindex\fR from zip archive. .TP 12n \fBdelete_extra\fR \fIindex extra_idx flags\fR Remove extra field number \fIextra_idx\fR from archive entry \fIindex\fR using \fIflags\fR. .TP 12n \fBdelete_extra_by_id\fR \fIindex extra_id extra_index flags\fR Remove extra field number \fIextra_index\fR of type \fIextra_id\fR from archive entry \fIindex\fR using \fIflags\fR. .TP 12n \fBget_archive_comment\fR Print archive comment. .TP 12n \fBget_archive_flag\fR \fIflag\fR Print state of archive flag \fIflag\fR. .TP 12n \fBget_extra\fR \fIindex extra_index flags\fR Print extra field \fIextra_index\fR for archive entry \fIindex\fR using \fIflags\fR. .TP 12n \fBget_extra_by_id\fR \fIindex extra_id extra_index flags\fR Print extra field \fIextra_index\fR of type \fIextra_id\fR for archive entry \fIindex\fR using \fIflags\fR. .TP 12n \fBget_file_comment\fR \fIindex\fR Get file comment for archive entry \fIindex\fR. .TP 12n \fBget_num_entries\fR \fIflags\fR Print number of entries in archive using \fIflags\fR. .TP 12n \fBname_locate\fR \fIname flags\fR Find entry in archive with the filename \fIname\fR using \fIflags\fR and print its index. .TP 12n \fBrename\fR \fIindex name\fR Rename archive entry \fIindex\fR to \fIname\fR. .TP 12n \fBreplace_file_contents\fR \fIindex data\fR Replace file contents for archive entry \fIindex\fR with the string \fIdata\fR. .TP 12n \fBset_archive_comment\fR \fIcomment\fR Set archive comment to \fIcomment\fR. .TP 12n \fBget_archive_flag\fR \fIflag\fR \fIvalue\fR Set archive flag \fIflag\fR to \fIvalue\fR. .TP 12n \fBset_extra\fR \fIindex extra_id extra_index flags value\fR Set extra field number \fIextra_index\fR of type \fIextra_id\fR for archive entry \fIindex\fR using \fIflags\fR to \fIvalue\fR. .TP 12n \fBset_file_comment\fR \fIindex comment\fR Set file comment for archive entry \fIindex\fR to string \fIcomment\fR. .TP 12n \fBset_file_compression\fR \fIindex method compression_flags\fR Set file compression method for archive entry \fIindex\fR to \fImethod\fR using \fIcompression_flags\fR. \fINote\fR: Currently, \fIcompression_flags\fR are ignored. .TP 12n \fBset_file_encryption\fR \fIindex method password\fR Set file encryption method for archive entry \fIindex\fR to \fImethod\fR with password \fIpassword\fR. .TP 12n \fBset_file_mtime\fR \fIindex timestamp\fR Set file modification time for archive entry \fIindex\fR to UNIX mtime \fItimestamp\fR. .TP 12n \fBset_file_mtime_all\fR \fItimestamp\fR Set file modification time for all archive entries to UNIX mtime \fItimestamp\fR. .TP 12n \fBset_password\fR \fIpassword\fR Set default password for encryption/decryption to \fIpassword\fR. .TP 12n \fBstat\fR \fIindex\fR Print information about archive entry \fIindex\fR. .SS "Flags" Some commands take flag arguments. Each character in the argument sets the corresponding flag. Use 0 or the empty string for no flags. .PP Supported flags are: .RS 6n .PD 0 .TP 5n \fI4\fR \fRZIP_FL_ENC_CP437\fR .TP 5n \fI8\fR \fRZIP_FL_ENC_UTF_8\fR .TP 5n \fIC\fR \fRZIP_FL_NOCASE\fR .TP 5n \fIc\fR \fRZIP_FL_CENTRAL\fR .TP 5n \fId\fR \fRZIP_FL_NODIR\fR .TP 5n \fIl\fR \fRZIP_FL_LOCAL\fR .TP 5n \fIr\fR \fRZIP_FL_ENC_RAW\fR .TP 5n \fIs\fR \fRZIP_FL_ENC_STRICT\fR .TP 5n \fIu\fR \fRZIP_FL_UNCHANGED\fR .RE .PD .SS "Archive flags" \fBget_archive_flag\fR and \fBset_archive_flag\fR work on the following flags: .RS 6n .PD 0 .TP 4n \fB\(bu\fR \fRcreate-or-keep-empty-file-for-archive\fR .TP 4n \fB\(bu\fR \fRis-torrentzip\fR .TP 4n \fB\(bu\fR \fRrdonly\fR .TP 4n \fB\(bu\fR \fRwant-torrentzip\fR .RE .PD .SS "Compression Methods" Some commands take compression method arguments. Supported methods are: .RS 6n .PD 0 .TP 4n \fB\(bu\fR \fRdefault\fR .TP 4n \fB\(bu\fR \fRdeflate\fR .TP 4n \fB\(bu\fR \fRstore\fR .RE .PD .SS "Encryption Methods" Some commands take encryption method arguments. Supported methods are: .RS 6n .PD 0 .TP 4n \fB\(bu\fR \fRnone\fR .TP 4n \fB\(bu\fR \fRAES-128\fR .TP 4n \fB\(bu\fR \fRAES-192\fR .TP 4n \fB\(bu\fR \fRAES-256\fR .RE .PD .SH "EXIT STATUS" .br The \fBziptool\fR utility exits\~0 on success, and\~>0 if an error occurs. .SH "EXAMPLES" Add a file called \fIteststring.txt\fR to the zip archive \fItestbuffer.zip\fR with data \(lqThis is a test.\en\(rq where \(lq\en\(rq is replaced with a newline character: .nf .sp .RS 6n ziptool testbuffer.zip add teststring.txt \\"This is a test.\en\\" .RE .fi .PP Delete the first file from the zip archive \fItestfile.zip\fR: .nf .sp .RS 6n ziptool testfile.zip delete 0 .RE .fi .SH "SEE ALSO" zipcmp(1), zipmerge(1), libzip(3) .SH "HISTORY" \fBziptool\fR was added in libzip 1.1. .SH "AUTHORS" Dieter Baron <\fIdillo@nih.at\fR> and Thomas Klausner <\fIwiz@gatalith.at\fR> ================================================ FILE: external/libzip/man/ziptool.mdoc ================================================ .\" ziptool.mdoc -- modify zip archives in multiple ways .\" Copyright (C) 2016-2022 Dieter Baron and Thomas Klausner .\" .\" This file is part of libzip, a library to manipulate ZIP archives. .\" The authors can be contacted at .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. The names of the authors may not be used to endorse or promote .\" products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd January 23, 2023 .Dt ZIPTOOL 1 .Os .Sh NAME .Nm ziptool .Nd modify zip archives .Sh SYNOPSIS .Nm .Op Fl ceghnrst .Op Fl l Ar length .Op Fl o Ar offset .Ar zip-archive .Cm command Op Ar command-args ... .Op Cm command Oo Ar command-args ... Oc ... .Sh DESCRIPTION .Nm modifies the zip archive .Ar zip-archive according to the .Ar commands given. .Pp Supported options: .Bl -tag -width MoMoffsetMM .It Fl c Check zip archive consistency when opening it. .It Fl e Error if archive already exists (only useful with .Fl n ) . .It Fl g Guess file name encoding (for .Cm stat command). .It Fl h Display help. .It Fl l Ar length Only read .Ar length bytes of archive. See also .Fl o . .It Fl n Create archive if it doesn't exist. See also .Fl e . .It Fl o Ar offset Start reading input archive from .Ar offset . See also .Fl l . .It Fl r Print raw file name encoding without translation (for .Cm stat command). .It Fl s Follow file name convention strictly (for .Cm stat command). .It Fl t Disregard current file contents, if any. .Em Note : use this with care, it deletes all existing file contents when you modify the archive. .El .Ss Commands For all commands below, the index is zero-based. In other words, the first entry in the zip archive has index 0. .Pp Supported commands and arguments are: .Bl -tag -width 10n .It Cm add Ar name content Add file called .Ar name using the string .Ar content from the command line as data. .It Cm add_dir Ar name Add directory .Ar name . .It Cm add_file Ar name file_to_add offset len Add file .Ar name to archive, using .Ar len bytes from the file .Ar file_to_add as input data, starting at .Ar offset . .It Cm add_from_zip Ar name archivename index offset len Add file called .Ar name to archive using data from another zip archive .Ar archivename using the entry with index .Ar index and reading .Ar len bytes from .Ar offset . .It Cm cat Ar index Output file contents for entry .Ar index to stdout. .It Cm count_extra Ar index flags Print the number of extra fields for archive entry .Ar index using .Ar flags . .It Cm count_extra_by_id Ar index extra_id flags Print number of extra fields of type .Ar extra_id for archive entry .Ar index using .Ar flags . .It Cm delete Ar index Remove entry at .Ar index from zip archive. .It Cm delete_extra Ar index extra_idx flags Remove extra field number .Ar extra_idx from archive entry .Ar index using .Ar flags . .It Cm delete_extra_by_id Ar index extra_id extra_index flags Remove extra field number .Ar extra_index of type .Ar extra_id from archive entry .Ar index using .Ar flags . .It Cm get_archive_comment Print archive comment. .It Cm get_archive_flag Ar flag Print state of archive flag .Ar flag . .It Cm get_extra Ar index extra_index flags Print extra field .Ar extra_index for archive entry .Ar index using .Ar flags . .It Cm get_extra_by_id Ar index extra_id extra_index flags Print extra field .Ar extra_index of type .Ar extra_id for archive entry .Ar index using .Ar flags . .It Cm get_file_comment Ar index Get file comment for archive entry .Ar index . .It Cm get_num_entries Ar flags Print number of entries in archive using .Ar flags . .It Cm name_locate Ar name flags Find entry in archive with the filename .Ar name using .Ar flags and print its index. .It Cm rename Ar index name Rename archive entry .Ar index to .Ar name . .It Cm replace_file_contents Ar index data Replace file contents for archive entry .Ar index with the string .Ar data . .It Cm set_archive_comment Ar comment Set archive comment to .Ar comment . .It Cm get_archive_flag Ar flag Ar value Set archive flag .Ar flag to .Ar value . .It Cm set_extra Ar index extra_id extra_index flags value Set extra field number .Ar extra_index of type .Ar extra_id for archive entry .Ar index using .Ar flags to .Ar value . .It Cm set_file_comment Ar index comment Set file comment for archive entry .Ar index to string .Ar comment . .It Cm set_file_compression Ar index method compression_flags Set file compression method for archive entry .Ar index to .Ar method using .Ar compression_flags . .Em Note : Currently, .Ar compression_flags are ignored. .It Cm set_file_encryption Ar index method password Set file encryption method for archive entry .Ar index to .Ar method with password .Ar password . .It Cm set_file_mtime Ar index timestamp Set file modification time for archive entry .Ar index to UNIX mtime .Ar timestamp . .It Cm set_file_mtime_all Ar timestamp Set file modification time for all archive entries to UNIX mtime .Ar timestamp . .It Cm set_password Ar password Set default password for encryption/decryption to .Ar password . .It Cm stat Ar index Print information about archive entry .Ar index . .El .Ss Flags Some commands take flag arguments. Each character in the argument sets the corresponding flag. Use 0 or the empty string for no flags. .Pp Supported flags are: .Bl -tag -width MMM -compact -offset indent .It Ar 4 .Dv ZIP_FL_ENC_CP437 .It Ar 8 .Dv ZIP_FL_ENC_UTF_8 .It Ar C .Dv ZIP_FL_NOCASE .It Ar c .Dv ZIP_FL_CENTRAL .It Ar d .Dv ZIP_FL_NODIR .It Ar l .Dv ZIP_FL_LOCAL .It Ar r .Dv ZIP_FL_ENC_RAW .It Ar s .Dv ZIP_FL_ENC_STRICT .It Ar u .Dv ZIP_FL_UNCHANGED .El .Ss Archive flags .Cm get_archive_flag and .Cm set_archive_flag work on the following flags: .Bl -bullet -compact -offset indent .It .Dv create-or-keep-empty-file-for-archive .It .Dv is-torrentzip .It .Dv rdonly .It .Dv want-torrentzip .El .Ss Compression Methods Some commands take compression method arguments. Supported methods are: .Bl -bullet -compact -offset indent .It .Dv default .It .Dv deflate .It .Dv store .El .Ss Encryption Methods Some commands take encryption method arguments. Supported methods are: .Bl -bullet -compact -offset indent .It .Dv none .It .Dv AES-128 .It .Dv AES-192 .It .Dv AES-256 .El .Sh EXIT STATUS .Ex -std .Sh EXAMPLES Add a file called .Pa teststring.txt to the zip archive .Pa testbuffer.zip with data .Dq This is a test.\en where .Dq \en is replaced with a newline character: .Bd -literal -offset indent ziptool testbuffer.zip add teststring.txt \\"This is a test.\en\\" .Ed .Pp Delete the first file from the zip archive .Pa testfile.zip : .Bd -literal -offset indent ziptool testfile.zip delete 0 .Ed .Sh SEE ALSO .Xr zipcmp 1 , .Xr zipmerge 1 , .Xr libzip 3 .Sh HISTORY .Nm was added in libzip 1.1. .Sh AUTHORS .An -nosplit .An Dieter Baron Aq Mt dillo@nih.at and .An Thomas Klausner Aq Mt wiz@gatalith.at ================================================ FILE: external/libzip/ossfuzz/CMakeLists.txt ================================================ set(FUZZ_PROGRAMS zip_read_file_fuzzer zip_read_fuzzer zip_write_encrypt_aes256_file_fuzzer zip_write_encrypt_pkware_file_fuzzer ) foreach(PROGRAM IN LISTS FUZZ_PROGRAMS) add_executable(${PROGRAM} ${PROGRAM}.c) target_sources(${PROGRAM} PRIVATE fuzz_main.c) target_include_directories(${PROGRAM} PRIVATE BEFORE ${PROJECT_SOURCE_DIR}/lib ${PROJECT_BINARY_DIR}) target_link_libraries(${PROGRAM} zip) endforeach() add_custom_target(list-fuzzers COMMAND echo FUZZERS: ${FUZZ_PROGRAMS} ) ================================================ FILE: external/libzip/ossfuzz/fuzz_main.c ================================================ #include #include #include /* fuzz target entry point, works without libFuzzer */ extern int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size); int main(int argc, char **argv) { FILE *f = NULL; char *buf = NULL; long siz_buf; if (argc < 2) { fprintf(stderr, "no input file\n"); goto err; } f = fopen(argv[1], "rb"); if (f == NULL) { fprintf(stderr, "error opening input file %s\n", argv[1]); goto err; } fseek(f, 0, SEEK_END); siz_buf = ftell(f); rewind(f); if (siz_buf < 1) { fprintf(stderr, "zero-byte file not supported\n"); goto err; } buf = (char *)malloc(siz_buf); if (buf == NULL) { fprintf(stderr, "malloc() failed\n"); goto err; } if (fread(buf, siz_buf, 1, f) != 1) { fprintf(stderr, "fread() failed\n"); goto err; } fclose(f); f = NULL; (void)LLVMFuzzerTestOneInput((uint8_t *)buf, siz_buf); err: if (f) { fclose(f); } free(buf); return 0; } ================================================ FILE: external/libzip/ossfuzz/ossfuzz.sh ================================================ #!/bin/bash -eu # Copyright 2019 Google Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ################################################################################ # This script is meant to be run by # https://github.com/google/oss-fuzz/blob/master/projects/libzip/Dockerfile mkdir build cd build cmake -DBUILD_SHARED_LIBS=OFF -DENABLE_GNUTLS=OFF -DENABLE_MBEDTLS=OFF -DENABLE_OPENSSL=ON -DBUILD_TOOLS=OFF -DHAVE_CRYPTO=ON .. make -j$(nproc) for fuzzer in $(make list-fuzzers | sed -n 's/^FUZZERS: //p') do $CXX $CFLAGS -I. -I../lib \ $SRC/libzip/ossfuzz/$fuzzer.c \ -o $OUT/$fuzzer \ $LIB_FUZZING_ENGINE $SRC/libzip/build/lib/libzip.a -lbz2 -llzma -lz -lzstd -v -lssl -lcrypto done find $SRC/libzip/regress -name "*zip" | \ xargs zip $OUT/zip_read_fuzzer_seed_corpus.zip cp $SRC/libzip/ossfuzz/zip_read_fuzzer.dict $OUT/ cp $SRC/libzip/ossfuzz/zip_write_encrypt_aes256_file_fuzzer_seed_corpus.zip $OUT/ for pair in \ zip_read_fuzzer:zip_read_file_fuzzer \ zip_write_encrypt_aes256_file_fuzzer:zip_write_encrypt_pkware_file_fuzzer do source=${pair%%:*} target=${pair##*:} for file in .dict _seed_corpus.zip do if [ -f $OUT/$source$file ] then cp $OUT/$source$file $OUT/$target$file fi done done ================================================ FILE: external/libzip/ossfuzz/zip_read_file_fuzzer.c ================================================ /* zip_random_uwp.c -- fill the user's buffer with random stuff (UWP version) Copyright (C) 2017-2023 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include "zip_read_fuzzer_common.h" /** This fuzzing target takes input data, creates a ZIP archive from it, checks the archive's consistency, and iterates over the entries in the archive, reading data from each entry. **/ #ifdef __cplusplus extern "C" #endif int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { zip_t *za; const char *name = "test.zip"; FILE *fp; zip_error_t error; int err = 0; (void)remove(name); if ((fp = fopen(name, "wb")) == NULL) { fprintf(stderr, "can't create file '%s': %s\n", name, strerror(errno)); return 0; } if (fwrite(data, 1, size, fp) != size) { fprintf(stderr, "can't write data to file '%s': %s\n", name, strerror(errno)); fclose(fp); (void)remove(name); return 0; } if (fclose(fp) < 0) { fprintf(stderr, "can't close file '%s': %s\n", name, strerror(errno)); (void)remove(name); return 0; } za = zip_open(name, 0, &err); zip_error_init_with_code(&error, err); fuzzer_read(za, &error, NULL); (void)remove(name); return 0; } ================================================ FILE: external/libzip/ossfuzz/zip_read_fuzzer.c ================================================ #include #include #include "zip_read_fuzzer_common.h" #ifdef __cplusplus extern "C" #endif int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { zip_source_t *src; zip_error_t error; zip_t *za; zip_error_init(&error); if ((src = zip_source_buffer_create(data, size, 0, &error)) == NULL) { zip_error_fini(&error); return 0; } za = zip_open_from_source(src, 0, &error); fuzzer_read(za, &error, "secretpassword"); if (za == NULL) { zip_source_free(src); } return 0; } ================================================ FILE: external/libzip/ossfuzz/zip_read_fuzzer.dict ================================================ header_cd="\x50\x4b\x01\x02" header_local_file_header="\x50\x4b\x03\x04" header_eocd="\x50\x4b\x05\x06" header_zip64_eocd="\x50\x4b\x06\x06" header_zip64_eocd_locator="\x50\x4b\x06\x07" header_data_descriptor="\x50\x4b\x07\x08" ================================================ FILE: external/libzip/ossfuzz/zip_read_fuzzer_common.h ================================================ /* zip_read_fuzzer_common.h -- common function for fuzzers to read all files in an archive Copyright (C) 2023 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "zip.h" void fuzzer_read(zip_t *za, zip_error_t *error, const char *password) { zip_int64_t i, n, ret; char buf[32768]; if (za == NULL) { fprintf(stderr, "Error opening archive: %s\n", zip_error_strerror(error)); zip_error_fini(error); return; } zip_set_default_password(za, password); zip_error_fini(error); n = zip_get_num_entries(za, 0); for (i = 0; i < n; i++) { zip_file_t *f = zip_fopen_index(za, i, 0); if (f == NULL) { fprintf(stderr, "Error opening file %d: %s\n", (int)i, zip_strerror(za)); continue; } while ((ret = zip_fread(f, buf, sizeof(buf))) > 0) { ; } if (ret < 0) { fprintf(stderr, "Error reading file %d: %s\n", (int)i, zip_strerror(za)); } if (zip_fclose(f) < 0) { fprintf(stderr, "Error closing file %d: %s\n", (int)i, zip_strerror(za)); continue; } } if (zip_close(za) < 0) { fprintf(stderr, "Error closing archive: %s\n", zip_strerror(za)); zip_discard(za); } } ================================================ FILE: external/libzip/ossfuzz/zip_write_encrypt_aes256_file_fuzzer.c ================================================ #include #include #include #include #include /** This fuzzing target takes input data, creates a ZIP archive, load it to a buffer, adds a file to it with AES-256 encryption and a specified password, and then closes and removes the archive. The purpose of this fuzzer is to test security of ZIP archive handling and encryption in the libzip by subjecting it to various inputs, including potentially malicious or malformed data of different file types. **/ #ifdef __cplusplus extern "C" #endif int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { const char *path = "test_aes256.zip"; const char *password = "password"; const char *file = "filename"; int error = 0; struct zip *archive; (void)remove(path); if ((archive = zip_open(path, ZIP_CREATE, &error)) == NULL) { return -1; } struct zip_source *source = zip_source_buffer(archive, data, size, 0); if (source == NULL) { fprintf(stderr, "failed to create source buffer. %s\n", zip_strerror(archive)); zip_discard(archive); return -1; } int index = (int)zip_file_add(archive, file, source, ZIP_FL_OVERWRITE); if (index < 0) { fprintf(stderr, "failed to add file to archive: %s\n", zip_strerror(archive)); zip_source_free(source); zip_discard(archive); return -1; } if (zip_file_set_encryption(archive, index, ZIP_EM_AES_256, password) < 0) { fprintf(stderr, "failed to set file encryption: %s\n", zip_strerror(archive)); zip_discard(archive); return -1; } if (zip_close(archive) < 0) { fprintf(stderr, "error closing archive: %s\n", zip_strerror(archive)); zip_discard(archive); return -1; } (void)remove(path); return 0; } ================================================ FILE: external/libzip/ossfuzz/zip_write_encrypt_pkware_file_fuzzer.c ================================================ #include #include #include #include #include /** This fuzzing target takes input data, creates a ZIP archive, load it to a buffer, adds a file to it with traditional PKWARE encryption and a specified password, and then closes and removes the archive. The purpose of this fuzzer is to test security of ZIP archive handling and encryption in the libzip by subjecting it to various inputs, including potentially malicious or malformed data of different file types. **/ #ifdef __cplusplus extern "C" #endif int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { const char *path = "test_pkware.zip"; const char *password = "password"; const char *file = "filename"; int error = 0; struct zip *archive; (void)remove(path); if ((archive = zip_open(path, ZIP_CREATE, &error)) == NULL) { return -1; } struct zip_source *source = zip_source_buffer(archive, data, size, 0); if (source == NULL) { fprintf(stderr, "failed to create source buffer. %s\n", zip_strerror(archive)); zip_discard(archive); return -1; } int index = (int)zip_file_add(archive, file, source, ZIP_FL_OVERWRITE); if (index < 0) { fprintf(stderr, "failed to add file to archive: %s\n", zip_strerror(archive)); zip_discard(archive); return -1; } if (zip_file_set_encryption(archive, index, ZIP_EM_TRAD_PKWARE, password) < 0) { fprintf(stderr, "failed to set file encryption: %s\n", zip_strerror(archive)); zip_discard(archive); return -1; } if (zip_close(archive) < 0) { fprintf(stderr, "error closing archive: %s\n", zip_strerror(archive)); zip_discard(archive); return -1; } (void)remove(path); return 0; } ================================================ FILE: external/libzip/regress/CMakeLists.txt ================================================ check_function_exists(getopt HAVE_GETOPT) set(TEST_PROGRAMS add_from_filep can_clone_file fopen_unchanged fseek nonrandomopentest liboverride-test ) set(GETOPT_USERS fread tryopen ) set(HOLE_USERS hole ziptool_regress ) set(ZIP_PROGRAMS ${TEST_PROGRAMS} ${GETOPT_USERS} ${HOLE_USERS}) foreach(PROGRAM IN LISTS ZIP_PROGRAMS) add_executable(${PROGRAM} ${PROGRAM}.c) target_include_directories(${PROGRAM} PRIVATE BEFORE ${PROJECT_SOURCE_DIR}/lib ${PROJECT_BINARY_DIR}) target_link_libraries(${PROGRAM} zip) endforeach() # both programs using source_hole.c also use getopt if(NOT HAVE_GETOPT) foreach(PROGRAM IN LISTS GETOPT_USERS HOLE_USERS) target_sources(${PROGRAM} PRIVATE ../src/getopt.c) target_include_directories(${PROGRAM} PRIVATE BEFORE ${PROJECT_SOURCE_DIR}/src) endforeach() endif(NOT HAVE_GETOPT) foreach(PROGRAM IN LISTS HOLE_USERS) target_sources(${PROGRAM} PRIVATE source_hole.c) endforeach() foreach(PROGRAM IN LISTS FUZZ_PROGRAMS) target_sources(${PROGRAM} PRIVATE fuzz_main.c) endforeach() # for including ziptool.c target_include_directories(ziptool_regress PRIVATE BEFORE ${PROJECT_SOURCE_DIR}/src) set(DL_USERS # malloc nonrandomopen liboverride ) foreach(PROGRAM IN LISTS DL_USERS) add_library(${PROGRAM} MODULE ${PROGRAM}.c) target_include_directories(${PROGRAM} PRIVATE BEFORE ${PROJECT_SOURCE_DIR}/lib ${PROJECT_BINARY_DIR}) endforeach() add_custom_target(cleanup COMMAND ${CMAKE_COMMAND} -DDIR=${PROJECT_BINARY_DIR}/regress -P ${PROJECT_SOURCE_DIR}/regress/cleanup.cmake ) add_custom_target(testinput ALL VERBATIM COMMAND ${CMAKE_COMMAND} -E tar x ${PROJECT_SOURCE_DIR}/regress/manyfiles-zip.zip COMMAND ${CMAKE_COMMAND} -E tar x ${PROJECT_SOURCE_DIR}/regress/bigzero-zip.zip DEPENDS ${PROJECT_SOURCE_DIR}/regress/manyfiles-zip.zip ${PROJECT_SOURCE_DIR}/regress/bigzero-zip.zip ) set_property(DIRECTORY PROPERTY ADDITIONAL_MAKE_CLEAN_FILES bigzero.zip manyfiles-133000.zip manyfiles-65536.zip manyfiles-fewer.zip manyfiles-more.zip manyfiles-zip64-modulo.zip manyfiles-zip64.zip manyfiles.zip ) set(path "$;$ENV{PATH}") if (TARGET zlib) set(path "$;${path}") endif() string(REPLACE ";" "\\;" path "${path}") set(ENV{srcdir} ${PROJECT_SOURCE_DIR}/regress) file(GLOB EXTRA_TESTS ${CMAKE_CURRENT_SOURCE_DIR}/*.test) foreach(FULL_CASE IN LISTS EXTRA_TESTS) get_filename_component(CASE ${FULL_CASE} NAME) add_test(NAME ${CASE} COMMAND ${NIHTEST} -v ${CASE}) # TODO: add --bin-sub-directory $ set_tests_properties(${CASE} PROPERTIES SKIP_RETURN_CODE 77) set_tests_properties(${CASE} PROPERTIES ENVIRONMENT "PATH=${path}") endforeach() set(XFAIL_TESTS # zipcmp_zip_dir_slash.test ) foreach(CASE ${XFAIL_TESTS}) set_tests_properties(${CASE} PROPERTIES WILL_FAIL TRUE) endforeach() add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND}) configure_file(nihtest.conf.in nihtest.conf @ONLY) ================================================ FILE: external/libzip/regress/add_dir.test ================================================ # add directories to zip return 0 arguments testdir.zip add_dir testdir/ add_dir testdir-noslash file testdir.zip {} testdir.zip ================================================ FILE: external/libzip/regress/add_from_buffer.test ================================================ # add buffer contents as file to zip return 0 arguments testbuffer.zip add teststring.txt "This is a test, and it seems to have been successful.\n" file testbuffer.zip {} testbuffer.zip ================================================ FILE: external/libzip/regress/add_from_file.test ================================================ # add file to zip return 0 arguments -- testfile.zip add_file testfile.txt testfile.txt 0 -1 file testfile.txt testfile.txt file testfile.zip {} testfile.zip ================================================ FILE: external/libzip/regress/add_from_file_duplicate.test ================================================ # add already existing file to zip, making duplicate names return 1 arguments -- testfile.zip add_file testfile.txt testfile.txt 0 -1 file testfile.txt testfile.txt file testfile.zip testfile.zip stderr can't add file 'testfile.txt': File already exists end-of-inline-data ================================================ FILE: external/libzip/regress/add_from_file_twice_duplicate.test ================================================ # add file to zip twice, making duplicate names return 1 arguments -- testfile.zip add_file testfile.txt testfile.txt 0 -1 add_file testfile.txt testfile.txt 0 -1 file testfile.txt testfile.txt file testfile.zip {} testfile.zip stderr can't add file 'testfile.txt': File already exists end-of-inline-data ================================================ FILE: external/libzip/regress/add_from_file_unchange.test ================================================ # add file to zip, but revert before closing return 0 arguments -- testfile.zip add_file testfile.txt testfile.txt 0 -1 unchange 0 file testfile.txt testfile.txt ================================================ FILE: external/libzip/regress/add_from_filep.c ================================================ /* add_from_filep.c -- test case for adding file to archive Copyright (C) 1999-2023 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include "zip.h" static const char *prg; int main(int argc, char *argv[]) { const char *archive; const char *file; const char *name; zip_t *za; zip_source_t *zs; int err; FILE *fp; prg = argv[0]; if (argc != 3) { fprintf(stderr, "usage: %s archive file\n", prg); return 1; } archive = argv[1]; file = argv[2]; if ((za = zip_open(archive, ZIP_CREATE, &err)) == NULL) { zip_error_t error; zip_error_init_with_code(&error, err); fprintf(stderr, "%s: can't open zip archive '%s': %s\n", prg, archive, zip_error_strerror(&error)); zip_error_fini(&error); return 1; } if ((fp = fopen(file, "rb")) == NULL) { fprintf(stderr, "%s: can't open input file '%s': %s\n", prg, file, strerror(errno)); return 1; } if ((zs = zip_source_filep(za, fp, 0, -1)) == NULL) { fprintf(stderr, "%s: error creating file source for '%s': %s\n", prg, file, zip_strerror(za)); return 1; } if ((name = strrchr(file, '/')) == NULL) name = file; if (zip_file_add(za, name, zs, 0) == -1) { zip_source_free(zs); fprintf(stderr, "%s: can't add file '%s': %s\n", prg, file, zip_strerror(za)); return 1; } if (zip_close(za) == -1) { fprintf(stderr, "%s: can't close zip archive '%s': %s\n", prg, archive, zip_strerror(za)); return 1; } return 0; } ================================================ FILE: external/libzip/regress/add_from_filep.test ================================================ # add file to zip program add_from_filep return 0 arguments testfile.zip testfile.txt file testfile.txt testfile.txt file testfile.zip {} testfile.zip ================================================ FILE: external/libzip/regress/add_from_stdin.test ================================================ # add stdin to zip arguments -- teststdin.zip add_file teststring.txt /dev/stdin 0 -1 return 0 file teststdin.zip {} teststdin.zip stdin This is a test, and it seems to have been successful. end-of-inline-data ================================================ FILE: external/libzip/regress/add_from_zip_closed.test ================================================ # add deflated file from zip to zip, but close the source before it can be read return 1 arguments -- testfile.zip add_from_zip abac-repeat.txt testdeflated.zzip 0 0 -1 zin_close 0 file testdeflated.zzip testdeflated.zip stderr can't close zip archive 'testfile.zip': Containing zip archive was closed end-of-inline-data ================================================ FILE: external/libzip/regress/add_from_zip_deflated.test ================================================ # add deflated file from zip to zip return 0 arguments -- testfile.zip add_from_zip abac-repeat.txt testdeflated.zzip 0 0 -1 file testdeflated.zzip testdeflated.zip file testfile.zip {} testdeflated.zip ================================================ FILE: external/libzip/regress/add_from_zip_deflated2.test ================================================ # add deflated files from zip to zip return 0 arguments -- testfile.zip add_from_zip abac-repeat.txt testdeflated.zzip 0 0 -1 add_from_zip abac-repeat2.txt testdeflated.zzip 0 0 -1 file testdeflated.zzip testdeflated.zip file testfile.zip {} testdeflated2.zip ================================================ FILE: external/libzip/regress/add_from_zip_partial_deflated.test ================================================ # add parts of a file from zip to zip return 0 arguments -- testfile.zip add_from_zip first firstsecond.zzip 0 0 9 add_from_zip second firstsecond.zzip 0 9 -1 file firstsecond.zzip firstsecond.zip file testfile.zip {} firstsecond-split-stored.zip ================================================ FILE: external/libzip/regress/add_from_zip_partial_stored.test ================================================ # add parts of a file from zip to zip return 0 arguments -- testfile.zip add_from_zip first firstsecond.zzip 1 0 9 add_from_zip second firstsecond.zzip 1 9 -1 file firstsecond.zzip firstsecond.zip file testfile.zip {} firstsecond-split-stored.zip ================================================ FILE: external/libzip/regress/add_from_zip_stored.test ================================================ # add stored file from zip to zip return 0 arguments -- testfile.zip add_from_zip abac-repeat.txt teststored.zzip 0 0 -1 file teststored.zzip teststored.zip file testfile.zip {} testdeflated.zip ================================================ FILE: external/libzip/regress/add_stored.test ================================================ # add file, set compression method to ZIP_CM_STORE return 0 arguments -n test.zip add foo foo set_file_compression 0 store 0 file test.zip {} foo-stored.zip ================================================ FILE: external/libzip/regress/add_stored_in_memory.test ================================================ # add file, set compression method to ZIP_CM_STORE return 0 arguments -mn test.zip add foo foo set_file_compression 0 store 0 file test.zip {} foo-stored.zip ================================================ FILE: external/libzip/regress/buffer-fragment-read.test ================================================ # test reading from a buffer fragment source return 0 arguments -mF 1024 test.zip cat 1 file test.zip cm-default.zip stdout uncompressible end-of-inline-data ================================================ FILE: external/libzip/regress/buffer-fragment-write.test ================================================ # rename file inside zip archive return 0 arguments -mF 100 rename.zip rename 1 notfile2 file rename.zip testcomment.zip rename_ok.zip ================================================ FILE: external/libzip/regress/can_clone_file.c ================================================ /* can_clone_file.c -- does the current filesystem support cloning Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include "config.h" #ifdef HAVE_CLONEFILE #include #include #include #include #include #include #include #elif defined(HAVE_FICLONERANGE) #include #include #include #include #include #include #endif int main(int argc, char *argv[]) { #ifdef HAVE_CLONEFILE struct statfs fs; struct attrlist attribute_list; struct { uint32_t size; vol_capabilities_attr_t capabilities; } volume_attributes; if (statfs(".", &fs) < 0) { fprintf(stderr, "%s: can't get mount point of current directory: %s\n", argv[0], strerror(errno)); exit(1); } /* Not all volumes support clonefile(). A volume can be tested for clonefile() support by using getattrlist(2) to get the volume capabilities attribute ATTR_VOL_CAPABILITIES, and then testing the VOL_CAP_INT_CLONE flag. */ memset(&attribute_list, 0, sizeof(attribute_list)); attribute_list.bitmapcount = ATTR_BIT_MAP_COUNT; attribute_list.volattr = ATTR_VOL_INFO | ATTR_VOL_CAPABILITIES; memset(&volume_attributes, 0, sizeof(volume_attributes)); if (getattrlist(fs.f_mntonname, &attribute_list, &volume_attributes, sizeof(volume_attributes), 0) < 0) { fprintf(stderr, "%s: can't get volume capabilities of '%s': %s\n", argv[0], fs.f_mntonname, strerror(errno)); exit(1); } if (volume_attributes.capabilities.capabilities[VOL_CAPABILITIES_INTERFACES] & VOL_CAP_INT_CLONE) { exit(0); } #elif defined(HAVE_FICLONERANGE) char namea[32] = "a.fioclone.XXXXXX"; char nameb[32] = "b.fioclone.XXXXXX"; int fda, fdb, ret; struct file_clone_range range; if ((fda = mkstemp(namea)) < 0) { fprintf(stderr, "can't create temp file a: %s\n", strerror(errno)); exit(1); } if ((fdb = mkstemp(nameb)) < 0) { fprintf(stderr, "can't create temp file b: %s\n", strerror(errno)); (void)close(fda); (void)remove(namea); exit(1); } if (write(fda, "test\n", 5) < 0) { fprintf(stderr, "can't write temp file a: %s\n", strerror(errno)); (void)close(fda); (void)remove(namea); close(fdb); (void)remove(nameb); exit(1); } range.src_fd = fda; range.src_offset = 0; range.src_length = 0; range.dest_offset = 0; ret = ioctl(fdb, FICLONERANGE, &range); (void)close(fda); (void)close(fdb); (void)remove(namea); (void)remove(nameb); if (ret >= 0) { exit(0); } #endif exit(1); } ================================================ FILE: external/libzip/regress/cancel_45.test ================================================ # test default compression stores if smaller; test cancel after 45% return 1 arguments -n -- test.zip cancel 45 add compressible aaaaaaaaaaaaaa add uncompressible uncompressible add_nul large-compressible 8200 add_file large-uncompressible large-uncompressible 0 -1 file large-uncompressible large-uncompressible stdout 0.0% done 25.0% done 50.0% done end-of-inline-data stderr can't close zip archive 'test.zip': Operation cancelled end-of-inline-data ================================================ FILE: external/libzip/regress/cancel_90.test ================================================ # test default compression stores if smaller; test cancel after 90% return 1 arguments -n -- test.zip cancel 90 add compressible aaaaaaaaaaaaaa add uncompressible uncompressible add_nul large-compressible 8200 add_file large-uncompressible large-uncompressible 0 -1 file large-uncompressible large-uncompressible stdout 0.0% done 25.0% done 50.0% done 75.0% done 100.0% done end-of-inline-data stderr can't close zip archive 'test.zip': Operation cancelled end-of-inline-data ================================================ FILE: external/libzip/regress/changing-size-decreases-fixed.test ================================================ description size of input file decreases between add and close arguments test.zip add_file new muchlonger 0 11 extract_as 0 muchlonger return 1 file test.zip changing-size.zip changing-size.zip file muchlonger muchlonger end-of-inline-data short end-of-inline-data stderr can't close zip archive 'test.zip': Unexpected length of data end-of-inline-data ================================================ FILE: external/libzip/regress/changing-size-decreases.test ================================================ description size of input file decreases between add and close arguments test.zip add_file new muchlonger 0 0 extract_as 0 muchlonger return 1 file test.zip changing-size.zip changing-size.zip file muchlonger muchlonger end-of-inline-data short end-of-inline-data stderr can't close zip archive 'test.zip': Unexpected length of data end-of-inline-data ================================================ FILE: external/libzip/regress/changing-size-increases-fixed.test ================================================ description size of input file increases between add and close arguments test.zip add_file new short 0 6 extract_as 1 short file test.zip changing-size.zip changing-size-muchlo.zip file short short end-of-inline-data muchlonger end-of-inline-data ================================================ FILE: external/libzip/regress/changing-size-increases-unchecked.test ================================================ description size of input file increases between add and close arguments -- test.zip add_file new short 0 -2 extract_as 1 short file test.zip changing-size.zip changing-size-muchlonger.zip file short short end-of-inline-data muchlonger end-of-inline-data ================================================ FILE: external/libzip/regress/changing-size-increases.test ================================================ description size of input file increases between add and close arguments test.zip add_file new short 0 0 extract_as 1 short file test.zip changing-size.zip changing-size-muchl.zip file short short muchlonger end-of-inline-data ================================================ FILE: external/libzip/regress/check_torrentzip_fail.test ================================================ # check if file is torrentzip, fails return 0 arguments testfile.zzip get_archive_flag is-torrentzip file testfile.zzip testfile.zip stdout 0 end-of-inline-data ================================================ FILE: external/libzip/regress/check_torrentzip_modified.test ================================================ # check if file is torrentzip, fails because it was modified afterwards return 0 arguments testfile.zzip get_archive_flag is-torrentzip file testfile.zzip testfile-torrentzip-modified.zip stdout 0 end-of-inline-data ================================================ FILE: external/libzip/regress/check_torrentzip_success.test ================================================ # check if file is torrentzip, succeeds return 0 arguments testfile.zzip get_archive_flag is-torrentzip file testfile.zzip testfile-torrentzip.zip stdout 1 end-of-inline-data ================================================ FILE: external/libzip/regress/cleanup.cmake ================================================ # expect variable DIR FILE(GLOB CLEANDIRS "${DIR}/sandbox-*.d[0-9]*") IF (CLEANDIRS) MESSAGE(STATUS "Removing ${CLEANDIRS}") FILE(REMOVE_RECURSE ${CLEANDIRS}) ENDIF() ================================================ FILE: external/libzip/regress/clone-buffer-add.test ================================================ # test cloning archive from buffer, add new file return 0 arguments -mF 100 test.zzip add new "A new file." set_file_mtime 3 1512998132 file test.zzip gap.zip gap-add.zip ================================================ FILE: external/libzip/regress/clone-buffer-delete.test ================================================ # test cloning archive from buffer, deleting a file return 0 arguments -mF 100 test.zzip delete 2 file test.zzip gap.zip gap-delete.zip ================================================ FILE: external/libzip/regress/clone-buffer-replace.test ================================================ # test cloning archive from buffer, replacing a file return 0 arguments -mF 100 test.zzip replace_file_contents 2 "A changed file." set_file_mtime 2 1512998082 file test.zzip gap.zip gap-replace.zip ================================================ FILE: external/libzip/regress/clone-fs-add.test ================================================ # test cloning archive from filesystem, add new file precheck ./can_clone_file return 0 arguments test.zzip add new "A new file." set_file_mtime 3 1512998132 file test.zzip gap.zip gap-add.zip ================================================ FILE: external/libzip/regress/clone-fs-delete.test ================================================ # test cloning archive from filesystem, deleting a file precheck ./can_clone_file return 0 arguments test.zzip delete 2 file test.zzip gap.zip gap-delete.zip ================================================ FILE: external/libzip/regress/clone-fs-replace.test ================================================ # test cloning archive from filesystem, replacing a file precheck ./can_clone_file return 0 arguments test.zzip replace_file_contents 2 "A changed file." set_file_mtime 2 1512998082 file test.zzip gap.zip gap-replace.zip ================================================ FILE: external/libzip/regress/cm-default.test ================================================ # test default compression stores if smaller return 0 arguments -n -- test.zip add compressible aaaaaaaaaaaaaa add uncompressible uncompressible add_nul large-compressible 8200 add_file large-uncompressible large-uncompressible 0 -1 file test.zip {} cm-default.zip file large-uncompressible large-uncompressible ================================================ FILE: external/libzip/regress/convert_to_torrentzip.test ================================================ # convert file to torrentzip return 0 arguments testfile.zzip set_archive_flag want-torrentzip 1 file testfile.zzip testfile.zip testfile-torrentzip.zip ================================================ FILE: external/libzip/regress/convert_to_torrentzip_ef.test ================================================ # convert file to torrentzip, removing extra fields, internal & external file attributes return 0 arguments testfile.zzip set_archive_flag want-torrentzip 1 file testfile.zzip testfile-ef.zip testfile-torrentzip.zip ================================================ FILE: external/libzip/regress/count_entries.test ================================================ # zip_open: count entries for archive with >65k entries arguments manyfiles.zip get_num_entries 0 return 0 file manyfiles.zip manyfiles.zip stdout 70000 entries in archive end-of-inline-data ================================================ FILE: external/libzip/regress/create_empty_keep.test ================================================ # delete last entry in zip archive return 0 arguments -n testfile.zzip set_archive_flag create-or-keep-file-for-empty-archive 1 file testfile.zzip {} testempty.zip ================================================ FILE: external/libzip/regress/decrypt-correct-password-aes128.test ================================================ # test AES decryption support, extract file using correct password features HAVE_CRYPTO return 0 arguments encrypt.zzip set_password foofoofoo cat 1 file encrypt.zzip encrypt-aes128.zip stdout encrypted end-of-inline-data ================================================ FILE: external/libzip/regress/decrypt-correct-password-aes192.test ================================================ # test AES decryption support, extract file using correct password features HAVE_CRYPTO return 0 arguments encrypt.zzip set_password foofoofoo cat 1 file encrypt.zzip encrypt-aes192.zip stdout encrypted end-of-inline-data ================================================ FILE: external/libzip/regress/decrypt-correct-password-aes256.test ================================================ # test AES decryption support, extract file using correct password features HAVE_CRYPTO return 0 arguments encrypt.zzip set_password foofoofoo cat 1 file encrypt.zzip encrypt-aes256.zip stdout encrypted end-of-inline-data ================================================ FILE: external/libzip/regress/decrypt-correct-password-pkware-2.test ================================================ # test decryption support, extract file using correct password return 0 arguments encrypt.zzip set_password 1234 cat 0 file encrypt.zzip encrypt-1234.zip stdout I would love to try or hear the sample audio your app can produce. I do not want to purchase, because I've purchased so many apps that say they do something and do not deliver. Can you please add audio samples with text you've converted? I'd love to see the end results. Thanks! end-of-inline-data ================================================ FILE: external/libzip/regress/decrypt-correct-password-pkware.test ================================================ # test decryption support, extract file using correct password return 0 arguments encrypt.zzip set_password foo cat 0 file encrypt.zzip encrypt.zip stdout foo end-of-inline-data ================================================ FILE: external/libzip/regress/decrypt-empty-file-pkware.test ================================================ # test decryption support, extract empty file using correct password return 0 arguments empty-pkware.zzip set_password 1 cat 0 file empty-pkware.zzip empty-pkware.zip stdout end-of-inline-data ================================================ FILE: external/libzip/regress/decrypt-no-password-aes256.test ================================================ # test AES decryption support, no password provided features HAVE_CRYPTO return 1 arguments encrypt.zzip cat 1 file encrypt.zzip encrypt-aes256.zip stderr can't open file at index '1': No password provided end-of-inline-data ================================================ FILE: external/libzip/regress/decrypt-wrong-password-aes128.test ================================================ # test AES decryption support, extract file using wrong password features HAVE_CRYPTO return 1 arguments encrypt.zzip set_password notfoonotfoo cat 1 file encrypt.zzip encrypt-aes128.zip stderr can't open file at index '1': Wrong password provided end-of-inline-data ================================================ FILE: external/libzip/regress/decrypt-wrong-password-aes192.test ================================================ # test AES decryption support, extract file using wrong password features HAVE_CRYPTO return 1 arguments encrypt.zzip set_password notfoonotfoo cat 1 file encrypt.zzip encrypt-aes192.zip stderr can't open file at index '1': Wrong password provided end-of-inline-data ================================================ FILE: external/libzip/regress/decrypt-wrong-password-aes256.test ================================================ # test AES decryption support, extract file using wrong password features HAVE_CRYPTO return 1 arguments encrypt.zzip set_password notfoonotfoo cat 1 file encrypt.zzip encrypt-aes256.zip stderr can't open file at index '1': Wrong password provided end-of-inline-data ================================================ FILE: external/libzip/regress/decrypt-wrong-password-pkware-2.test ================================================ # test decryption support, extract file using wrong password (correct: "1234") # In some cases, like this one, the password, even if incorrect, passes the # minimal verification that's possible due to the zip file format specification. return 1 arguments encrypt.zzip set_password sample cat 0 file encrypt.zzip encrypt-1234.zip stderr can't read file at index '0': Zlib error: data error end-of-inline-data ================================================ FILE: external/libzip/regress/decrypt-wrong-password-pkware.test ================================================ # test decryption support, extract file using wrong password return 1 arguments encrypt.zzip set_password notfoo cat 0 file encrypt.zzip encrypt.zip stderr can't open file at index '0': Wrong password provided end-of-inline-data ================================================ FILE: external/libzip/regress/delete_add_same.test ================================================ # delete entry in zip archive then add file of same name # time is now(), so use zipcmp return 0 arguments testfile.zip delete 0 add testfile.txt test file testfile.zip testfile.zip test2.zip ================================================ FILE: external/libzip/regress/delete_invalid.test ================================================ # delete last entry in zip archive return 1 arguments testfile.zzip delete 5 file testfile.zzip testfile.zip stderr can't delete file at index '5': Invalid argument end-of-inline-data ================================================ FILE: external/libzip/regress/delete_last.test ================================================ # delete last entry in zip archive return 0 arguments testfile.zzip delete 0 file testfile.zzip testfile.zip {} ================================================ FILE: external/libzip/regress/delete_last_keep.test ================================================ # delete last entry in zip archive return 0 arguments testfile.zzip set_archive_flag create-or-keep-file-for-empty-archive 1 delete 0 file testfile.zzip testfile.zip testempty.zip ================================================ FILE: external/libzip/regress/delete_multiple_last.test ================================================ # delete multiple entries in zip archive, emptying it return 0 arguments testfile.zzip delete 0 delete 1 delete 2 delete 3 file testfile.zzip testcomment.zip {} ================================================ FILE: external/libzip/regress/delete_multiple_partial.test ================================================ # delete some entries in zip archive return 0 arguments testfile.zip delete 1 delete 3 file testfile.zip testcomment.zip testcomment13.zip ================================================ FILE: external/libzip/regress/delete_renamed_rename.test ================================================ # delete renamed entry in zip archive then rename file to same name # file date is now(), so use zipcmp return 0 arguments testfile.zip rename 0 something add test test delete 0 rename 1 testfile.txt file testfile.zip testfile.zip test2.zip ================================================ FILE: external/libzip/regress/encrypt.test ================================================ # test encryption support # TODO: only checks recognition of encrypted entries for now. return 0 arguments encrypt.zzip stat 0 stat 1 file encrypt.zzip encrypt.zip stdout name: 'encrypted' index: '0' size: '4' compressed size: '16' mtime: 'Mon Apr 24 2006 16:01:34' crc: '7e3265a8' compression method: '0' encryption method: '1' name: 'plain' index: '1' size: '4' compressed size: '4' mtime: 'Mon Apr 24 2006 16:01:42' crc: '7e3265a8' compression method: '0' encryption method: '0' end-of-inline-data ================================================ FILE: external/libzip/regress/encryption-nonrandom-aes128.test ================================================ features HAVE_CRYPTO precheck ./liboverride-test description encrypt file without entropy, to make results repeatable return 0 preload nonrandomopen.so arguments encrypt.zzip set_file_encryption 1 AES-128 no-entropy file encrypt.zzip encrypt-none.zip encrypt-aes128-noentropy.zip ================================================ FILE: external/libzip/regress/encryption-nonrandom-aes192.test ================================================ features HAVE_CRYPTO precheck ./liboverride-test description encrypt file without entropy, to make results repeatable return 0 preload nonrandomopen.so arguments encrypt.zzip set_file_encryption 1 AES-192 no-entropy file encrypt.zzip encrypt-none.zip encrypt-aes192-noentropy.zip ================================================ FILE: external/libzip/regress/encryption-nonrandom-aes256.test ================================================ features HAVE_CRYPTO precheck ./liboverride-test description encrypt file without entropy, to make results repeatable return 0 preload nonrandomopen.so arguments encrypt.zzip set_file_encryption 1 AES-256 no-entropy file encrypt.zzip encrypt-none.zip encrypt-aes256-noentropy.zip ================================================ FILE: external/libzip/regress/encryption-nonrandom-pkware-2.test ================================================ features HAVE_CRYPTO precheck ./liboverride-test description encrypt file by Traditional PKWare, set mtime (used in PKWare encryption) return 0 preload nonrandomopen.so arguments encrypt.zzip set_file_mtime 1 1407272201 set_file_encryption 1 PKWARE no-entropy file encrypt.zzip encrypt-none.zip encrypt-pkware-noentropy-2.zip ================================================ FILE: external/libzip/regress/encryption-nonrandom-pkware.test ================================================ features HAVE_CRYPTO precheck ./liboverride-test description encrypt file by Traditional PKWARE return 0 preload nonrandomopen.so arguments encrypt.zzip set_file_encryption 1 PKWARE no-entropy file encrypt.zzip encrypt-none.zip encrypt-pkware-noentropy.zip ================================================ FILE: external/libzip/regress/encryption-remove.test ================================================ # test AES decryption support, remove encryption from file that has it features HAVE_CRYPTO return 0 arguments encrypt.zzip set_password foofoofoo set_file_encryption 1 none "" file encrypt.zzip encrypt-aes128.zip encrypt-none.zip ================================================ FILE: external/libzip/regress/encryption-stat.test ================================================ features HAVE_CRYPTO description encrypt file, look at stat before commit return 0 arguments encrypt.zzip stat 1 set_file_encryption 1 AES-128 no-entropy stat 1 unchange_all file encrypt.zzip encrypt-none.zip stdout name: 'encrypted' index: '1' size: '10' compressed size: '10' mtime: 'Sat Jan 14 2017 21:27:26' crc: 'fb8c5e55' compression method: '0' encryption method: '0' name: 'encrypted' index: '1' size: '10' compressed size: '10' mtime: 'Sat Jan 14 2017 21:27:26' crc: 'fb8c5e55' compression method: '0' encryption method: '257' end-of-inline-data ================================================ FILE: external/libzip/regress/extra_add.test ================================================ # add extra field #args encrypt.zip set_extra 0 2345 65535 cl extrafieldcontent arguments encrypt.zip set_extra 0 2345 65535 cl extrafieldcontent get_extra_by_id 0 2345 0 c get_extra_by_id 0 2345 0 l return 0 file encrypt.zip encrypt.zip encrypt_plus_extra.zip stdout Extra field 0x0929: len 17, data 0x65787472616669656c64636f6e74656e74 Extra field 0x0929: len 17, data 0x65787472616669656c64636f6e74656e74 end-of-inline-data ================================================ FILE: external/libzip/regress/extra_add_multiple.test ================================================ # add extra fields arguments testfile.zip set_extra 0 2345 65535 cl extra1 set_extra 0 2345 65535 cl extra2 set_extra 0 2345 0 c extra1c set_extra 0 2345 1 l extra2l get_extra_by_id 0 2345 0 c get_extra_by_id 0 2345 1 c get_extra_by_id 0 2345 0 l get_extra_by_id 0 2345 1 l return 0 file testfile.zip testfile.zip testfile-plus-extra.zip stdout Extra field 0x0929: len 7, data 0x65787472613163 Extra field 0x0929: len 6, data 0x657874726132 Extra field 0x0929: len 6, data 0x657874726131 Extra field 0x0929: len 7, data 0x6578747261326c end-of-inline-data ================================================ FILE: external/libzip/regress/extra_count.test ================================================ # count extra fields for index arguments encrypt.zip count_extra 0 l count_extra 0 c count_extra 0 lc count_extra 1 l count_extra 1 c count_extra 1 lc return 0 file encrypt.zip encrypt.zip stdout Extra field count: 2 Extra field count: 2 Extra field count: 4 Extra field count: 2 Extra field count: 2 Extra field count: 4 end-of-inline-data ================================================ FILE: external/libzip/regress/extra_count_by_id.test ================================================ # count extra fields for index arguments encrypt.zip count_extra_by_id 0 0 l count_extra_by_id 0 1 l count_extra_by_id 0 21589 l count_extra_by_id 0 30805 l count_extra_by_id 0 21844 l count_extra_by_id 0 12345 l count_extra_by_id 0 0 c count_extra_by_id 0 1 c count_extra_by_id 0 21589 c count_extra_by_id 0 30805 c count_extra_by_id 0 21844 c count_extra_by_id 0 12345 c count_extra_by_id 0 0 cl count_extra_by_id 0 1 cl count_extra_by_id 0 21589 cl count_extra_by_id 0 30805 cl count_extra_by_id 0 21844 cl count_extra_by_id 0 12345 cl return 0 file encrypt.zip encrypt.zip stdout Extra field count: 0 Extra field count: 0 Extra field count: 1 Extra field count: 1 Extra field count: 0 Extra field count: 0 Extra field count: 0 Extra field count: 0 Extra field count: 1 Extra field count: 1 Extra field count: 0 Extra field count: 0 Extra field count: 0 Extra field count: 0 Extra field count: 2 Extra field count: 2 Extra field count: 0 Extra field count: 0 end-of-inline-data ================================================ FILE: external/libzip/regress/extra_count_ignore_zip64.test ================================================ # count extra fields for index arguments bigzero.zip count_extra 0 l count_extra 0 c count_extra 0 lc return 0 file bigzero.zip bigzero.zip stdout Extra field count: 0 Extra field count: 0 Extra field count: 0 end-of-inline-data ================================================ FILE: external/libzip/regress/extra_delete.test ================================================ # delete extra field by index arguments encrypt.zip get_extra 0 0 c get_extra 0 1 c get_extra 0 2 c get_extra 0 0 l get_extra 0 1 l get_extra 0 2 l delete_extra 0 2 c delete_extra 0 0 l get_extra 0 0 c get_extra 0 1 c get_extra 0 0 l get_extra 0 1 l file encrypt.zip encrypt_plus_extra.zip encrypt.zip return 0 stdout Extra field 0x5455: len 5, data 0x033dda4c44 Extra field 0x7855: len 0 Extra field 0x0929: len 17, data 0x65787472616669656c64636f6e74656e74 Extra field 0x0929: len 17, data 0x65787472616669656c64636f6e74656e74 Extra field 0x5455: len 9, data 0x033dda4c444dda4c44 Extra field 0x7855: len 4, data 0x64001400 Extra field 0x5455: len 5, data 0x033dda4c44 Extra field 0x7855: len 0 Extra field 0x5455: len 9, data 0x033dda4c444dda4c44 Extra field 0x7855: len 4, data 0x64001400 end-of-inline-data ================================================ FILE: external/libzip/regress/extra_delete_by_id.test ================================================ # delete extra field by id and index #args encrypt.zip set_extra 0 2345 65535 cl extrafieldcontent arguments encrypt.zip delete_extra_by_id 0 2345 0 c delete_extra_by_id 0 2345 0 l get_extra_by_id 0 2345 0 c return 1 file encrypt.zip encrypt_plus_extra.zip encrypt.zip stderr can't get extra field data for file at index 0, extra field id 2345, ef index 0, flags 512: No such file end-of-inline-data ================================================ FILE: external/libzip/regress/extra_field_align.test ================================================ # try opening simulated Android APK zipaligned files, and similar inconsistent files program tryopen file extra_field_align_1-0.zzip extra_field_align_1-0.zip file extra_field_align_1-ff.zzip extra_field_align_1-ff.zip file extra_field_align_2-0.zzip extra_field_align_2-0.zip file extra_field_align_2-ff.zzip extra_field_align_2-ff.zip file extra_field_align_3-0.zzip extra_field_align_3-0.zip file extra_field_align_3-ff.zzip extra_field_align_3-ff.zip file extra_field_align_4-ff.zzip extra_field_align_4-ff.zip file extra_field_align_1-ef_00.zzip extra_field_align_1-ef_00.zip file extra_field_align_1-ef_ff.zzip extra_field_align_1-ef_ff.zip file extra_field_align_2-ef_00.zzip extra_field_align_2-ef_00.zip file extra_field_align_2-ef_ff.zzip extra_field_align_2-ef_ff.zip file extra_field_align_3-ef_00.zzip extra_field_align_3-ef_00.zip file extra_field_align_3-ef_ff.zzip extra_field_align_3-ef_ff.zip arguments -s -c extra_field_align_1-0.zzip extra_field_align_1-ff.zzip extra_field_align_2-0.zzip extra_field_align_2-ff.zzip extra_field_align_3-0.zzip extra_field_align_3-ff.zzip extra_field_align_4-ff.zzip extra_field_align_1-ef_00.zzip extra_field_align_1-ef_ff.zzip extra_field_align_2-ef_00.zzip extra_field_align_2-ef_ff.zzip extra_field_align_3-ef_00.zzip extra_field_align_3-ef_ff.zzip return 1 stdout opening 'extra_field_align_1-0.zzip' succeeded, 1 entries opening 'extra_field_align_1-ff.zzip' returned error Zip archive inconsistent: entry 0: garbage at end of extra fields opening 'extra_field_align_2-0.zzip' succeeded, 1 entries opening 'extra_field_align_2-ff.zzip' returned error Zip archive inconsistent: entry 0: garbage at end of extra fields opening 'extra_field_align_3-0.zzip' succeeded, 1 entries opening 'extra_field_align_3-ff.zzip' returned error Zip archive inconsistent: entry 0: garbage at end of extra fields opening 'extra_field_align_4-ff.zzip' succeeded, 1 entries opening 'extra_field_align_1-ef_00.zzip' succeeded, 1 entries opening 'extra_field_align_1-ef_ff.zzip' returned error Zip archive inconsistent: entry 0: garbage at end of extra fields opening 'extra_field_align_2-ef_00.zzip' succeeded, 1 entries opening 'extra_field_align_2-ef_ff.zzip' returned error Zip archive inconsistent: entry 0: garbage at end of extra fields opening 'extra_field_align_3-ef_00.zzip' succeeded, 1 entries opening 'extra_field_align_3-ef_ff.zzip' returned error Zip archive inconsistent: entry 0: garbage at end of extra fields end-of-inline-data stderr 6 errors end-of-inline-data ================================================ FILE: external/libzip/regress/extra_get.test ================================================ # get extra fields for index arguments encrypt.zip get_extra 0 0 l get_extra 0 0 c get_extra 0 1 l get_extra 0 1 c get_extra 0 2 l return 1 file encrypt.zip encrypt.zip stdout Extra field 0x5455: len 9, data 0x033dda4c444dda4c44 Extra field 0x5455: len 5, data 0x033dda4c44 Extra field 0x7855: len 4, data 0x64001400 Extra field 0x7855: len 0 end-of-inline-data stderr can't get extra field data for file at index 0, extra field 2, flags 256: No such file end-of-inline-data ================================================ FILE: external/libzip/regress/extra_get_by_id.test ================================================ # get extra_by_id fields for index arguments encrypt.zip get_extra_by_id 0 21589 0 l get_extra_by_id 0 30805 0 l get_extra_by_id 0 21589 0 c get_extra_by_id 0 30805 0 c get_extra_by_id 0 21544 0 c return 1 file encrypt.zip encrypt.zip stdout Extra field 0x5455: len 9, data 0x033dda4c444dda4c44 Extra field 0x7855: len 4, data 0x64001400 Extra field 0x5455: len 5, data 0x033dda4c44 Extra field 0x7855: len 0 end-of-inline-data stderr can't get extra field data for file at index 0, extra field id 21544, ef index 0, flags 512: No such file end-of-inline-data ================================================ FILE: external/libzip/regress/extra_set.test ================================================ # set extra field arguments -- encrypt get_extra 0 0 c get_extra 0 1 c get_extra 0 0 l get_extra 0 1 l set_extra 0 2345 -1 l extrafieldcontent set_extra 0 2345 -1 c extrafieldcontent get_extra 0 0 c get_extra 0 1 c get_extra 0 2 c get_extra 0 0 l get_extra 0 1 l get_extra 0 2 l file encrypt encrypt.zip encrypt_plus_extra.zip return 0 stdout Extra field 0x5455: len 5, data 0x033dda4c44 Extra field 0x7855: len 0 Extra field 0x5455: len 9, data 0x033dda4c444dda4c44 Extra field 0x7855: len 4, data 0x64001400 Extra field 0x5455: len 5, data 0x033dda4c44 Extra field 0x7855: len 0 Extra field 0x0929: len 17, data 0x65787472616669656c64636f6e74656e74 Extra field 0x5455: len 9, data 0x033dda4c444dda4c44 Extra field 0x7855: len 4, data 0x64001400 Extra field 0x0929: len 17, data 0x65787472616669656c64636f6e74656e74 end-of-inline-data ================================================ FILE: external/libzip/regress/extra_set_modify_c.test ================================================ # change existing central extra field arguments encrypt.zip get_extra 0 0 c get_extra 0 1 c get_extra 0 2 c get_extra 0 0 l get_extra 0 1 l get_extra 0 2 l set_extra 0 2345 0 c Extrafieldcontent get_extra 0 0 c get_extra 0 1 c get_extra 0 2 c get_extra 0 0 l get_extra 0 1 l get_extra 0 2 l file encrypt.zip encrypt_plus_extra.zip encrypt_plus_extra_modified_c.zip return 0 stdout Extra field 0x5455: len 5, data 0x033dda4c44 Extra field 0x7855: len 0 Extra field 0x0929: len 17, data 0x65787472616669656c64636f6e74656e74 Extra field 0x0929: len 17, data 0x65787472616669656c64636f6e74656e74 Extra field 0x5455: len 9, data 0x033dda4c444dda4c44 Extra field 0x7855: len 4, data 0x64001400 Extra field 0x5455: len 5, data 0x033dda4c44 Extra field 0x7855: len 0 Extra field 0x0929: len 17, data 0x45787472616669656c64636f6e74656e74 Extra field 0x0929: len 17, data 0x65787472616669656c64636f6e74656e74 Extra field 0x5455: len 9, data 0x033dda4c444dda4c44 Extra field 0x7855: len 4, data 0x64001400 end-of-inline-data ================================================ FILE: external/libzip/regress/extra_set_modify_l.test ================================================ # change existing local extra field arguments encrypt.zip get_extra 0 0 c get_extra 0 1 c get_extra 0 2 c get_extra 0 0 l get_extra 0 1 l get_extra 0 2 l set_extra 0 2345 0 l Extrafieldcontent get_extra 0 0 c get_extra 0 1 c get_extra 0 2 c get_extra 0 0 l get_extra 0 1 l get_extra 0 2 l file encrypt.zip encrypt_plus_extra.zip encrypt_plus_extra_modified_l.zip return 0 stdout Extra field 0x5455: len 5, data 0x033dda4c44 Extra field 0x7855: len 0 Extra field 0x0929: len 17, data 0x65787472616669656c64636f6e74656e74 Extra field 0x0929: len 17, data 0x65787472616669656c64636f6e74656e74 Extra field 0x5455: len 9, data 0x033dda4c444dda4c44 Extra field 0x7855: len 4, data 0x64001400 Extra field 0x5455: len 5, data 0x033dda4c44 Extra field 0x7855: len 0 Extra field 0x0929: len 17, data 0x65787472616669656c64636f6e74656e74 Extra field 0x0929: len 17, data 0x45787472616669656c64636f6e74656e74 Extra field 0x5455: len 9, data 0x033dda4c444dda4c44 Extra field 0x7855: len 4, data 0x64001400 end-of-inline-data ================================================ FILE: external/libzip/regress/fdopen_ok.test ================================================ # zip_fdopen: stdin opens fine #program ../src/ziptool arguments /dev/stdin stat 0 return 0 file test.zip test.zip stdin test.zip stdout name: 'test' index: '0' size: '5' compressed size: '5' mtime: 'Mon Oct 06 2003 15:46:42' crc: '3bb935c6' compression method: '0' encryption method: '0' end-of-inline-data ================================================ FILE: external/libzip/regress/file_comment_encmismatch.test ================================================ # set file comment to UTF-8 for CP437 encoded filename (adds InfoZIP extra field) return 0 arguments -i testfile.zip dummy stdin set_file_comment 0 ÄÖÜßäöü end-of-inline-data file testfile.zip test-cp437.zip test-cp437-comment-utf-8.zip ================================================ FILE: external/libzip/regress/fopen_multiple.test ================================================ # read contents from multiply opened unchanged file return 0 arguments test_open_multiple.zip fopen stuff fopen stuff fread 0 2 fread 1 4 fread 0 3 fread 1 3 fread 0 3 fread 1 1 unchange_all file test_open_multiple.zip test_open_multiple.zip stdout opened 'stuff' as file 0 opened 'stuff' as file 1 ababcdcdeefgfghh end-of-inline-data ================================================ FILE: external/libzip/regress/fopen_multiple_reopen.test ================================================ # read contents from multiply reopened changed file return 0 arguments test_open_multiple.zip replace_file_contents 0 12345678 fopen stuff fopen stuff fread 0 2 fread 1 4 fread 0 3 fread 1 3 fread 0 3 fread 1 1 unchange_all file test_open_multiple.zip test_open_multiple.zip stdout opened 'stuff' as file 0 opened 'stuff' as file 1 1212343455676788 end-of-inline-data ================================================ FILE: external/libzip/regress/fopen_unchanged.c ================================================ /* fopen_unchanged.c -- test case for adding file and reading from unchanged Copyright (C) 2012-2023 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include "zip.h" const char *teststr = "This is a test.\n"; const char *file = "teststring.txt"; int main(int argc, char *argv[]) { const char *archive; zip_t *za; zip_source_t *zs; int err; if (argc != 2) { fprintf(stderr, "usage: %s archive\n", argv[0]); return 1; } archive = argv[1]; if ((za = zip_open(archive, ZIP_CREATE, &err)) == NULL) { zip_error_t error; zip_error_init_with_code(&error, err); fprintf(stderr, "can't open zip archive '%s': %s\n", archive, zip_error_strerror(&error)); zip_error_fini(&error); return 1; } if ((zs = zip_source_buffer(za, teststr, strlen(teststr), 0)) == NULL) { fprintf(stderr, "can't create zip_source from buffer: %s\n", zip_strerror(za)); exit(1); } if (zip_file_add(za, file, zs, 0) == -1) { fprintf(stderr, "can't add file '%s': %s\n", file, zip_strerror(za)); (void)zip_source_free(zs); (void)zip_close(za); return 1; } if (zip_fopen(za, file, ZIP_FL_UNCHANGED) == NULL) { fprintf(stderr, "can't zip_fopen file '%s': %s\n", file, zip_strerror(za)); (void)zip_discard(za); return 1; } if (zip_close(za) == -1) { fprintf(stderr, "can't close zip archive '%s': %s\n", archive, zip_strerror(za)); return 1; } return 0; } ================================================ FILE: external/libzip/regress/fopen_unchanged.test ================================================ # add buffer contents as file to zip, then read unchanged from it program fopen_unchanged return 1 arguments testbuffer.zip stderr can't zip_fopen file 'teststring.txt': No such file end-of-inline-data ================================================ FILE: external/libzip/regress/fread.c ================================================ /* fread.c -- test cases for reading from zip archives Copyright (C) 2004-2023 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #include #include #ifndef HAVE_GETOPT #include "getopt.h" #endif #include "zip.h" enum when { WHEN_NEVER, WHEN_OPEN, WHEN_READ, WHEN_CLOSE }; const char *when_name[] = {"no", "zip_fopen", "zip_fread", "zip_fclose"}; static int do_read(zip_t *z, const char *name, zip_flags_t flags, enum when when_ex, int ze_ex, int se_ex); int verbose; const char *progname; #define USAGE "usage: %s [-v] archive\n" int main(int argc, char *argv[]) { int fail, ze; int c; zip_t *z; zip_source_t *zs; char *archive; zip_int64_t idx; verbose = 0; fail = 0; progname = argv[0]; while ((c = getopt(argc, argv, "v")) != -1) { switch (c) { case 'v': verbose = 1; break; default: fprintf(stderr, USAGE, progname); return 1; } } if (argc - optind != 1) { fprintf(stderr, USAGE, progname); return 1; } archive = argv[optind]; if ((z = zip_open(archive, 0, &ze)) == NULL) { zip_error_t error; zip_error_init_with_code(&error, ze); fprintf(stderr, "%s: can't open zip archive '%s': %s\n", progname, archive, zip_error_strerror(&error)); zip_error_fini(&error); return 1; } fail += do_read(z, "storedok", 0, WHEN_NEVER, 0, 0); fail += do_read(z, "deflateok", 0, WHEN_NEVER, 0, 0); fail += do_read(z, "storedcrcerror", 0, WHEN_READ, ZIP_ER_CRC, 0); fail += do_read(z, "deflatecrcerror", 0, WHEN_READ, ZIP_ER_CRC, 0); fail += do_read(z, "deflatezliberror", 0, WHEN_READ, ZIP_ER_ZLIB, -3); #ifndef __clang_analyzer__ /* This test intentionally violates nullability. */ fail += do_read(z, NULL, 0, WHEN_OPEN, ZIP_ER_INVAL, 0); #endif fail += do_read(z, "nosuchfile", 0, WHEN_OPEN, ZIP_ER_NOENT, 0); fail += do_read(z, "deflatezliberror", ZIP_FL_COMPRESSED, WHEN_NEVER, 0, 0); fail += do_read(z, "deflatecrcerror", ZIP_FL_COMPRESSED, WHEN_NEVER, 0, 0); fail += do_read(z, "storedcrcerror", ZIP_FL_COMPRESSED, WHEN_READ, ZIP_ER_CRC, 0); fail += do_read(z, "storedok", ZIP_FL_COMPRESSED, WHEN_NEVER, 0, 0); fail += do_read(z, "cryptok", 0, WHEN_OPEN, ZIP_ER_NOPASSWD, 0); zip_set_default_password(z, "crypt"); fail += do_read(z, "cryptok", 0, WHEN_NEVER, 0, 0); zip_set_default_password(z, "wrong"); fail += do_read(z, "cryptok", 0, WHEN_OPEN, ZIP_ER_WRONGPASSWD, 0); zip_set_default_password(z, NULL); zs = zip_source_buffer(z, "asdf", 4, 0); if ((idx = zip_name_locate(z, "storedok", 0)) < 0) { fprintf(stderr, "%s: can't locate 'storedok' in zip archive '%s': %s\n", progname, archive, zip_strerror(z)); fail++; } else { if (zip_file_replace(z, (zip_uint64_t)idx, zs, 0) < 0) { fprintf(stderr, "%s: can't replace 'storedok' in zip archive '%s': %s\n", progname, archive, zip_strerror(z)); fail++; } else { fail += do_read(z, "storedok", 0, WHEN_NEVER, 0, 0); fail += do_read(z, "storedok", ZIP_FL_UNCHANGED, WHEN_NEVER, 0, 0); } } if ((idx = zip_name_locate(z, "storedok", 0)) < 0) { fprintf(stderr, "%s: can't locate 'storedok' in zip archive '%s': %s\n", progname, archive, zip_strerror(z)); fail++; } else { if (zip_delete(z, (zip_uint64_t)idx) < 0) { fprintf(stderr, "%s: can't replace 'storedok' in zip archive '%s': %s\n", progname, archive, zip_strerror(z)); fail++; } else { fail += do_read(z, "storedok", 0, WHEN_OPEN, ZIP_ER_NOENT, 0); fail += do_read(z, "storedok", ZIP_FL_UNCHANGED, WHEN_NEVER, 0, 0); } } zs = zip_source_buffer(z, "asdf", 4, 0); if (zip_file_add(z, "new_file", zs, 0) < 0) { fprintf(stderr, "%s: can't add file to zip archive '%s': %s\n", progname, archive, zip_strerror(z)); fail++; } else { fail += do_read(z, "new_file", 0, WHEN_NEVER, 0, 0); } zip_unchange_all(z); if (zip_close(z) == -1) { fprintf(stderr, "%s: can't close zip archive '%s': %s\n", progname, archive, zip_strerror(z)); return 1; } exit(fail ? 1 : 0); } static int do_read(zip_t *z, const char *name, zip_flags_t flags, enum when when_ex, int ze_ex, int se_ex) { zip_file_t *zf; enum when when_got; zip_error_t error_got, error_ex; zip_error_t *zf_error; int err; char b[8192]; zip_int64_t n; when_got = WHEN_NEVER; zip_error_init(&error_got); zip_error_init(&error_ex); zip_error_set(&error_ex, ze_ex, se_ex); if ((zf = zip_fopen(z, name, flags)) == NULL) { when_got = WHEN_OPEN; zf_error = zip_get_error(z); zip_error_set(&error_got, zip_error_code_zip(zf_error), zip_error_code_system(zf_error)); } else { while ((n = zip_fread(zf, b, sizeof(b))) > 0) ; if (n < 0) { when_got = WHEN_READ; zf_error = zip_file_get_error(zf); zip_error_set(&error_got, zip_error_code_zip(zf_error), zip_error_code_system(zf_error)); } err = zip_fclose(zf); if (when_got == WHEN_NEVER && err != 0) { when_got = WHEN_CLOSE; zip_error_init_with_code(&error_got, err); } } if (when_got != when_ex || zip_error_code_zip(&error_got) != zip_error_code_zip(&error_ex) || zip_error_code_system(&error_got) != zip_error_code_system(&error_ex)) { printf("%s: %s: got %s error (%s), expected %s error (%s)\n", progname, name, when_name[when_got], zip_error_strerror(&error_got), when_name[when_ex], zip_error_strerror(&error_ex)); zip_error_fini(&error_got); zip_error_fini(&error_ex); return 1; } else if (verbose) printf("%s: %s: passed\n", progname, name); return 0; } ================================================ FILE: external/libzip/regress/fread.test ================================================ # various tests for zip_fread program fread arguments broken.zip return 0 file broken.zip broken.zip ================================================ FILE: external/libzip/regress/fseek.c ================================================ /* fseek.c -- test tool for seeking in zip archives Copyright (C) 2016-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include "zip.h" const char *progname; #define USAGE "usage: %s archive index offset\n" int main(int argc, char *argv[]) { int ze; zip_t *z; zip_file_t *zf; char *archive; zip_int64_t offset, n; zip_uint64_t index; char b[1024]; progname = argv[0]; if (argc != 4) { fprintf(stderr, USAGE, progname); return 1; } archive = argv[1]; index = strtoull(argv[2], NULL, 10); offset = (zip_int64_t)strtoull(argv[3], NULL, 10); if ((z = zip_open(archive, 0, &ze)) == NULL) { zip_error_t error; zip_error_init_with_code(&error, ze); fprintf(stderr, "%s: can't open zip archive '%s': %s\n", progname, archive, zip_error_strerror(&error)); zip_error_fini(&error); return 1; } if ((zf = zip_fopen_index(z, index, 0)) == NULL) { fprintf(stderr, "%s: can't open file in archive '%s': %s\n", progname, archive, zip_error_strerror(zip_file_get_error(zf))); zip_close(z); return 1; } if (zip_fseek(zf, offset, SEEK_SET) < 0) { fprintf(stderr, "%s: zip_fseek failed: %s\n", progname, zip_error_strerror(zip_file_get_error(zf))); zip_fclose(zf); zip_close(z); return 1; } while ((n = zip_fread(zf, b, sizeof(b))) > 0) { printf("%.*s", (int)n, b); } if (n < 0) { fprintf(stderr, "%s: zip_fread failed: %s\n", progname, zip_error_strerror(zip_file_get_error(zf))); zip_fclose(zf); zip_close(z); return 1; } if (zip_fclose(zf) == -1) { fprintf(stderr, "%s: can't close zip archive entry %" PRIu64 " in '%s': %s\n", progname, index, archive, zip_strerror(z)); return 1; } if (zip_close(z) == -1) { fprintf(stderr, "%s: can't close zip archive '%s': %s\n", progname, archive, zip_strerror(z)); return 1; } return 0; } ================================================ FILE: external/libzip/regress/fseek_deflated.test ================================================ # unsuccessful fseek test because data is compressed program fseek arguments test.zip 0 2 return 1 file test.zip testdeflated.zip stderr zip_fseek failed: Operation not supported end-of-inline-data ================================================ FILE: external/libzip/regress/fseek_fail.test ================================================ # successful fseek test program fseek arguments test.zip 0 8 return 1 file test.zip test.zip stderr zip_fseek failed: Invalid argument end-of-inline-data ================================================ FILE: external/libzip/regress/fseek_ok.test ================================================ # successful fseek test program fseek arguments test.zip 0 2 return 0 file test.zip test.zip stdout st end-of-inline-data ================================================ FILE: external/libzip/regress/get_comment.test ================================================ # show comments of a zip archive return 0 arguments testcomment.zip get_archive_comment get_file_comment 0 get_file_comment 1 get_file_comment 2 get_file_comment 3 file testcomment.zip testcomment.zip stdout Archive comment: This is the archive comment for the file. Long. Longer. No comment for 'file1' File comment for 'file2': First one had no comment. File comment for 'file3': Third one. File comment for 'file4': Last. end-of-inline-data ================================================ FILE: external/libzip/regress/get_comment_long.test ================================================ # show long archive comment of a zip archive return 0 arguments testfile.zip get_archive_comment file testfile.zip testfile-long-comment.zip stdout Archive comment: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX end-of-inline-data ================================================ FILE: external/libzip/regress/hmac-error.test ================================================ description test file that has an HMAC error return 1 arguments hmac-error.zip set_password 1234 cat 0 file hmac-error.zip hmac-error.zip stdout The quick brown fox jumps over t quazy dog end-of-inline-data stderr can't read file at index '0': CRC error end-of-inline-data ================================================ FILE: external/libzip/regress/hole.c ================================================ /* hole.c -- convert huge files with mostly NULs to/from source_hole Copyright (C) 2014-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #include #include #ifndef HAVE_GETOPT #include "getopt.h" #endif #include "zip.h" /* public API */ zip_source_t *source_hole_create(const char *, int flags, zip_error_t *); const char *progname; static int copy_source(zip_source_t *from, zip_source_t *to) { zip_uint8_t buf[8192]; zip_int64_t n; if (zip_source_open(from) < 0) { fprintf(stderr, "%s: can't open source for reading: %s\n", progname, zip_error_strerror(zip_source_error(from))); return -1; } if (zip_source_begin_write(to) < 0) { fprintf(stderr, "%s: can't open source for writing: %s\n", progname, zip_error_strerror(zip_source_error(to))); zip_source_close(from); return -1; } while ((n = zip_source_read(from, buf, sizeof(buf))) > 0) { if (zip_source_write(to, buf, (zip_uint64_t)n) != n) { fprintf(stderr, "%s: can't write to source: %s\n", progname, zip_error_strerror(zip_source_error(to))); zip_source_close(from); zip_source_rollback_write(to); return -1; } } if (n < 0) { fprintf(stderr, "%s: can't read from source: %s\n", progname, zip_error_strerror(zip_source_error(from))); zip_source_close(from); zip_source_rollback_write(to); return -1; } zip_source_close(from); if (zip_source_commit_write(to) < 0) { fprintf(stderr, "%s: can't commit source: %s\n", progname, zip_error_strerror(zip_source_error(to))); zip_source_rollback_write(to); return -1; } return 0; } static zip_source_t * open_compressed(const char *fname, int flags) { zip_error_t error; zip_source_t *src; zip_error_init(&error); if ((src = source_hole_create(fname, flags, &error)) == NULL) { fprintf(stderr, "%s: can't open compressed file %s: %s\n", progname, fname, zip_error_strerror(&error)); zip_error_fini(&error); exit(1); } return src; } static zip_source_t * open_file(const char *fname) { zip_error_t error; zip_source_t *src; zip_error_init(&error); if ((src = zip_source_file_create(fname, 0, 0, &error)) == NULL) { fprintf(stderr, "%s: can't open file %s: %s\n", progname, fname, zip_error_strerror(&error)); zip_error_fini(&error); exit(1); } return src; } static void usage(void) { fprintf(stderr, "usage: %s [-du] in out\n", progname); fprintf(stderr, "\nOptions:\n -d decompress in\n -u update in\n"); exit(1); } int main(int argc, char **argv) { zip_source_t *from; zip_source_t *to; int c, err; int compress = 1; int decompress = 0; progname = argv[0]; while ((c = getopt(argc, argv, "du")) != -1) { switch (c) { case 'd': compress = 0; decompress = 1; break; case 'u': compress = 1; decompress = 1; break; default: usage(); break; } } if (optind + 2 != argc) { usage(); } if (decompress) { from = open_compressed(argv[optind], 0); } else { from = open_file(argv[optind]); } if (compress) { to = open_compressed(argv[optind + 1], ZIP_CREATE); } else { to = open_file(argv[optind + 1]); } err = copy_source(from, to); zip_source_free(from); zip_source_free(to); exit(err < 0 ? 1 : 0); } ================================================ FILE: external/libzip/regress/junk_at_end.test ================================================ # test archive with junk at end of file arguments -l 412 junk-at-end.zzip get_num_entries 0 return 0 file junk-at-end.zzip junk-at-end.zip stdout 3 entries in archive end-of-inline-data ================================================ FILE: external/libzip/regress/junk_at_start.test ================================================ # test archive with junk at start of file arguments -o 4 junk-at-start.zzip get_num_entries 0 return 0 file junk-at-start.zzip junk-at-start.zip stdout 3 entries in archive end-of-inline-data ================================================ FILE: external/libzip/regress/liboverride-test.c ================================================ /* liboverride.c -- override function called by zip_open() Copyright (C) 2017-2022 Dieter Baron and Thomas Klausner This file is part of ckmame, a program to check rom sets for MAME. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #ifdef _WIN32 int main(int argc, const char *argv[]) { /* Symbol override is not supported on Windows. */ if (argc > 1 && strcmp(argv[1], "-v") == 0) { printf("not supported on Windows\n"); } exit(1); } #else #include #include #include "zip.h" /* Some systems bind functions called and defined within a shared library, so the override doesn't work. This program calls zip_open and checks whether the override worked. */ int main(int argc, const char *argv[]) { int verbose = 0; int error_code; if (argc > 1 && strcmp(argv[1], "-v") == 0) { verbose = 1; } if (getenv("LIBOVERRIDE_SET") == NULL) { char *cwd = getcwd(NULL, 0); size_t so_size = strlen(cwd) + 64; char *so = (char *)malloc(so_size); if (so == NULL) { if (verbose) { printf("malloc failed\n"); } exit(2); } snprintf(so, so_size, "%s/libliboverride.so", cwd); setenv("LIBOVERRIDE_SET", "1", 1); setenv("LD_PRELOAD", so, 1); execv(argv[0], (void *)argv); if (verbose) { printf("exec failed: %s\n", strerror(errno)); } exit(2); } if (zip_open("nosuchfile", 0, &error_code) != NULL) { /* We expect failure. */ if (verbose) { printf("open succeeded\n"); } exit(1); } if (error_code != 32000) { /* Override didn't take, we didn't get its magic error code. */ if (verbose) { printf("got unexpected error %d\n", error_code); } exit(1); } if (verbose) { printf("success\n"); } exit(0); } #endif /* not Windows */ ================================================ FILE: external/libzip/regress/liboverride.c ================================================ /* liboverride.c -- override function called by zip_open() Copyright (C) 2017-2021 Dieter Baron and Thomas Klausner This file is part of ckmame, a program to check rom sets for MAME. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "zipint.h" /* Some systems bind functions called and defined within a shared library, so the override doesn't work. This overrides a function called by zip_open to return an invalid error code so we can check whether the override works. */ zip_source_t * zip_source_file_create(const char *fname, zip_uint64_t start, zip_int64_t length, zip_error_t *error) { if (error != NULL) { error->zip_err = 32000; } return NULL; } ================================================ FILE: external/libzip/regress/malloc.c ================================================ /* malloc.c -- override *alloc() to allow testing special cases Copyright (C) 2015-2021 Dieter Baron and Thomas Klausner This file is part of ckmame, a program to check rom sets for MAME. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include /* #include */ #include #define __USE_GNU #include #undef __USE_GNU #include "config.h" #if !defined(RTLD_NEXT) #define RTLD_NEXT RTLD_DEFAULT #endif #if defined(HAVE___PROGNAME) extern char *__progname; #endif #if defined(HAVE_GETPROGNAME) /* all fine */ #else const char * getprogname(void) { #if defined(HAVE___PROGNAME) return __progname; #else return NULL; #endif } #endif static int inited = 0; static size_t count = 0; static size_t max_count = 0; static size_t min_size = 0; static void *(*real_malloc)(size_t size) = NULL; static void *(*real_calloc)(size_t number, size_t size) = NULL; static void *(*real_realloc)(void *ptr, size_t size) = NULL; static const char *myname = NULL; /* TODO: add sentinel -- check if particular size is malloced before doing other stuff */ /* TODO: catch free for sentinel too */ /* TODO: optionally, catch malloc of particular size */ static void init(void) { char *foo; myname = getprogname(); if (!myname) myname = "(unknown)"; if ((foo = getenv("MALLOC_MAX_COUNT")) != NULL) max_count = strtoul(foo, NULL, 0); if ((foo = getenv("MALLOC_MIN_SIZE")) != NULL) min_size = strtoul(foo, NULL, 0); real_calloc = dlsym(RTLD_NEXT, "calloc"); if (!real_calloc) abort(); real_malloc = dlsym(RTLD_NEXT, "malloc"); if (!real_malloc) abort(); real_realloc = dlsym(RTLD_NEXT, "realloc"); if (!real_realloc) abort(); inited = 1; } void * calloc(size_t number, size_t size) { void *ret; if (!inited) { init(); } if (number >= min_size / size && count >= max_count) { errno = ENOMEM; return NULL; } ret = real_calloc(number, size); if (size >= min_size) { count++; } return ret; } void * malloc(size_t size) { void *ret; if (!inited) { init(); } if (size >= min_size && count >= max_count) { errno = ENOMEM; return NULL; } ret = real_malloc(size); if (size >= min_size) { count++; } return ret; } void * realloc(void *ptr, size_t size) { void *ret; if (!inited) { init(); } if (size >= min_size && count >= max_count) { errno = ENOMEM; return NULL; } ret = real_realloc(ptr, size); if (size >= min_size) { count++; } return ret; } ================================================ FILE: external/libzip/regress/mtime-dstpoint.test ================================================ description change method from stored to deflated, which will change the timestamp because it is at a DST point and not valid in that time zone environment-set TZ America/New_York # setting it to a European timezone, where there is no DST change at this point, works #environment-set TZ Europe/Zurich return 0 arguments test.zzip set_file_compression 0 deflate 0 file test.zzip mtime-dstpoint.zip mtime-dstpoint-deflated.zip ================================================ FILE: external/libzip/regress/mtime-post-dstpoint.test ================================================ description change method from stored to deflated, for a file one hour after DST change environment-set TZ America/New_York return 0 arguments test.zzip set_file_compression 0 deflate 0 file test.zzip mtime-post-dstpoint.zip mtime-post-dstpoint-deflated.zip ================================================ FILE: external/libzip/regress/mtime-pre-dstpoint.test ================================================ description change method from stored to deflated, for a file one hour before DST change environment-set TZ America/New_York return 0 arguments test.zzip set_file_compression 0 deflate 0 file test.zzip mtime-pre-dstpoint.zip mtime-pre-dstpoint-deflated.zip ================================================ FILE: external/libzip/regress/name_locate-cp437.test ================================================ description tests for various encoding flags for zip_name_locate arguments -x test.zip name_locate "9192939495969798999A9B9C9D9E9FA0" 0 name_locate "9192939495969798999A9B9C9D9E9FA0" 4 name_locate "9192939495969798999A9B9C9D9E9FA0" 8 name_locate "9192939495969798999A9B9C9D9E9FA0" r name_locate "9192939495969798999A9B9C9D9E9FA0" s return 0 file test.zip test-cp437.zip stdout name '9192939495969798999A9B9C9D9E9FA0' using flags '0' found at index 9 name '9192939495969798999A9B9C9D9E9FA0' using flags '4' found at index 9 name '9192939495969798999A9B9C9D9E9FA0' using flags 'r' found at index 9 name '9192939495969798999A9B9C9D9E9FA0' using flags 's' found at index 9 end-of-inline-data stderr can't find entry with name '9192939495969798999A9B9C9D9E9FA0' using flags '8' end-of-inline-data ================================================ FILE: external/libzip/regress/name_locate-utf8.test ================================================ description tests for various encoding flags for zip_name_locate arguments -i test.zip dummy stdin name_locate æÆôöòûùÿÖÜ¢£¥₧ƒá 0 name_locate æÆôöòûùÿÖÜ¢£¥₧ƒá 4 name_locate æÆôöòûùÿÖÜ¢£¥₧ƒá 8 name_locate æÆôöòûùÿÖÜ¢£¥₧ƒá r name_locate æÆôöòûùÿÖÜ¢£¥₧ƒá s end-of-inline-data return 0 file test.zip test-cp437.zip stdout name 'æÆôöòûùÿÖÜ¢£¥₧ƒá' using flags '0' found at index 9 name 'æÆôöòûùÿÖÜ¢£¥₧ƒá' using flags '8' found at index 9 name 'æÆôöòûùÿÖÜ¢£¥₧ƒá' using flags 's' found at index 9 end-of-inline-data stderr can't find entry with name 'æÆôöòûùÿÖÜ¢£¥₧ƒá' using flags '4' can't find entry with name 'æÆôöòûùÿÖÜ¢£¥₧ƒá' using flags 'r' end-of-inline-data ================================================ FILE: external/libzip/regress/name_locate.test ================================================ # various tests for zip_name_locate arguments test.zip name_locate nosuchfile 0 name_locate test 0 name_locate "" 0 name_locate TeSt 0 name_locate TeSt C name_locate testdir/test2 0 name_locate tesTdir/tESt2 C name_locate testdir/test2 d name_locate tesTdir/tESt2 dC name_locate test2 0 name_locate test2 d name_locate TeST2 dC delete 0 name_locate test 0 name_locate test u add new teststring name_locate new 0 name_locate new u add "" teststring name_locate "" 0 unchange_all name_locate test 0 name_locate new 0 # delete 0 # add "new" # add "" # unchange all return 0 file test.zip test.zip stdout name 'test' using flags '0' found at index 0 name 'TeSt' using flags 'C' found at index 0 name 'testdir/test2' using flags '0' found at index 2 name 'tesTdir/tESt2' using flags 'C' found at index 2 name 'test2' using flags 'd' found at index 2 name 'TeST2' using flags 'dC' found at index 2 name 'test' using flags 'u' found at index 0 name 'new' using flags '0' found at index 3 name '' using flags '0' found at index 4 name 'test' using flags '0' found at index 0 end-of-inline-data stderr can't find entry with name 'nosuchfile' using flags '0' can't find entry with name '' using flags '0' can't find entry with name 'TeSt' using flags '0' can't find entry with name 'testdir/test2' using flags 'd' can't find entry with name 'tesTdir/tESt2' using flags 'dC' can't find entry with name 'test2' using flags '0' can't find entry with name 'test' using flags '0' can't find entry with name 'new' using flags 'u' can't find entry with name 'new' using flags '0' end-of-inline-data ================================================ FILE: external/libzip/regress/nihtest.conf.in ================================================ [settings] features-files = @PROJECT_BINARY_DIR@/config.h test-input-directories = @CMAKE_CURRENT_SOURCE_DIR@ program-directories = @PROJECT_BINARY_DIR@/regress @PROJECT_BINARY_DIR@/regress/Release @PROJECT_BINARY_DIR@/regress/Debug @PROJECT_BINARY_DIR@/src @PROJECT_BINARY_DIR@/src/Release @PROJECT_BINARY_DIR@/src/Debug default-program = ziptool_regress default-stderr-replace = "^([A-Z]:)?[^ :]*: " "" [comparators] zip.zip = zipcmp -pv ================================================ FILE: external/libzip/regress/nonrandomopen.c ================================================ /* nonrandomopen.c -- override zip_secure_random Copyright (C) 2017-2021 Dieter Baron and Thomas Klausner This file is part of ckmame, a program to check rom sets for MAME. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include "zipint.h" bool zip_secure_random(zip_uint8_t *buffer, zip_uint16_t length) { memset(buffer, 0, length); return true; } ================================================ FILE: external/libzip/regress/nonrandomopentest.c ================================================ /* nonrandomopentest.c -- test nonrandomopen.so Copyright (C) 2017-2021 Dieter Baron and Thomas Klausner This file is part of ckmame, a program to check rom sets for MAME. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "zipint.h" #include #include int main(int argc, const char *argv[]) { zip_uint8_t buf[1024]; int i; #ifdef HAVE_CRYPTO if (!zip_secure_random(buf, sizeof(buf))) { fprintf(stderr, "zip_secure_random returned false\n"); exit(1); } for (i = 0; i < sizeof(buf); i++) { if (buf[i] != 0) { fprintf(stderr, "non-zero byte found\n"); exit(1); } } #endif exit(0); } ================================================ FILE: external/libzip/regress/open_archive_comment_wrong.test ================================================ # zip_open: file with wrong archive comment length, no consistency check: opens fine program tryopen arguments incons-archive-comment-longer.zip incons-archive-comment-shorter.zip return 0 file incons-archive-comment-longer.zip incons-archive-comment-longer.zip file incons-archive-comment-shorter.zip incons-archive-comment-shorter.zip stdout opening 'incons-archive-comment-longer.zip' succeeded, 1 entries opening 'incons-archive-comment-shorter.zip' succeeded, 1 entries end-of-inline-data ================================================ FILE: external/libzip/regress/open_cons_extrabytes.test ================================================ # zip_open: file has extra bytes at end of archive program tryopen file testextrabytes.zzip testextrabytes.zip arguments -c testextrabytes.zzip return 1 stdout opening 'testextrabytes.zzip' returned error 21/2 end-of-inline-data stderr 1 errors end-of-inline-data ================================================ FILE: external/libzip/regress/open_empty.test ================================================ # zip_open: file contains no entry, but is valid program tryopen file testempty.zip testempty.zip arguments testempty.zip return 0 stdout opening 'testempty.zip' succeeded, 0 entries end-of-inline-data ================================================ FILE: external/libzip/regress/open_empty_2.test ================================================ # zip_open: 0 size file is recognized as empty zip program tryopen file testfile.txt testfile.txt arguments testfile.txt return 1 stdout opening 'testfile.txt' returned error 19 end-of-inline-data stderr 1 errors end-of-inline-data ================================================ FILE: external/libzip/regress/open_extrabytes.test ================================================ # zip_open: file has extra bytes at end of archive program tryopen file testextrabytes.zzip testextrabytes.zip arguments testextrabytes.zzip return 0 stdout opening 'testextrabytes.zzip' succeeded, 1 entries end-of-inline-data ================================================ FILE: external/libzip/regress/open_file_count.test ================================================ # zip_open: various inconsistent files program tryopen file incons-file-count-high.zzip incons-file-count-high.zip file incons-file-count-low.zzip incons-file-count-low.zip file incons-file-count-overflow.zzip incons-file-count-overflow.zip arguments incons-file-count-high.zzip incons-file-count-low.zzip incons-file-count-overflow.zzip return 1 stdout opening 'incons-file-count-high.zzip' returned error 21/5 opening 'incons-file-count-low.zzip' returned error 21/5 opening 'incons-file-count-overflow.zzip' returned error 21/11 end-of-inline-data stderr 3 errors end-of-inline-data ================================================ FILE: external/libzip/regress/open_filename_duplicate.test ================================================ # zip_open: file opens fine even though same file name appears twice program tryopen arguments filename_duplicate.zzip return 0 file filename_duplicate.zzip filename_duplicate.zip stdout opening 'filename_duplicate.zzip' succeeded, 2 entries end-of-inline-data ================================================ FILE: external/libzip/regress/open_filename_duplicate_consistency.test ================================================ # zip_open: file opens fine even though same file name appears twice program tryopen arguments -c filename_duplicate.zzip return 1 file filename_duplicate.zzip filename_duplicate.zip stdout opening 'filename_duplicate.zzip' returned error 10 end-of-inline-data stderr 1 errors end-of-inline-data ================================================ FILE: external/libzip/regress/open_filename_duplicate_empty.test ================================================ # zip_open: file opens fine even though same file name (empty file name) appears twice program tryopen arguments filename_duplicate_empty.zzip return 0 file filename_duplicate_empty.zzip filename_duplicate_empty.zip stdout opening 'filename_duplicate_empty.zzip' succeeded, 2 entries end-of-inline-data ================================================ FILE: external/libzip/regress/open_filename_duplicate_empty_consistency.test ================================================ # zip_open: file opens fine even though same file name (empty file name) appears twice program tryopen arguments -c filename_duplicate_empty.zzip return 1 file filename_duplicate_empty.zzip filename_duplicate_empty.zip stdout opening 'filename_duplicate_empty.zzip' returned error 10 end-of-inline-data stderr 1 errors end-of-inline-data ================================================ FILE: external/libzip/regress/open_filename_empty.test ================================================ # zip_open: file opens fine even though file name has length 0 program tryopen arguments filename_empty.zip return 0 file filename_empty.zip filename_empty.zip stdout opening 'filename_empty.zip' succeeded, 1 entries end-of-inline-data ================================================ FILE: external/libzip/regress/open_incons.test ================================================ # zip_open: various inconsistent files program tryopen file incons-archive-comment-longer.zzip incons-archive-comment-longer.zip file incons-archive-comment-shorter.zzip incons-archive-comment-shorter.zip file incons-cdoffset.zzip incons-cdoffset.zip file incons-cdsize-large.zzip incons-cdsize-large.zip file incons-cdsize-small.zzip incons-cdsize-large.zip file incons-central-compression-method.zzip incons-central-compression-method.zip file incons-central-compsize-larger.zzip incons-central-compsize-larger.zip file incons-central-compsize-larger-toolarge.zzip incons-central-compsize-larger-toolarge.zip file incons-central-compsize-smaller.zzip incons-central-compsize-smaller.zip file incons-central-crc.zzip incons-central-crc.zip file incons-central-date.zzip incons-central-date.zip file incons-central-file-comment-longer.zzip incons-central-file-comment-longer.zip file incons-central-file-comment-shorter.zzip incons-central-file-comment-shorter.zip file incons-central-file-comment-utf8-ascii.zzip incons-central-file-comment-utf8-ascii.zip file incons-central-magic-bad.zzip incons-central-magic-bad.zip file incons-central-magic-bad2.zzip incons-central-magic-bad2.zip file incons-central-size-larger.zzip incons-central-size-larger.zip file incons-data.zzip incons-data.zip file incons-ef-central-size-wrong.zzip incons-ef-central-size-wrong.zip file incons-ef-local-dupe-utf8comment.zzip incons-ef-local-dupe-utf8comment.zip file incons-ef-local-dupe-utf8name.zzip incons-ef-local-dupe-utf8name.zip file incons-ef-local-dupe-zip64-v1.zzip incons-ef-local-dupe-zip64-v1.zip file incons-ef-local-dupe-zip64-v2.zzip incons-ef-local-dupe-zip64-v2.zip file incons-ef-local-id-size.zzip incons-ef-local-id-size.zip file incons-ef-local-id.zzip incons-ef-local-id.zip file incons-ef-local-size.zzip incons-ef-local-size.zip file incons-ef-local-utf8name-ascii.zzip incons-ef-local-utf8name-ascii.zip file incons-eocd64.zzip incons-eocd64.zip file incons-eocd-magic-bad.zzip incons-eocd-magic-bad.zip file incons-file-count-high.zzip incons-file-count-high.zip file incons-file-count-low.zzip incons-file-count-low.zip file incons-file-count-overflow.zzip incons-file-count-overflow.zip file incons-gap-before-cd.zzip incons-gap-before-cd.zip file incons-gap-before-eocd.zzip incons-gap-before-eocd.zip file incons-gap-before-local.zzip incons-gap-before-local.zip file incons-local-compression-method.zzip incons-local-compression-method.zip file incons-local-compsize-larger.zzip incons-local-compsize-larger.zip file incons-local-compsize-smaller.zzip incons-local-compsize-smaller.zip file incons-local-crc.zzip incons-local-crc.zip file incons-local-filename-long.zzip incons-local-filename-long.zip file incons-local-filename-missing.zzip incons-local-filename-missing.zip file incons-local-filename-nil-byte.zzip incons-local-filename-nil-byte.zip file incons-local-filename-short.zzip incons-local-filename-short.zip file incons-local-filename.zzip incons-local-filename.zip file incons-local-magic-bad.zzip incons-local-magic-bad.zip file incons-local-size-larger.zzip incons-local-size-larger.zip file incons-stored-size.zzip incons-stored-size.zip file incons-streamed.zzip incons-streamed.zip file incons-streamed-2.zzip incons-streamed-2.zip arguments -s -c incons-archive-comment-longer.zzip incons-archive-comment-shorter.zzip incons-cdoffset.zzip incons-cdsize-large.zzip incons-cdsize-small.zzip incons-central-compression-method.zzip incons-central-compsize-larger-toolarge.zzip incons-central-compsize-larger.zzip incons-central-compsize-smaller.zzip incons-central-crc.zzip incons-central-date.zzip incons-central-file-comment-longer.zzip incons-central-file-comment-shorter.zzip incons-central-file-comment-utf8-ascii.zzip incons-central-magic-bad.zzip incons-central-magic-bad2.zzip incons-central-size-larger.zzip incons-data.zzip incons-ef-central-size-wrong.zzip incons-ef-local-dupe-utf8comment.zzip incons-ef-local-dupe-utf8name.zzip incons-ef-local-dupe-zip64-v1.zzip incons-ef-local-dupe-zip64-v2.zzip incons-ef-local-id-size.zzip incons-ef-local-id.zzip incons-ef-local-size.zzip incons-ef-local-utf8name-ascii.zzip incons-eocd64.zzip incons-eocd-magic-bad.zzip incons-file-count-high.zzip incons-file-count-low.zzip incons-file-count-overflow.zzip incons-gap-before-cd.zzip incons-gap-before-eocd.zzip incons-gap-before-local.zzip incons-local-compression-method.zzip incons-local-compsize-larger.zzip incons-local-compsize-smaller.zzip incons-local-crc.zzip incons-local-filename-long.zzip incons-local-filename-missing.zzip incons-local-filename-nil-byte.zzip incons-local-filename-short.zzip incons-local-filename.zzip incons-local-magic-bad.zzip incons-local-size-larger.zzip incons-stored-size.zzip incons-streamed.zzip incons-streamed-2.zzip return 1 # tryopen does not test checksums, so this is fine. # different extra fields local vs. central is fine stdout opening 'incons-archive-comment-longer.zzip' returned error Zip archive inconsistent: archive comment length incorrect opening 'incons-archive-comment-shorter.zzip' returned error Zip archive inconsistent: archive comment length incorrect opening 'incons-cdoffset.zzip' returned error Possibly truncated or corrupted zip archive opening 'incons-cdsize-large.zzip' returned error Zip archive inconsistent: central directory overlaps EOCD, or there is space between them opening 'incons-cdsize-small.zzip' returned error Zip archive inconsistent: central directory overlaps EOCD, or there is space between them opening 'incons-central-compression-method.zzip' returned error Zip archive inconsistent: entry 0: local and central headers do not match opening 'incons-central-compsize-larger-toolarge.zzip' returned error Possibly truncated or corrupted zip archive opening 'incons-central-compsize-larger.zzip' returned error Zip archive inconsistent: entry 0: local and central headers do not match opening 'incons-central-compsize-smaller.zzip' returned error Zip archive inconsistent: entry 0: local and central headers do not match opening 'incons-central-crc.zzip' returned error Zip archive inconsistent: entry 0: local and central headers do not match opening 'incons-central-date.zzip' returned error Zip archive inconsistent: entry 0: local and central headers do not match opening 'incons-central-file-comment-longer.zzip' returned error Zip archive inconsistent: entry 0: variable size fields overflow header opening 'incons-central-file-comment-shorter.zzip' returned error Zip archive inconsistent: entry 1: central header invalid opening 'incons-central-file-comment-utf8-ascii.zzip' succeeded, 1 entries opening 'incons-central-magic-bad.zzip' returned error Possibly truncated or corrupted zip archive opening 'incons-central-magic-bad2.zzip' returned error Possibly truncated or corrupted zip archive opening 'incons-central-size-larger.zzip' returned error Zip archive inconsistent: entry 0: local and central headers do not match opening 'incons-data.zzip' succeeded, 1 entries opening 'incons-ef-central-size-wrong.zzip' returned error Zip archive inconsistent: entry 0: extra field length is invalid opening 'incons-ef-local-dupe-utf8comment.zzip' succeeded, 1 entries opening 'incons-ef-local-dupe-utf8name.zzip' returned error Zip archive inconsistent: entry 0: local and central headers do not match opening 'incons-ef-local-dupe-zip64-v1.zzip' returned error Zip archive inconsistent: entry 0: local and central headers do not match opening 'incons-ef-local-dupe-zip64-v2.zzip' succeeded, 1 entries opening 'incons-ef-local-id-size.zzip' returned error Zip archive inconsistent: entry 0: extra field length is invalid opening 'incons-ef-local-id.zzip' succeeded, 1 entries opening 'incons-ef-local-size.zzip' returned error Zip archive inconsistent: entry 0: extra field length is invalid opening 'incons-ef-local-utf8name-ascii.zzip' returned error Zip archive inconsistent: entry 0: UTF-8 filename is ASCII and doesn't match filename opening 'incons-eocd64.zzip' returned error Zip archive inconsistent: EOCD64 and EOCD do not match opening 'incons-eocd-magic-bad.zzip' returned error Possibly truncated or corrupted zip archive opening 'incons-file-count-high.zzip' returned error Zip archive inconsistent: central directory count of entries is incorrect opening 'incons-file-count-low.zzip' returned error Zip archive inconsistent: central directory count of entries is incorrect opening 'incons-file-count-overflow.zzip' returned error Zip archive inconsistent: invalid value in central directory opening 'incons-gap-before-cd.zzip' succeeded, 1 entries opening 'incons-gap-before-eocd.zzip' succeeded, 1 entries opening 'incons-gap-before-local.zzip' succeeded, 2 entries opening 'incons-local-compression-method.zzip' returned error Zip archive inconsistent: entry 0: local and central headers do not match opening 'incons-local-compsize-larger.zzip' returned error Zip archive inconsistent: entry 0: local and central headers do not match opening 'incons-local-compsize-smaller.zzip' returned error Zip archive inconsistent: entry 0: local and central headers do not match opening 'incons-local-crc.zzip' returned error Zip archive inconsistent: entry 0: local and central headers do not match opening 'incons-local-filename-long.zzip' returned error Premature end of file opening 'incons-local-filename-missing.zzip' returned error Zip archive inconsistent: entry 0: local and central headers do not match opening 'incons-local-filename-nil-byte.zzip' succeeded, 1 entries opening 'incons-local-filename-short.zzip' returned error Zip archive inconsistent: entry 0: extra field length is invalid opening 'incons-local-filename.zzip' returned error Zip archive inconsistent: entry 0: local and central headers do not match opening 'incons-local-magic-bad.zzip' returned error Not a zip archive opening 'incons-local-size-larger.zzip' returned error Zip archive inconsistent: entry 0: local and central headers do not match opening 'incons-stored-size.zzip' returned error Zip archive inconsistent: entry 0: compressed and uncompressed sizes don't match for stored file opening 'incons-streamed.zzip' returned error Zip archive inconsistent: entry 0: local and central headers do not match opening 'incons-streamed-2.zzip' returned error Zip archive inconsistent: entry 0: local header and data descriptor do not match end-of-inline-data stderr 40 errors end-of-inline-data ================================================ FILE: external/libzip/regress/open_many_fail.test ================================================ # zip_open: files with >65k that have issues program tryopen arguments manyfiles-zip64-modulo.zzip manyfiles-fewer.zzip manyfiles-more.zzip return 1 file manyfiles-zip64-modulo.zzip manyfiles-zip64-modulo.zip file manyfiles-fewer.zzip manyfiles-fewer.zip file manyfiles-more.zzip manyfiles-more.zip stdout opening 'manyfiles-zip64-modulo.zzip' returned error 21/5 opening 'manyfiles-fewer.zzip' returned error 21/5 opening 'manyfiles-more.zzip' returned error 21/5 end-of-inline-data stderr 3 errors end-of-inline-data ================================================ FILE: external/libzip/regress/open_many_ok.test ================================================ # zip_open: files open fine, have > 65k entries program tryopen arguments manyfiles.zip manyfiles-zip64.zip manyfiles-133000.zip manyfiles-65536.zip return 0 file manyfiles.zip manyfiles.zip file manyfiles-zip64.zip manyfiles-zip64.zip file manyfiles-133000.zip manyfiles-133000.zip file manyfiles-65536.zip manyfiles-65536.zip stdout opening 'manyfiles.zip' succeeded, 70000 entries opening 'manyfiles-zip64.zip' succeeded, 70000 entries opening 'manyfiles-133000.zip' succeeded, 133000 entries opening 'manyfiles-65536.zip' succeeded, 65536 entries end-of-inline-data ================================================ FILE: external/libzip/regress/open_multidisk.test ================================================ # zip_open: file is part of a multi-disk zip archive program tryopen arguments test.piz return 1 file test.piz multidisk.zip stdout opening 'test.piz' returned error 1 end-of-inline-data stderr 1 errors end-of-inline-data ================================================ FILE: external/libzip/regress/open_new_but_exists.test ================================================ # zip_open: file shall be created but already exists program tryopen arguments -e test.zip return 1 file test.zip test.zip stdout opening 'test.zip' returned error 10 end-of-inline-data stderr 1 errors end-of-inline-data ================================================ FILE: external/libzip/regress/open_new_ok.test ================================================ # zip_open: create new archive program tryopen arguments -n new.zip return 0 stdout opening 'new.zip' succeeded, 0 entries end-of-inline-data ================================================ FILE: external/libzip/regress/open_nonarchive.test ================================================ # zip_open: file is not a zip archive program tryopen file CMakeLists.txt CMakeLists.txt arguments CMakeLists.txt return 1 stdout opening 'CMakeLists.txt' returned error 19 end-of-inline-data stderr 1 errors end-of-inline-data ================================================ FILE: external/libzip/regress/open_nosuchfile.test ================================================ # zip_open: file doesn't exist program tryopen arguments nosuchfile return 1 stdout opening 'nosuchfile' returned error 9 end-of-inline-data stderr 1 errors end-of-inline-data ================================================ FILE: external/libzip/regress/open_ok.test ================================================ # zip_open: file opens fine program tryopen arguments test.zip return 0 file test.zip test.zip stdout opening 'test.zip' succeeded, 3 entries end-of-inline-data ================================================ FILE: external/libzip/regress/open_too_short.test ================================================ # zip_open: file is too short for even a central directory entry program tryopen arguments test.piz return 1 file test.piz bogus.zip stdout opening 'test.piz' returned error 19 end-of-inline-data stderr 1 errors end-of-inline-data ================================================ FILE: external/libzip/regress/open_truncate.test ================================================ # zip_open: file opens fine and gets truncated program tryopen arguments -t test.zip return 0 file test.zip test.zip {} stdout opening 'test.zip' succeeded, 0 entries end-of-inline-data ================================================ FILE: external/libzip/regress/open_truncated.test ================================================ # zip_open: try opening an incomplete zip archive program tryopen arguments test.zzip return 1 file test.zzip testfile-truncated.zip stdout opening 'test.zzip' returned error 35 end-of-inline-data stderr 1 errors end-of-inline-data ================================================ FILE: external/libzip/regress/open_zip64_3mf.test ================================================ # zip_open: ZIP64 file opens fine even when most eocd entries are 0xff (3MF format) program tryopen arguments test.zip return 0 file test.zip zip64-3mf.zip stdout opening 'test.zip' succeeded, 1 entries end-of-inline-data ================================================ FILE: external/libzip/regress/open_zip64_ok.test ================================================ # zip_open: ZIP64 file opens fine program tryopen arguments test.zip return 0 file test.zip zip64.zip stdout opening 'test.zip' succeeded, 1 entries end-of-inline-data ================================================ FILE: external/libzip/regress/preload.test ================================================ description test if preload works program nonrandomopentest return 0 preload nonrandomopen.so ================================================ FILE: external/libzip/regress/progress.test ================================================ # test default compression stores if smaller; print progress return 0 arguments -n -- test.zip print_progress add compressible aaaaaaaaaaaaaa add uncompressible uncompressible add_nul large-compressible 8200 add_file large-uncompressible large-uncompressible 0 -1 file test.zip {} cm-default.zip file large-uncompressible large-uncompressible stdout 0.0% done 25.0% done 50.0% done 75.0% done 100.0% done end-of-inline-data ================================================ FILE: external/libzip/regress/read_incons.test ================================================ arguments -c test.zip cat 0 return 1 file test.zip incons-trailing-garbage.zip stdout test end-of-inline-data stderr can't read file at index '0': Zip archive inconsistent: garbage at end of compressed data end-of-inline-data ================================================ FILE: external/libzip/regress/read_seek_read.test ================================================ # read past EOF, seek to beginning, read again return 0 arguments test.zip fopen test fread 0 10 fseek 0 0 set fread 0 5 file test.zip test.zip stdout opened 'test' as file 0 test test end-of-inline-data ================================================ FILE: external/libzip/regress/rename_ascii.test ================================================ # rename file to ASCII name in zip archive return 0 arguments testfile rename 0 testfile.txt file testfile testfile-UTF8.zip testfile.zip ================================================ FILE: external/libzip/regress/rename_cp437.test ================================================ # rename file to CP437 name in zip archive (fails) return 0 arguments -x testfile.zip rename 0 "8182838485868788898A8B8C8D8E8F90" file testfile.zip testfile.zip testfile-cp437.zip ================================================ FILE: external/libzip/regress/rename_deleted.test ================================================ # rename deleted entry in zip archive (fails) return 1 arguments testfile.zip delete 1 delete 3 rename 1 othername file testfile.zip testcomment.zip testcomment13.zip stderr can't rename file at index '1' to 'othername': Entry has been deleted end-of-inline-data ================================================ FILE: external/libzip/regress/rename_fail.test ================================================ # rename file inside zip archive, but file name already exists return 1 arguments rename.zip rename 0 file4 file rename.zip testcomment.zip stderr can't rename file at index '0' to 'file4': File already exists end-of-inline-data ================================================ FILE: external/libzip/regress/rename_ok.test ================================================ # rename file inside zip archive return 0 arguments rename.zip rename 1 notfile2 file rename.zip testcomment.zip rename_ok.zip ================================================ FILE: external/libzip/regress/rename_utf8.test ================================================ # rename file to UTF-8 name in zip archive return 0 arguments -i testfile dummy stdin rename 0 ÄÖÜßäöü end-of-inline-data file testfile testfile.zip testfile-UTF8.zip ================================================ FILE: external/libzip/regress/rename_utf8_encmismatch.test ================================================ # rename file to UTF-8 name in zip archive with CP437 comment (sets InfoZIP UTF-8 Name Extension) return 0 arguments -i testfile dummy stdin rename 0 ÄÖÜßäöü end-of-inline-data file testfile test-cp437-fc.zip test-cp437-fc-utf-8-filename.zip ================================================ FILE: external/libzip/regress/reopen.test ================================================ description check the reopen functionality return 0 arguments -- testbuffer.zip cat 0 replace_file_contents 0 "Overwritten\n" cat 0 add newfile.txt "A new file\n" cat 1 file testbuffer.zip testbuffer.zip testbuffer_reopen.zip stdout This is a test, and it seems to have been successful. Overwritten A new file end-of-inline-data ================================================ FILE: external/libzip/regress/reopen_partial.test ================================================ description check the reopen functionality (partial reads) return 0 arguments -- testbuffer.zip cat 0 replace_file_contents 0 "Overwritten\n" cat_partial 0 4 5 add newfile.txt "A new file\n" cat_partial 1 2 3 file testbuffer.zip testbuffer.zip testbuffer_reopen.zip stdout This is a test, and it seems to have been successful. writtnew end-of-inline-data ================================================ FILE: external/libzip/regress/reopen_partial_rest.test ================================================ description check the reopen functionality (partial reads with -1 length) return 0 arguments -- testbuffer.zip cat 0 replace_file_contents 0 "Overwritten\n" cat_partial 0 4 -1 add newfile.txt "A new file\n" cat_partial 1 2 -1 file testbuffer.zip testbuffer.zip testbuffer_reopen.zip stdout This is a test, and it seems to have been successful. written new file end-of-inline-data ================================================ FILE: external/libzip/regress/replace_set_stored.test ================================================ # replace file, set compression method to ZIP_CM_STORE (like it was before) return 0 arguments -n test.zip replace_file_contents 0 aaaaaaaa set_file_compression 0 store 0 file test.zip aaaaaaaa-stored.zip ================================================ FILE: external/libzip/regress/set_comment_all.test ================================================ # change local and global comments in a zip archive return 0 arguments testcomment.zip set_archive_comment "This is the new,\r\nmultiline archive comment.\r\nAin't it nice?" set_file_comment 0 "File comment no 0" set_file_comment 1 "File comment no 1" set_file_comment 2 "File comment no 2" set_file_comment 3 "File comment no 3" file testcomment.zip testcomment.zip testchanged.zip ================================================ FILE: external/libzip/regress/set_comment_localonly.test ================================================ # change file comments in a zip archive return 0 arguments testcomment.zip set_file_comment 0 "File comment no 0" set_file_comment 1 "File comment no 1" set_file_comment 3 "File comment no 3" set_file_comment 2 "" file testcomment.zip testcomment.zip testchangedlocal.zip ================================================ FILE: external/libzip/regress/set_comment_removeglobal.test ================================================ # remove archive comment return 0 arguments testcomment.zip set_archive_comment "" file testcomment.zip testcomment.zip testcommentremoved.zip ================================================ FILE: external/libzip/regress/set_comment_revert.test ================================================ # start changing local and global comments, but revert before closing return 0 arguments testcomment.zip set_archive_comment "some long string, a bit longer than this at least" set_file_comment 0 "File comment no 0" set_file_comment 1 "File comment no 1" set_file_comment 3 "File comment no 3" set_file_comment 2 "" unchange_all file testcomment.zip testcomment.zip ================================================ FILE: external/libzip/regress/set_compression_bzip2_to_deflate.test ================================================ # change method from bzip2 to deflated features HAVE_LIBBZ2 return 0 arguments test.zip set_file_compression 0 deflate 0 file test.zip testbzip2.zip testdeflated.zip ================================================ FILE: external/libzip/regress/set_compression_deflate_to_bzip2.test ================================================ # change method from deflated to bzip2 features HAVE_LIBBZ2 return 0 arguments test.zip set_file_compression 0 bzip2 0 file test.zip testdeflated.zip testbzip2.zip ================================================ FILE: external/libzip/regress/set_compression_deflate_to_deflate.test ================================================ # change method from deflated to deflated (no change) return 0 arguments test.zip set_file_compression 0 deflate 0 file test.zip testdeflated.zip ================================================ FILE: external/libzip/regress/set_compression_deflate_to_store.test ================================================ # change method from deflated to stored return 0 arguments test.zip set_file_compression 0 store 0 file test.zip testdeflated.zip teststored.zip ================================================ FILE: external/libzip/regress/set_compression_lzma_no_eos_to_store.test ================================================ # change method from lzma-compressed (id 14) without EOS/EOPM marker to stored features HAVE_LIBLZMA return 0 arguments test.zip set_file_compression 0 store 0 file test.zip lzma-no-eos.zip stored-no-eos.zip ================================================ FILE: external/libzip/regress/set_compression_lzma_to_store.test ================================================ # change method from lzma-compressed (id 14) to stored features HAVE_LIBLZMA return 0 arguments test.zip set_file_compression 0 store 0 file test.zip testfile-lzma.zip testfile-stored-dos.zip ================================================ FILE: external/libzip/regress/set_compression_store_to_bzip2.test ================================================ # change method from stored to bzip2 features HAVE_LIBBZ2 return 0 arguments test.zip set_file_compression 0 bzip2 0 file test.zip teststored.zip testbzip2.zip ================================================ FILE: external/libzip/regress/set_compression_store_to_deflate.test ================================================ # change method from stored to deflated return 0 arguments test.zip set_file_compression 0 deflate 0 file test.zip teststored.zip testdeflated.zip ================================================ FILE: external/libzip/regress/set_compression_store_to_lzma.test ================================================ # change method from stored to lzma-compressed (Id 14) features HAVE_LIBLZMA return 0 arguments test.zip set_file_compression 0 lzma 0 file test.zip testfile-stored-dos.zip testfile-lzma.zip ================================================ FILE: external/libzip/regress/set_compression_store_to_store.test ================================================ # change method from stored to stored (no change) return 0 arguments test.zip set_file_compression 0 store 0 file test.zip teststored.zip ================================================ FILE: external/libzip/regress/set_compression_store_to_xz.test ================================================ # change method from stored to xz-compressed features HAVE_LIBLZMA return 0 arguments test.zip set_file_compression 0 xz 0 file test.zip testfile-stored-dos.zip testfile-xz.zip ================================================ FILE: external/libzip/regress/set_compression_store_to_zstd.test ================================================ # change method from stored to zstd-compressed features HAVE_LIBZSTD return 0 arguments test.zip set_file_compression 0 zstd 0 file test.zip testfile-stored-dos.zip testfile-zstd.zip ================================================ FILE: external/libzip/regress/set_compression_unknown.test ================================================ # change method to unknown return 1 arguments test.zip set_file_compression 0 unknown 0 file test.zip teststored.zip stderr can't set file compression method at index '0' to 'unknown', flags '0': Compression method not supported end-of-inline-data ================================================ FILE: external/libzip/regress/set_compression_xz_to_store.test ================================================ # change method from xz-compressed to stored features HAVE_LIBLZMA return 0 arguments test.zip set_file_compression 0 store 0 file test.zip testfile-xz.zip testfile-stored-dos.zip ================================================ FILE: external/libzip/regress/set_compression_zstd_to_store.test ================================================ # change method from zstd-compressed to stored features HAVE_LIBZSTD return 0 arguments test.zip set_file_compression 0 store 0 file test.zip testfile-zstd.zip testfile-stored-dos.zip ================================================ FILE: external/libzip/regress/set_file_dostime.test ================================================ # change dostime in a zip archive (use torrentzip default time) return 0 arguments testfile set_file_dostime 0 48128 8600 file testfile testfile.zip testfile0.zip ================================================ FILE: external/libzip/regress/set_file_mtime.test ================================================ # change mtime in a zip archive return 0 arguments testfile set_file_mtime 0 1407272201 file testfile testfile.zip testfile2014.zip ================================================ FILE: external/libzip/regress/set_file_mtime_pkware.test ================================================ # change mtime in a zip archive, fails because file is PKWare-encrypted return 1 arguments testfile set_file_mtime 0 1407272201 file testfile encrypt.zip stderr can't set file mtime at index '0' to '1407272201': Operation not supported end-of-inline-data ================================================ FILE: external/libzip/regress/short ================================================ short ================================================ FILE: external/libzip/regress/source_hole.c ================================================ /* source_hole.c -- source for handling huge files that are mostly NULs Copyright (C) 2014-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include "zip.h" /* public API */ zip_source_t *source_hole_create(const char *, int flags, zip_error_t *); #ifndef EFTYPE #define EFTYPE EINVAL #endif #define MY_MIN(a, b) ((a) < (b) ? (a) : (b)) #define FRAGMENT_SIZE (8 * 1024) #define MARK_BEGIN "NiH0" #define MARK_DATA "NiH1" #define MARK_NUL "NiH2" typedef struct buffer { zip_uint64_t fragment_size; zip_uint8_t **fragment; zip_uint64_t nfragments; zip_uint64_t size; zip_uint64_t offset; } buffer_t; static void buffer_free(buffer_t *buffer); static buffer_t *buffer_from_file(const char *fname, int flags, zip_error_t *error); static buffer_t *buffer_new(void); static zip_int64_t buffer_read(buffer_t *buffer, zip_uint8_t *data, zip_uint64_t length, zip_error_t *error); static int buffer_read_file(buffer_t *buffer, FILE *f, zip_error_t *error); static zip_int64_t buffer_seek(buffer_t *buffer, void *data, zip_uint64_t length, zip_error_t *error); static int buffer_to_file(buffer_t *buffer, const char *fname, zip_error_t *error); static zip_int64_t buffer_write(buffer_t *buffer, const zip_uint8_t *data, zip_uint64_t length, zip_error_t *error); static zip_uint64_t get_u64(const zip_uint8_t *b); static int only_nul(const zip_uint8_t *data, zip_uint64_t length); static int write_nuls(zip_uint64_t n, FILE *f); static int write_u64(zip_uint64_t u64, FILE *f); typedef struct hole { zip_error_t error; char *fname; buffer_t *in; buffer_t *out; } hole_t; static hole_t *hole_new(const char *fname, int flags, zip_error_t *error); static zip_int64_t source_hole_cb(void *ud, void *data, zip_uint64_t length, zip_source_cmd_t command); zip_source_t * source_hole_create(const char *fname, int flags, zip_error_t *error) { hole_t *ud = hole_new(fname, flags, error); if (ud == NULL) { return NULL; } return zip_source_function_create(source_hole_cb, ud, error); } static void buffer_free(buffer_t *buffer) { zip_uint64_t i; if (buffer == NULL) { return; } if (buffer->fragment) { for (i = 0; i < buffer->nfragments; i++) { free(buffer->fragment[i]); } free(buffer->fragment); } free(buffer); } static buffer_t * buffer_from_file(const char *fname, int flags, zip_error_t *error) { buffer_t *buffer; FILE *f; if ((buffer = buffer_new()) == NULL) { zip_error_set(error, ZIP_ER_MEMORY, 0); return NULL; } if ((flags & ZIP_TRUNCATE) == 0) { if ((f = fopen(fname, "rb")) == NULL) { if (!(errno == ENOENT && (flags & ZIP_CREATE))) { buffer_free(buffer); return NULL; } } else { if (buffer_read_file(buffer, f, error) < 0) { buffer_free(buffer); fclose(f); return NULL; } fclose(f); } } return buffer; } static buffer_t * buffer_new(void) { buffer_t *buffer; if ((buffer = (buffer_t *)malloc(sizeof(*buffer))) == NULL) { return NULL; } buffer->fragment = NULL; buffer->nfragments = 0; buffer->fragment_size = FRAGMENT_SIZE; buffer->size = 0; buffer->offset = 0; return buffer; } static zip_int64_t buffer_read(buffer_t *buffer, zip_uint8_t *data, zip_uint64_t length, zip_error_t *error) { zip_uint64_t n, i, fragment_offset; length = MY_MIN(length, buffer->size - buffer->offset); if (length == 0) { return 0; } if (length > ZIP_INT64_MAX) { return -1; } i = buffer->offset / buffer->fragment_size; fragment_offset = buffer->offset % buffer->fragment_size; n = 0; while (n < length) { zip_uint64_t left = MY_MIN(length - n, buffer->fragment_size - fragment_offset); if (buffer->fragment[i]) { memcpy(data + n, buffer->fragment[i] + fragment_offset, left); } else { memset(data + n, 0, left); } n += left; i++; fragment_offset = 0; } buffer->offset += n; return (zip_int64_t)n; } static int buffer_read_file(buffer_t *buffer, FILE *f, zip_error_t *error) { zip_uint8_t b[20]; zip_uint64_t i; if (fread(b, 20, 1, f) != 1) { zip_error_set(error, ZIP_ER_READ, errno); return -1; } if (memcmp(b, MARK_BEGIN, 4) != 0) { zip_error_set(error, ZIP_ER_READ, EFTYPE); return -1; } buffer->fragment_size = get_u64(b + 4); buffer->size = get_u64(b + 12); if (buffer->fragment_size == 0) { zip_error_set(error, ZIP_ER_INCONS, 0); return -1; } buffer->nfragments = buffer->size / buffer->fragment_size; if (buffer->size % buffer->fragment_size != 0) { buffer->nfragments += 1; } if ((buffer->nfragments > SIZE_MAX / sizeof(buffer->fragment[0])) || ((buffer->fragment = (zip_uint8_t **)malloc(sizeof(buffer->fragment[0]) * buffer->nfragments)) == NULL)) { zip_error_set(error, ZIP_ER_MEMORY, 0); return -1; } for (i = 0; i < buffer->nfragments; i++) { buffer->fragment[i] = NULL; } i = 0; while (i < buffer->nfragments) { if (fread(b, 4, 1, f) != 1) { zip_error_set(error, ZIP_ER_READ, errno); return -1; } if (memcmp(b, MARK_DATA, 4) == 0) { if (buffer->fragment_size > SIZE_MAX) { zip_error_set(error, ZIP_ER_MEMORY, 0); return -1; } if ((buffer->fragment[i] = (zip_uint8_t *)malloc(buffer->fragment_size)) == NULL) { zip_error_set(error, ZIP_ER_MEMORY, 0); return -1; } if (fread(buffer->fragment[i], buffer->fragment_size, 1, f) != 1) { zip_error_set(error, ZIP_ER_READ, errno); return -1; } i++; } else if (memcmp(b, MARK_NUL, 4) == 0) { if (fread(b, 8, 1, f) != 1) { zip_error_set(error, ZIP_ER_READ, errno); return -1; } i += get_u64(b); } else { zip_error_set(error, ZIP_ER_READ, EFTYPE); return -1; } } return 0; } static zip_int64_t buffer_seek(buffer_t *buffer, void *data, zip_uint64_t length, zip_error_t *error) { zip_int64_t new_offset = zip_source_seek_compute_offset(buffer->offset, buffer->size, data, length, error); if (new_offset < 0) { return -1; } buffer->offset = (zip_uint64_t)new_offset; return 0; } static int buffer_to_file(buffer_t *buffer, const char *fname, zip_error_t *error) { FILE *f = fopen(fname, "wb"); zip_uint64_t i; zip_uint64_t nul_run; if (f == NULL) { zip_error_set(error, ZIP_ER_OPEN, errno); return -1; } fwrite(MARK_BEGIN, 4, 1, f); write_u64(buffer->fragment_size, f); write_u64(buffer->size, f); nul_run = 0; for (i = 0; i * buffer->fragment_size < buffer->size; i++) { if (buffer->fragment[i] == NULL || only_nul(buffer->fragment[i], buffer->fragment_size)) { nul_run++; } else { if (nul_run > 0) { write_nuls(nul_run, f); nul_run = 0; } fwrite(MARK_DATA, 4, 1, f); fwrite(buffer->fragment[i], 1, buffer->fragment_size, f); } } if (nul_run > 0) { write_nuls(nul_run, f); } if (fclose(f) != 0) { zip_error_set(error, ZIP_ER_WRITE, errno); return -1; } return 0; } static zip_int64_t buffer_write(buffer_t *buffer, const zip_uint8_t *data, zip_uint64_t length, zip_error_t *error) { zip_uint8_t **fragment; if (buffer->offset + length > buffer->nfragments * buffer->fragment_size) { zip_uint64_t needed_fragments = (buffer->offset + length + buffer->fragment_size - 1) / buffer->fragment_size; zip_uint64_t new_capacity = buffer->nfragments; zip_uint64_t i; if (new_capacity == 0) { new_capacity = 4; } while (new_capacity < needed_fragments) { new_capacity *= 2; } fragment = realloc(buffer->fragment, new_capacity * sizeof(*fragment)); if (fragment == NULL) { zip_error_set(error, ZIP_ER_MEMORY, 0); return -1; } for (i = buffer->nfragments; i < new_capacity; i++) { fragment[i] = NULL; } buffer->fragment = fragment; buffer->nfragments = new_capacity; } if (!only_nul(data, length)) { zip_uint64_t idx, n, fragment_offset; idx = buffer->offset / buffer->fragment_size; fragment_offset = buffer->offset % buffer->fragment_size; n = 0; while (n < length) { zip_uint64_t left = MY_MIN(length - n, buffer->fragment_size - fragment_offset); if (buffer->fragment[idx] == NULL) { if ((buffer->fragment[idx] = (zip_uint8_t *)malloc(buffer->fragment_size)) == NULL) { zip_error_set(error, ZIP_ER_MEMORY, 0); return -1; } memset(buffer->fragment[idx], 0, buffer->fragment_size); } memcpy(buffer->fragment[idx] + fragment_offset, data + n, left); n += left; idx++; fragment_offset = 0; } } buffer->offset += length; if (buffer->offset > buffer->size) { buffer->size = buffer->offset; } return (zip_int64_t)length; } static zip_uint64_t get_u64(const zip_uint8_t *b) { zip_uint64_t i; i = (zip_uint64_t)b[0] << 56 | (zip_uint64_t)b[1] << 48 | (zip_uint64_t)b[2] << 40 | (zip_uint64_t)b[3] << 32 | (zip_uint64_t)b[4] << 24 | (zip_uint64_t)b[5] << 16 | (zip_uint64_t)b[6] << 8 | (zip_uint64_t)b[7]; return i; } static int only_nul(const zip_uint8_t *data, zip_uint64_t length) { zip_uint64_t i; for (i = 0; i < length; i++) { if (data[i] != '\0') { return 0; } } return 1; } static int write_nuls(zip_uint64_t n, FILE *f) { if (fwrite(MARK_NUL, 4, 1, f) != 1) { return -1; } return write_u64(n, f); } static int write_u64(zip_uint64_t u64, FILE *f) { zip_uint8_t b[8]; b[0] = (zip_uint8_t)((u64 >> 56) & 0xff); b[1] = (zip_uint8_t)((u64 >> 48) & 0xff); b[2] = (zip_uint8_t)((u64 >> 40) & 0xff); b[3] = (zip_uint8_t)((u64 >> 32) & 0xff); b[4] = (zip_uint8_t)((u64 >> 24) & 0xff); b[5] = (zip_uint8_t)((u64 >> 16) & 0xff); b[6] = (zip_uint8_t)((u64 >> 8) & 0xff); b[7] = (zip_uint8_t)(u64 & 0xff); return fwrite(b, 8, 1, f) == 1 ? 0 : -1; } static void hole_free(hole_t *hole) { if (hole == NULL) { return; } zip_error_fini(&hole->error); buffer_free(hole->in); buffer_free(hole->out); free(hole->fname); free(hole); } static hole_t * hole_new(const char *fname, int flags, zip_error_t *error) { hole_t *ctx = (hole_t *)malloc(sizeof(*ctx)); if (ctx == NULL) { zip_error_set(error, ZIP_ER_MEMORY, 0); return NULL; } if ((ctx->fname = strdup(fname)) == NULL) { free(ctx); zip_error_set(error, ZIP_ER_MEMORY, 0); return NULL; } if ((ctx->in = buffer_from_file(fname, flags, error)) == NULL) { free(ctx); return NULL; } zip_error_init(&ctx->error); ctx->out = NULL; return ctx; } static zip_int64_t source_hole_cb(void *ud, void *data, zip_uint64_t length, zip_source_cmd_t command) { hole_t *ctx = (hole_t *)ud; switch (command) { case ZIP_SOURCE_BEGIN_WRITE: ctx->out = buffer_new(); return 0; case ZIP_SOURCE_CLOSE: return 0; case ZIP_SOURCE_COMMIT_WRITE: if (buffer_to_file(ctx->out, ctx->fname, &ctx->error) < 0) { return -1; } buffer_free(ctx->in); ctx->in = ctx->out; ctx->out = NULL; return 0; case ZIP_SOURCE_ERROR: return zip_error_to_data(&ctx->error, data, length); case ZIP_SOURCE_FREE: hole_free(ctx); return 0; case ZIP_SOURCE_OPEN: ctx->in->offset = 0; return 0; case ZIP_SOURCE_READ: return buffer_read(ctx->in, data, length, &ctx->error); case ZIP_SOURCE_REMOVE: buffer_free(ctx->in); ctx->in = buffer_new(); buffer_free(ctx->out); ctx->out = NULL; (void)remove(ctx->fname); return 0; case ZIP_SOURCE_ROLLBACK_WRITE: buffer_free(ctx->out); ctx->out = NULL; return 0; case ZIP_SOURCE_SEEK: return buffer_seek(ctx->in, data, length, &ctx->error); case ZIP_SOURCE_SEEK_WRITE: return buffer_seek(ctx->out, data, length, &ctx->error); case ZIP_SOURCE_STAT: { zip_stat_t *st = ZIP_SOURCE_GET_ARGS(zip_stat_t, data, length, &ctx->error); if (st == NULL) { return -1; } /* TODO: return ENOENT if fname doesn't exist */ st->valid |= ZIP_STAT_SIZE; st->size = ctx->in->size; return 0; } case ZIP_SOURCE_TELL: return (zip_int64_t)ctx->in->offset; case ZIP_SOURCE_TELL_WRITE: return (zip_int64_t)ctx->out->offset; case ZIP_SOURCE_WRITE: return buffer_write(ctx->out, data, length, &ctx->error); case ZIP_SOURCE_SUPPORTS: return zip_source_make_command_bitmap(ZIP_SOURCE_BEGIN_WRITE, ZIP_SOURCE_COMMIT_WRITE, ZIP_SOURCE_CLOSE, ZIP_SOURCE_ERROR, ZIP_SOURCE_FREE, ZIP_SOURCE_OPEN, ZIP_SOURCE_READ, ZIP_SOURCE_REMOVE, ZIP_SOURCE_ROLLBACK_WRITE, ZIP_SOURCE_SEEK, ZIP_SOURCE_SEEK_WRITE, ZIP_SOURCE_STAT, ZIP_SOURCE_TELL, ZIP_SOURCE_TELL_WRITE, ZIP_SOURCE_WRITE, -1); default: zip_error_set(&ctx->error, ZIP_ER_OPNOTSUPP, 0); return -1; } } ================================================ FILE: external/libzip/regress/stat_index_cp437_guess.test ================================================ # guess CP437 file names and autoconvert them arguments test-cp437.zip stat 0 stat 1 stat 2 stat 3 stat 4 stat 5 stat 6 stat 7 stat 8 stat 9 stat 10 stat 11 stat 12 stat 13 stat 14 stat 15 return 0 file test-cp437.zip test-cp437.zip stdout name: '☺☻♥♦♣♠•◘○◙♂♀♪♫☼►' index: '0' size: '0' compressed size: '0' mtime: 'Fri Feb 17 2012 20:51:50' crc: '0' compression method: '0' encryption method: '0' name: '◄↕‼¶§▬↨↑↓→←∟↔▲▼ ' index: '1' size: '0' compressed size: '0' mtime: 'Fri Feb 17 2012 20:51:54' crc: '0' compression method: '0' encryption method: '0' name: '!"#$%&'()*+,-./0' index: '2' size: '0' compressed size: '0' mtime: 'Fri Feb 17 2012 20:51:58' crc: '0' compression method: '0' encryption method: '0' name: '123456789:;<=>?@' index: '3' size: '0' compressed size: '0' mtime: 'Fri Feb 17 2012 20:52:04' crc: '0' compression method: '0' encryption method: '0' name: 'ABCDEFGHIJKLMNOP' index: '4' size: '0' compressed size: '0' mtime: 'Fri Feb 17 2012 20:52:08' crc: '0' compression method: '0' encryption method: '0' name: 'QRSTUVWXYZ[\]^_`' index: '5' size: '0' compressed size: '0' mtime: 'Fri Feb 17 2012 20:52:12' crc: '0' compression method: '0' encryption method: '0' name: 'abcdefghijklmnop' index: '6' size: '0' compressed size: '0' mtime: 'Fri Feb 17 2012 20:52:18' crc: '0' compression method: '0' encryption method: '0' name: 'qrstuvwxyz{|}~⌂Ç' index: '7' size: '0' compressed size: '0' mtime: 'Fri Feb 17 2012 20:52:22' crc: '0' compression method: '0' encryption method: '0' name: 'üéâäàåçêëèïîìÄÅÉ' index: '8' size: '0' compressed size: '0' mtime: 'Fri Feb 17 2012 20:52:26' crc: '0' compression method: '0' encryption method: '0' name: 'æÆôöòûùÿÖÜ¢£¥₧ƒá' index: '9' size: '0' compressed size: '0' mtime: 'Fri Feb 17 2012 20:52:30' crc: '0' compression method: '0' encryption method: '0' name: 'íóúñѪº¿⌐¬½¼¡«»░' index: '10' size: '0' compressed size: '0' mtime: 'Fri Feb 17 2012 20:52:36' crc: '0' compression method: '0' encryption method: '0' name: '▒▓│┤╡╢╖╕╣║╗╝╜╛┐└' index: '11' size: '0' compressed size: '0' mtime: 'Fri Feb 17 2012 20:52:40' crc: '0' compression method: '0' encryption method: '0' name: '┴┬├─┼╞╟╚╔╩╦╠═╬╧╨' index: '12' size: '0' compressed size: '0' mtime: 'Fri Feb 17 2012 20:52:44' crc: '0' compression method: '0' encryption method: '0' name: '╤╥╙╘╒╓╫╪┘┌█▄▌▐▀α' index: '13' size: '0' compressed size: '0' mtime: 'Fri Feb 17 2012 20:52:50' crc: '0' compression method: '0' encryption method: '0' name: 'ßΓπΣσµτΦΘΩδ∞φε∩≡' index: '14' size: '0' compressed size: '0' mtime: 'Fri Feb 17 2012 20:52:54' crc: '0' compression method: '0' encryption method: '0' name: '±≥≤⌠⌡÷≈°∙·√ⁿ²■  ' index: '15' size: '0' compressed size: '0' mtime: 'Fri Feb 17 2012 20:53:02' crc: '0' compression method: '0' encryption method: '0' end-of-inline-data ================================================ FILE: external/libzip/regress/stat_index_cp437_raw.test ================================================ # get raw file names them from archive arguments -x -r test-cp437.zip stat 0 stat 1 stat 2 stat 3 stat 4 stat 5 stat 6 stat 7 stat 8 stat 9 stat 10 stat 11 stat 12 stat 13 stat 14 stat 15 return 0 file test-cp437.zip test-cp437.zip stdout name: '0102030405060708090a0b0c0d0e0f10' index: '0' size: '0' compressed size: '0' mtime: 'Fri Feb 17 2012 20:51:50' crc: '0' compression method: '0' encryption method: '0' name: '1112131415161718191a1b1c1d1e1f20' index: '1' size: '0' compressed size: '0' mtime: 'Fri Feb 17 2012 20:51:54' crc: '0' compression method: '0' encryption method: '0' name: '2122232425262728292a2b2c2d2e2f30' index: '2' size: '0' compressed size: '0' mtime: 'Fri Feb 17 2012 20:51:58' crc: '0' compression method: '0' encryption method: '0' name: '3132333435363738393a3b3c3d3e3f40' index: '3' size: '0' compressed size: '0' mtime: 'Fri Feb 17 2012 20:52:04' crc: '0' compression method: '0' encryption method: '0' name: '4142434445464748494a4b4c4d4e4f50' index: '4' size: '0' compressed size: '0' mtime: 'Fri Feb 17 2012 20:52:08' crc: '0' compression method: '0' encryption method: '0' name: '5152535455565758595a5b5c5d5e5f60' index: '5' size: '0' compressed size: '0' mtime: 'Fri Feb 17 2012 20:52:12' crc: '0' compression method: '0' encryption method: '0' name: '6162636465666768696a6b6c6d6e6f70' index: '6' size: '0' compressed size: '0' mtime: 'Fri Feb 17 2012 20:52:18' crc: '0' compression method: '0' encryption method: '0' name: '7172737475767778797a7b7c7d7e7f80' index: '7' size: '0' compressed size: '0' mtime: 'Fri Feb 17 2012 20:52:22' crc: '0' compression method: '0' encryption method: '0' name: '8182838485868788898a8b8c8d8e8f90' index: '8' size: '0' compressed size: '0' mtime: 'Fri Feb 17 2012 20:52:26' crc: '0' compression method: '0' encryption method: '0' name: '9192939495969798999a9b9c9d9e9fa0' index: '9' size: '0' compressed size: '0' mtime: 'Fri Feb 17 2012 20:52:30' crc: '0' compression method: '0' encryption method: '0' name: 'a1a2a3a4a5a6a7a8a9aaabacadaeafb0' index: '10' size: '0' compressed size: '0' mtime: 'Fri Feb 17 2012 20:52:36' crc: '0' compression method: '0' encryption method: '0' name: 'b1b2b3b4b5b6b7b8b9babbbcbdbebfc0' index: '11' size: '0' compressed size: '0' mtime: 'Fri Feb 17 2012 20:52:40' crc: '0' compression method: '0' encryption method: '0' name: 'c1c2c3c4c5c6c7c8c9cacbcccdcecfd0' index: '12' size: '0' compressed size: '0' mtime: 'Fri Feb 17 2012 20:52:44' crc: '0' compression method: '0' encryption method: '0' name: 'd1d2d3d4d5d6d7d8d9dadbdcdddedfe0' index: '13' size: '0' compressed size: '0' mtime: 'Fri Feb 17 2012 20:52:50' crc: '0' compression method: '0' encryption method: '0' name: 'e1e2e3e4e5e6e7e8e9eaebecedeeeff0' index: '14' size: '0' compressed size: '0' mtime: 'Fri Feb 17 2012 20:52:54' crc: '0' compression method: '0' encryption method: '0' name: 'f1f2f3f4f5f6f7f8f9fafbfcfdfeffff' index: '15' size: '0' compressed size: '0' mtime: 'Fri Feb 17 2012 20:53:02' crc: '0' compression method: '0' encryption method: '0' end-of-inline-data ================================================ FILE: external/libzip/regress/stat_index_cp437_strict.test ================================================ # strictly follow ZIP spec and expect CP437 file names, and autoconvert them arguments -s test-cp437.zip stat 0 stat 1 stat 2 stat 3 stat 4 stat 5 stat 6 stat 7 stat 8 stat 9 stat 10 stat 11 stat 12 stat 13 stat 14 stat 15 return 0 file test-cp437.zip test-cp437.zip stdout name: '☺☻♥♦♣♠•◘○◙♂♀♪♫☼►' index: '0' size: '0' compressed size: '0' mtime: 'Fri Feb 17 2012 20:51:50' crc: '0' compression method: '0' encryption method: '0' name: '◄↕‼¶§▬↨↑↓→←∟↔▲▼ ' index: '1' size: '0' compressed size: '0' mtime: 'Fri Feb 17 2012 20:51:54' crc: '0' compression method: '0' encryption method: '0' name: '!"#$%&'()*+,-./0' index: '2' size: '0' compressed size: '0' mtime: 'Fri Feb 17 2012 20:51:58' crc: '0' compression method: '0' encryption method: '0' name: '123456789:;<=>?@' index: '3' size: '0' compressed size: '0' mtime: 'Fri Feb 17 2012 20:52:04' crc: '0' compression method: '0' encryption method: '0' name: 'ABCDEFGHIJKLMNOP' index: '4' size: '0' compressed size: '0' mtime: 'Fri Feb 17 2012 20:52:08' crc: '0' compression method: '0' encryption method: '0' name: 'QRSTUVWXYZ[\]^_`' index: '5' size: '0' compressed size: '0' mtime: 'Fri Feb 17 2012 20:52:12' crc: '0' compression method: '0' encryption method: '0' name: 'abcdefghijklmnop' index: '6' size: '0' compressed size: '0' mtime: 'Fri Feb 17 2012 20:52:18' crc: '0' compression method: '0' encryption method: '0' name: 'qrstuvwxyz{|}~⌂Ç' index: '7' size: '0' compressed size: '0' mtime: 'Fri Feb 17 2012 20:52:22' crc: '0' compression method: '0' encryption method: '0' name: 'üéâäàåçêëèïîìÄÅÉ' index: '8' size: '0' compressed size: '0' mtime: 'Fri Feb 17 2012 20:52:26' crc: '0' compression method: '0' encryption method: '0' name: 'æÆôöòûùÿÖÜ¢£¥₧ƒá' index: '9' size: '0' compressed size: '0' mtime: 'Fri Feb 17 2012 20:52:30' crc: '0' compression method: '0' encryption method: '0' name: 'íóúñѪº¿⌐¬½¼¡«»░' index: '10' size: '0' compressed size: '0' mtime: 'Fri Feb 17 2012 20:52:36' crc: '0' compression method: '0' encryption method: '0' name: '▒▓│┤╡╢╖╕╣║╗╝╜╛┐└' index: '11' size: '0' compressed size: '0' mtime: 'Fri Feb 17 2012 20:52:40' crc: '0' compression method: '0' encryption method: '0' name: '┴┬├─┼╞╟╚╔╩╦╠═╬╧╨' index: '12' size: '0' compressed size: '0' mtime: 'Fri Feb 17 2012 20:52:44' crc: '0' compression method: '0' encryption method: '0' name: '╤╥╙╘╒╓╫╪┘┌█▄▌▐▀α' index: '13' size: '0' compressed size: '0' mtime: 'Fri Feb 17 2012 20:52:50' crc: '0' compression method: '0' encryption method: '0' name: 'ßΓπΣσµτΦΘΩδ∞φε∩≡' index: '14' size: '0' compressed size: '0' mtime: 'Fri Feb 17 2012 20:52:54' crc: '0' compression method: '0' encryption method: '0' name: '±≥≤⌠⌡÷≈°∙·√ⁿ²■  ' index: '15' size: '0' compressed size: '0' mtime: 'Fri Feb 17 2012 20:53:02' crc: '0' compression method: '0' encryption method: '0' end-of-inline-data ================================================ FILE: external/libzip/regress/stat_index_fileorder.test ================================================ # zip_open: entries ordered by central directory order arguments fileorder.zzip stat 0 stat 1 return 0 file fileorder.zzip fileorder.zip stdout name: 'file1' index: '0' size: '5' compressed size: '5' mtime: 'Fri Apr 27 2012 23:21:42' crc: '9ee760e5' compression method: '0' encryption method: '0' name: 'file2' index: '1' size: '5' compressed size: '5' mtime: 'Fri Apr 27 2012 23:21:44' crc: '7ee315f' compression method: '0' encryption method: '0' end-of-inline-data ================================================ FILE: external/libzip/regress/stat_index_streamed.test ================================================ # stat file in streamed zip file arguments streamed stat 0 file streamed streamed.zip return 0 stdout name: '-' index: '0' size: '2' compressed size: '4' mtime: 'Wed Apr 25 2012 10:20:38' crc: 'ddeaa107' compression method: '8' encryption method: '0' end-of-inline-data ================================================ FILE: external/libzip/regress/stat_index_streamed_zip64.test ================================================ # stat file in streamed zip file arguments streamed stat 0 file streamed streamed-zip64.zip return 0 stdout name: '-' index: '0' size: '2' compressed size: '4' mtime: 'Wed Apr 25 2012 10:20:38' crc: 'ddeaa107' compression method: '8' encryption method: '0' end-of-inline-data ================================================ FILE: external/libzip/regress/stat_index_utf8_guess.test ================================================ # guess UTF-8 file names arguments test-utf8.zip stat 0 return 0 file test-utf8.zip test-utf8.zip stdout name: 'ÄÖÜäöüßćçĉéèêëē' index: '0' size: '0' compressed size: '0' mtime: 'Sat Feb 18 2012 00:15:08' crc: '0' compression method: '0' encryption method: '0' end-of-inline-data ================================================ FILE: external/libzip/regress/stat_index_utf8_raw.test ================================================ # print UTF-8 file names arguments -r test-utf8.zip stat 0 return 0 file test-utf8.zip test-utf8.zip stdout name: 'ÄÖÜäöüßćçĉéèêëē' index: '0' size: '0' compressed size: '0' mtime: 'Sat Feb 18 2012 00:15:08' crc: '0' compression method: '0' encryption method: '0' end-of-inline-data ================================================ FILE: external/libzip/regress/stat_index_utf8_strict.test ================================================ # follow strict rules and convert UTF-8 as if it was CP437, but not # if the files are marked as having UTF-8 names arguments -s test-utf8.zip stat 0 return 0 file test-utf8.zip test-utf8.zip stdout name: 'ÄÖÜäöüßćçĉéèêëē' index: '0' size: '0' compressed size: '0' mtime: 'Sat Feb 18 2012 00:15:08' crc: '0' compression method: '0' encryption method: '0' end-of-inline-data ================================================ FILE: external/libzip/regress/stat_index_utf8_unmarked_strict.test ================================================ # follow strict rules and convert UTF-8 as if it was CP437, # if not marked otherwise (in this case: not marked) arguments -s test-utf8-unmarked.zip stat 0 return 0 file test-utf8-unmarked.zip test-utf8-unmarked.zip stdout name: '├ä├û├£├ñ├╢├╝├ƒ─ç├º─ë├⌐├¿├¬├½─ô' index: '0' size: '0' compressed size: '0' mtime: 'Sat Feb 18 2012 00:15:08' crc: '0' compression method: '0' encryption method: '0' end-of-inline-data ================================================ FILE: external/libzip/regress/stat_index_zip64.test ================================================ # stat file in zip64 zip file arguments bigzero stat 0 file bigzero bigzero.zip return 0 stdout name: 'bigzero' index: '0' size: '4294967296' compressed size: '4168157' mtime: 'Thu Mar 15 2012 14:54:06' crc: 'd202ef8d' compression method: '8' encryption method: '0' end-of-inline-data ================================================ FILE: external/libzip/regress/testfile.txt ================================================ ================================================ FILE: external/libzip/regress/truncate_empty_keep.test ================================================ # delete last entry in zip archive return 0 arguments -t testfile.zzip set_archive_flag create-or-keep-file-for-empty-archive 1 file testfile.zzip testfile.zip testempty.zip ================================================ FILE: external/libzip/regress/tryopen.c ================================================ /* tryopen.c -- tool for tests that try opening zip archives Copyright (C) 1999-2024 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #include #include #ifndef HAVE_GETOPT #include "getopt.h" #endif #include "zip.h" #define TRYOPEN_USAGE \ "usage: %s [-cent] file\n\n" \ "\t-c\tcheck consistency\n" \ "\t-e\texclusively open archive\n" \ "\t-n\tcreate new file\n" \ "\t-s\tprint error string\n" \ "\t-t\ttruncate file to size 0\n" int main(int argc, char *argv[]) { const char *fname; zip_t *z; int c, flags, ze; zip_int64_t count; int error_count; zip_error_t error; int error_strings = 0; flags = 0; while ((c = getopt(argc, argv, "censt")) != -1) { switch (c) { case 'c': flags |= ZIP_CHECKCONS; break; case 'e': flags |= ZIP_EXCL; break; case 'n': flags |= ZIP_CREATE; break; case 's': error_strings = 1; break; case 't': flags |= ZIP_TRUNCATE; break; default: fprintf(stderr, TRYOPEN_USAGE, argv[0]); return 1; } } error_count = 0; for (; optind < argc; optind++) { fname = argv[optind]; errno = 0; if ((z = zip_open(fname, flags, &ze)) != NULL) { count = zip_get_num_entries(z, 0); printf("opening '%s' succeeded, %" PRIu64 " entries\n", fname, count); zip_close(z); continue; } zip_error_init_with_code(&error, ze); printf("opening '%s' returned error ", fname); if (error_strings) { printf("%s", zip_error_strerror(&error)); } else { printf("%d", ze); switch (zip_error_system_type(&error)) { case ZIP_ET_SYS: case ZIP_ET_LIBZIP: printf("/%d", zip_error_code_system(&error)); break; default: break; } } printf("\n"); error_count++; } if (error_count > 0) fprintf(stderr, "%d errors\n", error_count); return error_count ? 1 : 0; } ================================================ FILE: external/libzip/regress/unchange-delete-namelocate.test ================================================ # namelocate after a file has been deleted and unchanged should succeed. arguments test2.zip delete 0 unchange 0 name_locate testfile.txt 0 return 0 file test2.zip test2.zip stdout name 'testfile.txt' using flags '0' found at index 0 end-of-inline-data ================================================ FILE: external/libzip/regress/utf-8-standardization.test ================================================ # replace file contents and make UTF-8 name return 0 arguments testfile.zzip replace_file_contents 0 "Some new content for the file." set_file_mtime 0 1406885162 file testfile.zzip utf-8-standardization-input.zip utf-8-standardization-output.zip ================================================ FILE: external/libzip/regress/want_torrentzip_stat.test ================================================ # check that wanting to convert a file to torrentzip changes stat information return 0 arguments testfile.zzip stat 0 set_archive_flag want-torrentzip 1 stat 0 unchange_all stat 0 file testfile.zzip testfile.zip stdout name: 'testfile.txt' index: '0' size: '0' compressed size: '0' mtime: 'Fri Jul 15 2005 16:37:14' crc: '0' compression method: '0' encryption method: '0' name: 'testfile.txt' index: '0' size: '0' mtime: 'Tue Dec 24 1996 23:32:00' crc: '0' compression method: '8' encryption method: '0' name: 'testfile.txt' index: '0' size: '0' compressed size: '0' mtime: 'Fri Jul 15 2005 16:37:14' crc: '0' compression method: '0' encryption method: '0' end-of-inline-data ================================================ FILE: external/libzip/regress/zip-in-archive-comment.test ================================================ # stat file in zip that contains archive comment to find out if it detected the right one of the two arguments zip-in-archive-comment.zip stat 0 file zip-in-archive-comment.zip zip-in-archive-comment.zip return 0 stdout name: 'test' index: '0' size: '5' compressed size: '5' mtime: 'Mon Oct 06 2003 15:46:42' crc: '3bb935c6' compression method: '0' encryption method: '0' end-of-inline-data ================================================ FILE: external/libzip/regress/zip64-in-archive-comment.test ================================================ # stat file in zip that contains archive comment to find out if it detected the right one of the two arguments zip64-in-archive-comment.zip stat 0 file zip64-in-archive-comment.zip zip64-in-archive-comment.zip return 0 stdout name: 'testfile.txt' index: '0' size: '0' compressed size: '0' mtime: 'Fri Jul 15 2005 16:37:14' crc: '0' compression method: '0' encryption method: '0' end-of-inline-data ================================================ FILE: external/libzip/regress/zip64_creation.test ================================================ # create big zip64 zip file from scratch arguments bigzero.zip add_nul bigzero 4294967296 file bigzero.zip {} bigzero.zip return 0 ================================================ FILE: external/libzip/regress/zip64_stored_creation.test ================================================ # create big zip64 zip file from scratch arguments -H bigstored.zh add_nul bigzero 4294967296 set_file_compression 0 0 0 set_file_mtime 0 0 add_nul smallzero 16384 set_file_compression 1 0 0 set_file_mtime 1 0 file bigstored.zh {} bigstored.zh return 0 ================================================ FILE: external/libzip/regress/zipcmp_zip_dir.test ================================================ # compare zip with directory features HAVE_FTS_H program zipcmp mkdir a mkdir a/dir-with-file mkdir a/empty-dir-in-dir arguments zipcmp_zip_dir.zip a file zipcmp_zip_dir.zip zipcmp_zip_dir.zip return 1 stdout --- zipcmp_zip_dir.zip +++ a - directory '00-empty-dir/' - file 'dir-with-file/a', size 1, crc e8b7be43, mtime 1610623116 + directory 'empty-dir-in-dir/' - directory 'empty-dir/' end-of-inline-data ================================================ FILE: external/libzip/regress/zipcmp_zip_dir_slash.test ================================================ # compare zip with directory with trailing slash features HAVE_FTS_H program zipcmp mkdir a mkdir a/dir-with-file mkdir a/empty-dir-in-dir arguments zipcmp_zip_dir.zip a/ file zipcmp_zip_dir.zip zipcmp_zip_dir.zip return 1 stdout --- zipcmp_zip_dir.zip +++ a/ - directory '00-empty-dir/' - file 'dir-with-file/a', size 1, crc e8b7be43, mtime 1610623116 + directory 'empty-dir-in-dir/' - directory 'empty-dir/' end-of-inline-data ================================================ FILE: external/libzip/regress/ziptool_regress.c ================================================ #include "zip.h" #include #define ZIP_MIN(a, b) ((a) < (b) ? (a) : (b)) #define FOR_REGRESS typedef enum { SOURCE_TYPE_NONE, SOURCE_TYPE_IN_MEMORY, SOURCE_TYPE_HOLE } source_type_t; source_type_t source_type = SOURCE_TYPE_NONE; zip_uint64_t fragment_size = 0; zip_file_t *z_files[16]; unsigned int z_files_count; int commands_from_stdin = 0; static int add_nul(char *argv[]); static int cancel(char *argv[]); static int extract_as(char *argv[]); static int regress_fopen(char *argv[]); static int regress_fread(char *argv[]); static int regress_fseek(char *argv[]); static int is_seekable(char *argv[]); static int unchange_one(char *argv[]); static int unchange_all(char *argv[]); static int zin_close(char *argv[]); #define OPTIONS_REGRESS "F:Himx" #define USAGE_REGRESS " [-Himx] [-F fragment-size]" #define GETOPT_REGRESS \ case 'H': \ source_type = SOURCE_TYPE_HOLE; \ break; \ case 'i': \ commands_from_stdin = 1; \ break; \ case 'm': \ source_type = SOURCE_TYPE_IN_MEMORY; \ break; \ case 'F': \ fragment_size = strtoull(optarg, NULL, 10); \ break; \ case 'x': \ hex_encoded_filenames = 1; \ break; /* clang-format off */ #define DISPATCH_REGRESS \ {"add_nul", 2, "name length", "add NUL bytes", add_nul}, \ {"cancel", 1, "limit", "cancel writing archive when limit% have been written (calls print_progress)", cancel}, \ {"extract_as", 2, "index name", "extract file data to given file name", extract_as}, \ {"fopen", 1, "name", "open archive entry", regress_fopen}, \ {"fread", 2, "file_index length", "read from fopened file and print", regress_fread}, \ {"fseek", 3, "file_index offset whence", "seek in fopened file", regress_fseek}, \ {"is_seekable", 1, "index", "report if entry is seekable", is_seekable}, \ {"unchange", 1, "index", "revert changes for entry", unchange_one}, \ {"unchange_all", 0, "", "revert all changes", unchange_all}, \ {"zin_close", 1, "index", "close input zip_source (for internal tests)", zin_close} #define PRECLOSE_REGRESS \ do { \ unsigned int file_idx = 0; \ for (file_idx = 0; file_idx < z_files_count; ++file_idx) { \ if (zip_fclose (z_files[file_idx]) != 0) { \ err = 1; \ } \ } \ } \ while (0) /* clang-format on */ #define MAX_STDIN_ARGC 128 #define MAX_STDIN_LENGTH 8192 char* stdin_argv[MAX_STDIN_ARGC]; static char stdin_line[MAX_STDIN_LENGTH]; int get_stdin_commands(void); #define REGRESS_PREPARE_ARGS \ if (commands_from_stdin) { \ argc = get_stdin_commands(); \ arg = 0; \ argv = stdin_argv; \ } zip_t *ziptool_open(const char *archive, int flags, zip_error_t *error, zip_uint64_t offset, zip_uint64_t len); #include "ziptool.c" int get_stdin_commands(void) { int argc = 0; char *p, *word; fgets(stdin_line, sizeof(stdin_line), stdin); word = p = stdin_line; while (1) { if (*p == ' ' || *p == '\n') { *p = '\0'; if (word[0] != '\0') { stdin_argv[argc] = word; argc += 1; if (argc >= MAX_STDIN_ARGC) { break; } } word = p + 1; } else if (*p == '\0') { if (word[0] != '\0') { stdin_argv[argc] = word; argc += 1; } break; } p += 1; } return argc; } zip_source_t *memory_src = NULL; static int get_whence(const char *str); zip_source_t *source_hole_create(const char *, int flags, zip_error_t *); static zip_t *read_to_memory(const char *archive, int flags, zip_error_t *error, zip_source_t **srcp); static zip_source_t *source_nul(zip_t *za, zip_uint64_t length); static int add_nul(char *argv[]) { zip_source_t *zs; zip_uint64_t length = strtoull(argv[1], NULL, 10); if ((zs = source_nul(za, length)) == NULL) { fprintf(stderr, "can't create zip_source for length: %s\n", zip_strerror(za)); return -1; } if (zip_file_add(za, argv[0], zs, 0) == -1) { zip_source_free(zs); fprintf(stderr, "can't add file '%s': %s\n", argv[0], zip_strerror(za)); return -1; } return 0; } static int cancel_callback(zip_t *archive, void *ud) { if (progress_userdata.percentage >= progress_userdata.limit) { return -1; } return 0; } static int cancel(char *argv[]) { zip_int64_t percent; percent = strtoll(argv[0], NULL, 10); if (percent > 100 || percent < 0) { fprintf(stderr, "invalid percentage '%" PRId64 "' for cancel (valid: 0 <= x <= 100)\n", percent); return -1; } progress_userdata.limit = ((double)percent) / 100; zip_register_cancel_callback_with_state(za, cancel_callback, NULL, NULL); /* needs the percentage updates from print_progress */ print_progress(argv); return 0; } static int extract_as(char *argv[]) { zip_uint64_t idx; FILE *fp; int ret; idx = strtoull(argv[0], NULL, 10); if ((fp=fopen(argv[1], "wb")) == NULL) { fprintf(stderr, "can't open output file '%s': %s", argv[1], strerror(errno)); return -1; } ret = cat_impl_backend(idx, 0, -1, fp); if (fclose(fp) != 0) { fprintf(stderr, "can't close output file '%s': %s", argv[1], strerror(errno)); ret = -1; } return ret; } static int is_seekable(char *argv[]) { zip_uint64_t idx; zip_file_t *zf; idx = strtoull(argv[0], NULL, 10); if ((zf = zip_fopen_index(za, idx, 0)) == NULL) { fprintf(stderr, "can't open file at index '%" PRIu64 "': %s\n", idx, zip_strerror(za)); return -1; } switch (zip_file_is_seekable(zf)) { case -1: fprintf(stderr, "can't check if file %" PRIu64 " is seekable: %s\n", idx, zip_strerror(za)); return -1; case 0: printf("%" PRIu64 ": NOT seekable\n", idx); break; case 1: printf("%" PRIu64 ": seekable\n", idx); break; } return 0; } static int regress_fseek(char *argv[]) { zip_uint64_t file_idx; zip_file_t *zf; zip_int64_t offset; int whence; file_idx = strtoull(argv[0], NULL, 10); offset = strtoll(argv[1], NULL, 10); whence = get_whence(argv[2]); if (file_idx >= z_files_count || z_files[file_idx] == NULL) { fprintf(stderr, "trying to seek in invalid opened file\n"); return -1; } zf = z_files[file_idx]; if (zip_fseek(zf, offset, whence) == -1) { fprintf(stderr, "can't seek in file %" PRIu64 ": %s\n", file_idx, zip_strerror(za)); return -1; } return 0; } static int unchange_all(char *argv[]) { if (zip_unchange_all(za) < 0) { fprintf(stderr, "can't revert changes to archive: %s\n", zip_strerror(za)); return -1; } return 0; } static int unchange_one(char *argv[]) { zip_uint64_t idx; idx = strtoull(argv[0], NULL, 10); if (zip_unchange(za, idx) < 0) { fprintf(stderr, "can't revert changes for entry %" PRIu64 ": %s", idx, zip_strerror(za)); return -1; } return 0; } static int zin_close(char *argv[]) { zip_uint64_t idx; idx = strtoull(argv[0], NULL, 10); if (idx >= z_in_count) { fprintf(stderr, "invalid argument '%" PRIu64 "', only %u zip sources open\n", idx, z_in_count); return -1; } if (zip_close(z_in[idx]) < 0) { fprintf(stderr, "can't close source archive: %s\n", zip_strerror(z_in[idx])); return -1; } z_in[idx] = z_in[z_in_count]; z_in_count--; return 0; } static int regress_fopen(char *argv[]) { if (z_files_count >= (sizeof(z_files) / sizeof(*z_files))) { fprintf(stderr, "too many open files\n"); return -1; } if ((z_files[z_files_count] = zip_fopen(za, argv[0], 0)) == NULL) { fprintf(stderr, "can't open entry '%s' from input archive: %s\n", argv[0], zip_strerror(za)); return -1; } printf("opened '%s' as file %u\n", argv[0], z_files_count); z_files_count += 1; return 0; } static int regress_fread(char *argv[]) { zip_uint64_t file_idx; zip_uint64_t length; char buf[8192]; zip_int64_t n; zip_file_t *f; file_idx = strtoull(argv[0], NULL, 10); length = strtoull(argv[1], NULL, 10); if (file_idx >= z_files_count || z_files[file_idx] == NULL) { fprintf(stderr, "trying to read from invalid opened file\n"); return -1; } f = z_files[file_idx]; while (length > 0) { zip_uint64_t to_read; if (length > sizeof (buf)) { to_read = sizeof (buf); } else { to_read = length; } n = zip_fread(f, buf, to_read); if (n < 0) { fprintf(stderr, "can't read opened file %" PRIu64 ": %s\n", file_idx, zip_file_strerror(f)); return -1; } if (n == 0) { #if 0 fprintf(stderr, "premature end of opened file %" PRIu64 "\n", file_idx); return -1; #else break; #endif } if (fwrite(buf, (size_t)n, 1, stdout) != 1) { fprintf(stderr, "can't write file contents to stdout: %s\n", strerror(errno)); return -1; } length -= n; } return 0; } static zip_t * read_hole(const char *archive, int flags, zip_error_t *error) { zip_source_t *src = NULL; zip_t *zs = NULL; if (strcmp(archive, "/dev/stdin") == 0) { zip_error_set(error, ZIP_ER_OPNOTSUPP, 0); return NULL; } if ((src = source_hole_create(archive, flags, error)) == NULL || (zs = zip_open_from_source(src, flags, error)) == NULL) { zip_source_free(src); } return zs; } static int get_whence(const char *str) { if (strcasecmp(str, "set") == 0) { return SEEK_SET; } else if (strcasecmp(str, "cur") == 0) { return SEEK_CUR; } else if (strcasecmp(str, "end") == 0) { return SEEK_END; } else { return 100; /* invalid */ } } static zip_t * read_to_memory(const char *archive, int flags, zip_error_t *error, zip_source_t **srcp) { zip_source_t *src; zip_t *zb; FILE *fp; if (strcmp(archive, "/dev/stdin") == 0) { zip_error_set(error, ZIP_ER_OPNOTSUPP, 0); return NULL; } if ((fp = fopen(archive, "rb")) == NULL) { if (errno == ENOENT) { src = zip_source_buffer_create(NULL, 0, 0, error); } else { zip_error_set(error, ZIP_ER_OPEN, errno); return NULL; } } else { struct stat st; if (fstat(fileno(fp), &st) < 0) { fclose(fp); zip_error_set(error, ZIP_ER_OPEN, errno); return NULL; } if (fragment_size == 0) { char *buf; if ((buf = malloc((size_t)st.st_size)) == NULL) { fclose(fp); zip_error_set(error, ZIP_ER_MEMORY, 0); return NULL; } if (fread(buf, (size_t)st.st_size, 1, fp) < 1) { free(buf); fclose(fp); zip_error_set(error, ZIP_ER_READ, errno); return NULL; } src = zip_source_buffer_create(buf, (zip_uint64_t)st.st_size, 1, error); if (src == NULL) { free(buf); } } else { zip_uint64_t nfragments, i, left; zip_buffer_fragment_t *fragments; nfragments = ((size_t)st.st_size + fragment_size - 1) / fragment_size; if ((fragments = malloc(sizeof(fragments[0]) * nfragments)) == NULL) { fclose(fp); zip_error_set(error, ZIP_ER_MEMORY, 0); return NULL; } for (i = 0; i < nfragments; i++) { left = ZIP_MIN(fragment_size, (size_t)st.st_size - i * fragment_size); if ((fragments[i].data = malloc(left)) == NULL) { #ifndef __clang_analyzer__ /* fragments is initialized up to i - 1*/ while (--i > 0) { free(fragments[i].data); } #endif free(fragments); fclose(fp); zip_error_set(error, ZIP_ER_MEMORY, 0); return NULL; } fragments[i].length = left; if (fread(fragments[i].data, left, 1, fp) < 1) { #ifndef __clang_analyzer__ /* fragments is initialized up to i - 1*/ while (--i > 0) { free(fragments[i].data); } #endif free(fragments); fclose(fp); zip_error_set(error, ZIP_ER_READ, errno); return NULL; } } src = zip_source_buffer_fragment_create(fragments, nfragments, 1, error); if (src == NULL) { for (i = 0; i < nfragments; i++) { free(fragments[i].data); } free(fragments); fclose(fp); return NULL; } free(fragments); } fclose(fp); } if (src == NULL) { return NULL; } zb = zip_open_from_source(src, flags, error); if (zb == NULL) { zip_source_free(src); return NULL; } zip_source_keep(src); *srcp = src; return zb; } typedef struct source_nul { zip_error_t error; zip_uint64_t length; zip_uint64_t offset; } source_nul_t; static zip_int64_t source_nul_cb(void *ud, void *data, zip_uint64_t length, zip_source_cmd_t command) { source_nul_t *ctx = (source_nul_t *)ud; switch (command) { case ZIP_SOURCE_CLOSE: return 0; case ZIP_SOURCE_ERROR: return zip_error_to_data(&ctx->error, data, length); case ZIP_SOURCE_FREE: free(ctx); return 0; case ZIP_SOURCE_OPEN: ctx->offset = 0; return 0; case ZIP_SOURCE_READ: if (length > ZIP_INT64_MAX) { zip_error_set(&ctx->error, ZIP_ER_INVAL, 0); return -1; } if (length > ctx->length - ctx->offset) { length = ctx->length - ctx->offset; } memset(data, 0, length); ctx->offset += length; return (zip_int64_t)length; case ZIP_SOURCE_STAT: { zip_stat_t *st = ZIP_SOURCE_GET_ARGS(zip_stat_t, data, length, &ctx->error); if (st == NULL) { return -1; } st->valid |= ZIP_STAT_SIZE; st->size = ctx->length; return 0; } case ZIP_SOURCE_SUPPORTS: return zip_source_make_command_bitmap(ZIP_SOURCE_CLOSE, ZIP_SOURCE_ERROR, ZIP_SOURCE_FREE, ZIP_SOURCE_OPEN, ZIP_SOURCE_READ, ZIP_SOURCE_STAT, -1); default: zip_error_set(&ctx->error, ZIP_ER_OPNOTSUPP, 0); return -1; } } static zip_source_t * source_nul(zip_t *zs, zip_uint64_t length) { source_nul_t *ctx; zip_source_t *src; if ((ctx = (source_nul_t *)malloc(sizeof(*ctx))) == NULL) { zip_error_set(zip_get_error(zs), ZIP_ER_MEMORY, 0); return NULL; } zip_error_init(&ctx->error); ctx->length = length; ctx->offset = 0; if ((src = zip_source_function(zs, source_nul_cb, ctx)) == NULL) { free(ctx); return NULL; } return src; } static int write_memory_src_to_file(const char *archive, zip_source_t *src) { zip_stat_t zst; char *buf; FILE *fp; if (zip_source_stat(src, &zst) < 0) { fprintf(stderr, "zip_source_stat on buffer failed: %s\n", zip_error_strerror(zip_source_error(src))); return -1; } if (zip_source_open(src) < 0) { if (zip_error_code_zip(zip_source_error(src)) == ZIP_ER_DELETED) { if (unlink(archive) < 0 && errno != ENOENT) { fprintf(stderr, "unlink failed: %s\n", strerror(errno)); return -1; } return 0; } fprintf(stderr, "zip_source_open on buffer failed: %s\n", zip_error_strerror(zip_source_error(src))); return -1; } if ((buf = malloc(zst.size)) == NULL) { fprintf(stderr, "malloc failed: %s\n", strerror(errno)); zip_source_close(src); return -1; } if (zip_source_read(src, buf, zst.size) < (zip_int64_t)zst.size) { fprintf(stderr, "zip_source_read on buffer failed: %s\n", zip_error_strerror(zip_source_error(src))); zip_source_close(src); free(buf); return -1; } zip_source_close(src); if ((fp = fopen(archive, "wb")) == NULL) { fprintf(stderr, "fopen failed: %s\n", strerror(errno)); free(buf); return -1; } if (fwrite(buf, zst.size, 1, fp) < 1) { fprintf(stderr, "fwrite failed: %s\n", strerror(errno)); free(buf); fclose(fp); return -1; } free(buf); if (fclose(fp) != 0) { fprintf(stderr, "fclose failed: %s\n", strerror(errno)); return -1; } return 0; } zip_t * ziptool_open(const char *archive, int flags, zip_error_t *error, zip_uint64_t offset, zip_uint64_t len) { switch (source_type) { case SOURCE_TYPE_NONE: za = read_from_file(archive, flags, error, offset, len); break; case SOURCE_TYPE_IN_MEMORY: za = read_to_memory(archive, flags, error, &memory_src); break; case SOURCE_TYPE_HOLE: za = read_hole(archive, flags, error); break; } return za; } int ziptool_post_close(const char *archive) { if (source_type == SOURCE_TYPE_IN_MEMORY) { if (write_memory_src_to_file(archive, memory_src) < 0) { return -1; } zip_source_free(memory_src); } return 0; } ================================================ FILE: external/libzip/src/CMakeLists.txt ================================================ check_function_exists(getopt HAVE_GETOPT) foreach(PROGRAM zipcmp zipmerge ziptool) add_executable(${PROGRAM} ${PROGRAM}.c) target_link_libraries(${PROGRAM} zip) target_include_directories(${PROGRAM} PRIVATE BEFORE ${PROJECT_SOURCE_DIR}/lib ${PROJECT_BINARY_DIR}) if(LIBZIP_DO_INSTALL) install(TARGETS ${PROGRAM} EXPORT ${PROJECT_NAME}-bin-targets DESTINATION bin) endif() if(NOT HAVE_GETOPT) target_sources(${PROGRAM} PRIVATE getopt.c) endif(NOT HAVE_GETOPT) endforeach() target_sources(zipcmp PRIVATE diff_output.c) target_link_libraries(zipcmp ${FTS_LIB} ZLIB::ZLIB) ================================================ FILE: external/libzip/src/diff_output.c ================================================ #include "diff_output.h" #include #include #include #include #include "compat.h" static void ensure_header(diff_output_t *output) { if (output->archive_names[0] != NULL) { printf("--- %s\n", output->archive_names[0]); printf("+++ %s\n", output->archive_names[1]); output->archive_names[0] = NULL; output->archive_names[1] = NULL; } } void diff_output_init(diff_output_t *output, int verbose, char *const archive_names[]) { output->archive_names[0] = archive_names[0]; output->archive_names[1] = archive_names[1]; output->verbose = verbose; output->file_name = NULL; output->file_size = 0; output->file_crc = 0; output->file_mtime = 0; } void diff_output_start_file(diff_output_t *output, const char *name, zip_uint64_t size, zip_uint32_t crc, zip_uint64_t mtime) { output->file_name = name; output->file_size = size; output->file_crc = crc; output->file_mtime = mtime; } void diff_output_end_file(diff_output_t *output) { output->file_name = NULL; } void diff_output(diff_output_t *output, int side, const char *fmt, ...) { va_list ap; if (!output->verbose) { return; } ensure_header(output); if (output->file_name != NULL) { diff_output_file(output, ' ', output->file_name, output->file_size, output->file_crc, output->file_mtime); output->file_name = NULL; } printf("%c ", side); va_start(ap, fmt); vprintf(fmt, ap); va_end(ap); printf("\n"); } void diff_output_file(diff_output_t *output, char side, const char *name, zip_uint64_t size, zip_uint32_t crc, zip_uint64_t mtime) { if (!output->verbose) { return; } ensure_header(output); if (size == 0 && crc == 0 && name[0] != '\0' && name[strlen(name) - 1] == '/') { printf("%c directory '%s'\n", side, name); } else { printf("%c file '%s', size %" PRIu64 ", crc %08x, mtime %" PRIu64 "\n", side, name, size, crc, mtime); } } #define MAX_BYTES 64 void diff_output_data(diff_output_t *output, int side, const zip_uint8_t *data, zip_uint64_t data_length, const char *fmt, ...) { char prefix[1024]; char hexdata[MAX_BYTES * 3 + 6]; size_t i, offset; va_list ap; if (!output->verbose) { return; } offset = 0; for (i = 0; i < data_length; i++) { hexdata[offset++] = (i == 0 ? '<' : ' '); if (i >= MAX_BYTES) { snprintf(hexdata + offset, sizeof(hexdata) - offset, "..."); break; } snprintf(hexdata + offset, sizeof(hexdata) - offset, "%02x", data[i]); offset += 2; } hexdata[offset++] = '>'; hexdata[offset] = '\0'; va_start(ap, fmt); vsnprintf(prefix, sizeof(prefix), fmt, ap); va_end(ap); prefix[sizeof(prefix) - 1] = '\0'; diff_output(output, side, "%s, length %" PRIu64 ", data %s", prefix, data_length, hexdata); } ================================================ FILE: external/libzip/src/diff_output.h ================================================ #ifndef HAD_DIFF_OUTPUT_H #define HAD_DIFF_OUTPUT_H #include typedef struct { const char *archive_names[2]; const char *file_name; zip_uint64_t file_size; zip_uint32_t file_crc; zip_uint64_t file_mtime; int verbose; } diff_output_t; #if defined(__GNUC__) && __GNUC__ >= 4 #define PRINTF_LIKE(n, m) __attribute__((__format__(__printf__, n, m))) #else #define PRINTF_LIKE(n, m) #endif void diff_output_init(diff_output_t *output, int verbose, char *const archive_names[]); void diff_output_start_file(diff_output_t *output, const char *name, zip_uint64_t size, zip_uint32_t crc, zip_uint64_t mtime); void diff_output_end_file(diff_output_t *output); void diff_output(diff_output_t *output, int side, const char *fmt, ...) PRINTF_LIKE(3, 4); void diff_output_data(diff_output_t *output, int side, const zip_uint8_t *data, zip_uint64_t data_length, const char *fmt, ...) PRINTF_LIKE(5, 6); void diff_output_file(diff_output_t *output, char side, const char *name, zip_uint64_t size, zip_uint32_t crc, zip_uint64_t mtime); #endif /* HAD_DIFF_OUTPUT_H */ ================================================ FILE: external/libzip/src/getopt.c ================================================ /* * getopt.c -- * * Standard UNIX getopt function. Code is from BSD. * * Copyright (c) 1987-2002 The Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * A. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * B. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * C. Neither the names of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* #if !defined(lint) * static char sccsid[] = "@(#)getopt.c 8.2 (Berkeley) 4/2/94"; * #endif */ #include #include #include #include "getopt.h" int opterr = 1, /* if error message should be printed */ optind = 1, /* index into parent argv vector */ optopt, /* character checked for validity */ optreset; /* reset getopt */ char *optarg; /* argument associated with option */ #define BADCH (int)'?' #define BADARG (int)':' #define EMSG "" /* * getopt -- * Parse argc/argv argument vector. */ int getopt(int nargc, char *const *nargv, const char *ostr) { static char *place = EMSG; /* option letter processing */ char *oli; /* option letter list index */ if (optreset || !*place) { /* update scanning pointer */ optreset = 0; if (optind >= nargc || *(place = nargv[optind]) != '-') { place = EMSG; return (EOF); } if (place[1] && *++place == '-') { /* found "--" */ ++optind; place = EMSG; return (EOF); } } /* option letter okay? */ if ((optopt = (int)*place++) == (int)':' || !(oli = (char *)strchr(ostr, optopt))) { /* * if the user didn't specify '-' as an option, * assume it means EOF. */ if (optopt == (int)'-') return (EOF); if (!*place) ++optind; if (opterr && *ostr != ':') (void)fprintf(stderr, "illegal option -- %c\n", optopt); return (BADCH); } if (*++oli != ':') { /* don't need argument */ optarg = NULL; if (!*place) ++optind; } else { /* need an argument */ if (*place) /* no white space */ optarg = place; else if (nargc <= ++optind) { /* no arg */ place = EMSG; if (*ostr == ':') return (BADARG); if (opterr) (void)fprintf(stderr, "option requires an argument -- %c\n", optopt); return (BADCH); } else /* white space */ optarg = nargv[optind]; place = EMSG; ++optind; } return (optopt); /* dump back option letter */ } ================================================ FILE: external/libzip/src/getopt.h ================================================ #ifndef _HAD_GETOPT_H #define _HAD_GETOPT_H /* getopt.h -- header for getopt() replacement function Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifdef __cplusplus extern "C" { #endif extern char *optarg; extern int optind; extern int opterr; extern int getopt(int, char *const *, const char *); #ifdef __cplusplus } #endif #endif /* _HAD_GETOPT_H */ ================================================ FILE: external/libzip/src/zipcmp.c ================================================ /* zipcmp.c -- compare zip files Copyright (C) 2003-2024 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #include #include #include #include #include #ifdef HAVE_STRINGS_H #include #endif #ifdef HAVE_FTS_H #include #endif #include #ifndef HAVE_GETOPT #include "getopt.h" #endif #include "zip.h" #include "compat.h" #include "diff_output.h" struct archive { const char *name; zip_t *za; zip_uint64_t nentry; struct entry *entry; const char *comment; size_t comment_length; }; struct ef { const char *name; zip_uint16_t flags; zip_uint16_t id; zip_uint16_t size; const zip_uint8_t *data; }; struct entry { char *name; zip_uint64_t size; zip_uint32_t crc; zip_uint32_t comp_method; time_t last_modification_time; struct ef *extra_fields; zip_uint16_t n_extra_fields; const char *comment; zip_uint32_t comment_length; }; typedef struct { uint32_t value; const char *const name; } enum_map_t; const enum_map_t comp_methods[] = {{0, "Stored (no compression)"}, {1, "Shrunk"}, {2, "Reduced with compression factor 1"}, {3, "Reduced with compression factor 2"}, {4, "Reduced with compression factor 3"}, {5, "Reduced with compression factor 4"}, {6, "Imploded"}, {7, "Reserved for Tokenizing compression algorithm"}, {8, "Deflated"}, {9, "Enhanced Deflating using Deflate64(tm)"}, {10, "PKWARE Data Compression Library Imploding (old IBM TERSE)"}, {11, "11 (Reserved by PKWARE)"}, {12, "BZIP2"}, {13, "13 (Reserved by PKWARE)"}, {14, "LZMA (EFS)"}, {15, "15 (Reserved by PKWARE)"}, {16, "16 (Reserved by PKWARE)"}, {17, "17 (Reserved by PKWARE)"}, {18, "IBM TERSE (new)"}, {19, "IBM LZ77 z Architecture (PFS)"}, {20, "Zstandard compressed data (obsolete)"}, {93, "Zstandard compressed data"}, {95, "XZ compressed data"}, {97, "WavPack compressed data"}, {98, "PPMd version I, Rev 1"}, {99, "WinZIP AES Encryption"}, {UINT32_MAX, NULL}}; const enum_map_t extra_fields[] = { /* PKWARE defined */ {0x0001, "Zip64 extended information"}, {0x0007, "AV Info"}, {0x0008, "Reserved for extended language encoding data (PFS)"}, {0x0009, "OS/2"}, {0x000a, "NTFS"}, {0x000c, "OpenVMS"}, {0x000d, "UNIX"}, {0x000e, "Reserved for file stream and fork descriptors"}, {0x000f, "Patch Descriptor"}, {0x0014, "PKCS#7 Store for X.509 Certificates"}, {0x0015, "X.509 Certificate ID and Signature for individual file"}, {0x0016, "X.509 Certificate ID for Central Directory"}, {0x0017, "Strong Encryption Header"}, {0x0018, "Record Management Controls"}, {0x0019, "PKCS#7 Encryption Recipient Certificate List"}, {0x0065, "IBM S/390 (Z390), AS/400 (I400) attributes - uncompressed"}, {0x0066, "Reserved for IBM S/390 (Z390), AS/400 (I400) attributes - compressed"}, {0x4690, "POSZIP 4690 (reserved)"}, /* Third-Party defined; see InfoZIP unzip sources proginfo/extrafld.txt */ {0x07c8, "Info-ZIP Macintosh (old)"}, {0x2605, "ZipIt Macintosh (first version)"}, {0x2705, "ZipIt Macintosh 1.3.5+ (w/o full filename)"}, {0x2805, "ZipIt Macintosh 1.3.5+"}, {0x334d, "Info-ZIP Macintosh (new)"}, {0x4154, "Tandem NSK"}, {0x4341, "Acorn/SparkFS"}, {0x4453, "Windows NT security descriptor"}, {0x4704, "VM/CMS"}, {0x470f, "MVS"}, {0x4854, "Theos, old unofficial port"}, {0x4b46, "FWKCS MD5"}, {0x4c41, "OS/2 access control list (text ACL)"}, {0x4d49, "Info-ZIP OpenVMS (obsolete)"}, {0x4d63, "Macintosh SmartZIP"}, {0x4f4c, "Xceed original location extra field"}, {0x5356, "AOS/VS (ACL)"}, {0x5455, "extended timestamp"}, {0x554e, "Xceed unicode extra field"}, {0x5855, "Info-ZIP UNIX (original)"}, {0x6375, "Info-ZIP UTF-8 comment field"}, {0x6542, "BeOS (BeBox, PowerMac, etc.)"}, {0x6854, "Theos"}, {0x7075, "Info-ZIP UTF-8 name field"}, {0x7441, "AtheOS (AtheOS/Syllable attributes)"}, {0x756e, "ASi UNIX"}, {0x7855, "Info-ZIP UNIX"}, {0x7875, "Info-ZIP UNIX 3rd generation"}, {0x9901, "WinZIP AES encryption"}, {0xa220, "Microsoft Open Packaging Growth Hint"}, {0xcafe, "executable Java JAR file"}, {0xfb4a, "SMS/QDOS"}, /* per InfoZIP extrafld.txt */ {0xfd4a, "SMS/QDOS"}, /* per appnote.txt */ {UINT32_MAX, NULL}}; const char *progname; #define PROGRAM "zipcmp" #define USAGE "usage: %s [-" OPTIONS "] archive1 archive2\n" char help_head[] = PROGRAM " (" PACKAGE ") by Dieter Baron and Thomas Klausner\n\n"; char help[] = "\n\ -C check archive consistencies\n\ -h display this help message\n\ -i compare names ignoring case distinctions\n\ -p compare as many details as possible\n\ -q be quiet\n\ -s print a summary\n\ -T compare time stamps\n\ -t test zip files (compare file contents to checksum)\n\ -V display version number\n\ -v be verbose (print differences, default)\n\ \n\ Report bugs to .\n"; char version_string[] = PROGRAM " (" PACKAGE " " VERSION ")\n\ Copyright (C) 2003-2024 Dieter Baron and Thomas Klausner\n\ " PACKAGE " comes with ABSOLUTELY NO WARRANTY, to the extent permitted by law.\n"; #define OPTIONS "ChipqsTtVv" #define BOTH_ARE_ZIPS(a) (a[0].za && a[1].za) static int comment_compare(const char *c1, size_t l1, const char *c2, size_t l2); static int compare_list(char *const name[2], const void *list[2], const zip_uint64_t list_length[2], int element_size, int (*cmp)(const void *a, const void *b), int (*ignore)(const void *list, int last, const void *other), int (*check)(char *const name[2], const void *a, const void *b), void (*print)(char side, const void *element), void (*start_file)(const void *element)); static int compare_zip(char *const zn[]); static int ef_compare(char *const name[2], const struct entry *e1, const struct entry *e2); static int ef_order(const void *a, const void *b); static void ef_print(char side, const void *p); static int ef_read(zip_t *za, zip_uint64_t idx, struct entry *e); static int entry_cmp(const void *p1, const void *p2); static int entry_ignore(const void *p1, int last, const void *o); static int entry_paranoia_checks(char *const name[2], const void *p1, const void *p2); static void entry_print(char side, const void *p); static void entry_start_file(const void *p); static const char *map_enum(const enum_map_t *map, uint32_t value); static int is_directory(const char *name); #ifdef HAVE_FTS_H static int list_directory(const char *name, struct archive *a); #endif static int list_zip(const char *name, struct archive *a); static int test_file(zip_t *za, zip_uint64_t idx, const char *zipname, const char *filename, zip_uint64_t size, zip_uint32_t crc); int ignore_case, test_files, paranoid, verbose, have_directory, check_consistency, compare_time_stamps, summary; int plus_count = 0, minus_count = 0; diff_output_t output; int main(int argc, char *const argv[]) { int c; progname = argv[0]; ignore_case = 0; test_files = 0; check_consistency = 0; compare_time_stamps = 0; paranoid = 0; have_directory = 0; verbose = 1; summary = 0; while ((c = getopt(argc, argv, OPTIONS)) != -1) { switch (c) { case 'C': check_consistency = 1; break; case 'h': fputs(help_head, stdout); printf(USAGE, progname); fputs(help, stdout); exit(0); case 'i': ignore_case = 1; break; case 'p': paranoid = 1; break; case 'q': verbose = 0; break; case 's': summary = 1; break; case 'T': compare_time_stamps = 1; break; case 't': test_files = 1; break; case 'V': fputs(version_string, stdout); exit(0); case 'v': verbose = 1; break; default: fprintf(stderr, USAGE, progname); exit(2); } } if (argc != optind + 2) { fprintf(stderr, USAGE, progname); exit(2); } exit((compare_zip(argv + optind) == 0) ? 0 : 1); } static int compare_zip(char *const zn[]) { struct archive a[2]; struct entry *e[2]; zip_uint64_t n[2]; int i; int res; for (i = 0; i < 2; i++) { a[i].name = zn[i]; a[i].entry = NULL; a[i].nentry = 0; a[i].za = NULL; a[i].comment = NULL; a[i].comment_length = 0; if (is_directory(zn[i])) { #ifndef HAVE_FTS_H fprintf(stderr, "%s: reading directories not supported\n", progname); exit(2); #else if (list_directory(zn[i], a + i) < 0) exit(2); have_directory = 1; paranoid = 0; /* paranoid checks make no sense for directories, since they compare zip metadata */ #endif } else { if (list_zip(zn[i], a + i) < 0) exit(2); } if (a[i].nentry > 0) qsort(a[i].entry, a[i].nentry, sizeof(a[i].entry[0]), entry_cmp); } diff_output_init(&output, verbose, zn); e[0] = a[0].entry; e[1] = a[1].entry; n[0] = a[0].nentry; n[1] = a[1].nentry; res = compare_list(zn, (const void **)e, n, sizeof(e[i][0]), entry_cmp, have_directory ? entry_ignore : NULL, paranoid ? entry_paranoia_checks : NULL, entry_print, entry_start_file); if (paranoid) { if (comment_compare(a[0].comment, a[0].comment_length, a[1].comment, a[1].comment_length) != 0) { if (a[0].comment_length > 0) { diff_output_data(&output, '-', (const zip_uint8_t *)a[0].comment, a[0].comment_length, "archive comment"); minus_count++; } if (a[1].comment_length > 0) { diff_output_data(&output, '+', (const zip_uint8_t *)a[1].comment, a[1].comment_length, "archive comment"); plus_count++; } res = 1; } } for (i = 0; i < 2; i++) { zip_uint64_t j; if (a[i].za) { zip_close(a[i].za); } for (j = 0; j < a[i].nentry; j++) { free(a[i].entry[j].name); } free(a[i].entry); } if (summary) { printf("%d files removed, %d files added\n", minus_count, plus_count); } switch (res) { case 0: exit(0); case 1: exit(1); default: exit(2); } } #ifdef HAVE_FTS_H static zip_int64_t compute_crc(const char *fname) { FILE *f; uLong crc = crc32(0L, Z_NULL, 0); size_t n; Bytef buffer[8192]; if ((f = fopen(fname, "rb")) == NULL) { fprintf(stderr, "%s: can't open %s: %s\n", progname, fname, strerror(errno)); return -1; } while ((n = fread(buffer, 1, sizeof(buffer), f)) > 0) { crc = crc32(crc, buffer, (unsigned int)n); } if (ferror(f)) { fprintf(stderr, "%s: read error on %s: %s\n", progname, fname, strerror(errno)); fclose(f); return -1; } fclose(f); return (zip_int64_t)crc; } #endif static int is_directory(const char *name) { struct stat st; if (stat(name, &st) < 0) return 0; return S_ISDIR(st.st_mode); } #ifdef HAVE_FTS_H static int list_directory(const char *name, struct archive *a) { FTS *fts; FTSENT *ent; zip_uint64_t nalloc; size_t prefix_length; size_t name_length; char* normalized_name; name_length = strlen(name); if (name_length == 0) { fprintf(stderr, "%s: can't open directory '': invalid name\n", progname); return -1; } normalized_name = strdup(name); while (name_length > 0 && normalized_name[name_length-1] == '/') { name_length -= 1; } normalized_name[name_length] = '\0'; if (name_length == 0) { normalized_name[0] = '/'; normalized_name[1] = '\0'; name_length = 1; } prefix_length = name_length + 1; char *const names[2] = {normalized_name, NULL}; if ((fts = fts_open(names, FTS_NOCHDIR | FTS_LOGICAL, NULL)) == NULL) { fprintf(stderr, "%s: can't open directory '%s': %s\n", progname, name, strerror(errno)); free(normalized_name); return -1; } nalloc = 0; while ((ent = fts_read(fts))) { zip_int64_t crc; switch (ent->fts_info) { case FTS_DOT: case FTS_DP: case FTS_DEFAULT: case FTS_SL: case FTS_NSOK: break; case FTS_DC: case FTS_DNR: case FTS_ERR: case FTS_NS: case FTS_SLNONE: /* TODO: error */ fts_close(fts); return -1; case FTS_D: case FTS_F: if (a->nentry >= nalloc) { nalloc += 16; if (nalloc > SIZE_MAX / sizeof(a->entry[0])) { fprintf(stderr, "%s: malloc failure\n", progname); exit(1); } a->entry = realloc(a->entry, sizeof(a->entry[0]) * nalloc); if (a->entry == NULL) { fprintf(stderr, "%s: malloc failure\n", progname); exit(1); } } if (ent->fts_info == FTS_D) { char *dir_name; if (ent->fts_path[prefix_length - 1] == '\0') { break; } size_t dir_name_size = strlen(ent->fts_path + prefix_length) + 2; dir_name = malloc(dir_name_size); if (dir_name == NULL) { fprintf(stderr, "%s: malloc failure\n", progname); exit(1); } snprintf(dir_name, dir_name_size, "%s/", ent->fts_path + prefix_length); a->entry[a->nentry].name = dir_name; a->entry[a->nentry].size = 0; a->entry[a->nentry].crc = 0; a->entry[a->nentry].last_modification_time = 0; } else { a->entry[a->nentry].name = strdup(ent->fts_path + prefix_length); a->entry[a->nentry].size = (zip_uint64_t)ent->fts_statp->st_size; if ((crc = compute_crc(ent->fts_accpath)) < 0) { fts_close(fts); free(normalized_name); return -1; } a->entry[a->nentry].crc = (zip_uint32_t)crc; a->entry[a->nentry].last_modification_time = ent->fts_statp->st_mtime; } a->nentry++; break; } } if (fts_close(fts)) { fprintf(stderr, "%s: error closing directory '%s': %s\n", progname, a->name, strerror(errno)); free(normalized_name); return -1; } free(normalized_name); return 0; } #endif static int list_zip(const char *name, struct archive *a) { zip_t *za; int err; struct zip_stat st; unsigned int i; if ((za = zip_open(name, check_consistency ? ZIP_CHECKCONS : 0, &err)) == NULL) { zip_error_t error; zip_error_init_with_code(&error, err); fprintf(stderr, "%s: cannot open zip archive '%s': %s\n", progname, name, zip_error_strerror(&error)); zip_error_fini(&error); return -1; } a->za = za; a->nentry = (zip_uint64_t)zip_get_num_entries(za, 0); if (a->nentry == 0) a->entry = NULL; else { if ((a->nentry > SIZE_MAX / sizeof(a->entry[0])) || (a->entry = (struct entry *)malloc(sizeof(a->entry[0]) * a->nentry)) == NULL) { fprintf(stderr, "%s: malloc failure\n", progname); exit(1); } for (i = 0; i < a->nentry; i++) { zip_stat_index(za, i, 0, &st); a->entry[i].name = strdup(st.name); a->entry[i].size = st.size; a->entry[i].crc = st.crc; if (test_files) test_file(za, i, name, st.name, st.size, st.crc); if (paranoid) { a->entry[i].comp_method = st.comp_method; ef_read(za, i, a->entry + i); a->entry[i].comment = zip_file_get_comment(za, i, &a->entry[i].comment_length, 0); } else { a->entry[i].comp_method = 0; a->entry[i].n_extra_fields = 0; } a->entry[i].last_modification_time = st.mtime; } if (paranoid) { int length; a->comment = zip_get_archive_comment(za, &length, 0); a->comment_length = (size_t)length; } else { a->comment = NULL; a->comment_length = 0; } } return 0; } static int comment_compare(const char *c1, size_t l1, const char *c2, size_t l2) { if (l1 != l2) return 1; if (l1 == 0) return 0; if (c1 == NULL || c2 == NULL) return c1 == c2; return memcmp(c1, c2, (size_t)l2); } static int compare_list(char *const name[2], const void *list[2], const zip_uint64_t list_length[2], int element_size, int (*cmp)(const void *a, const void *b), int (*ignore)(const void *list, int last, const void *other), int (*check)(char *const name[2], const void *a, const void *b), void (*print)(char side, const void *element), void (*start_file)(const void *element)) { unsigned int i[2]; int j; int diff; #define INC(k) (i[k]++, list[k] = ((const char *)list[k]) + element_size) #define PRINT(k) \ do { \ if (ignore && ignore(list[k], i[k] >= list_length[k] - 1, i[1 - k] < list_length[1 - k] ? list[1 - k] : NULL)) { \ break; \ } \ print((k) ? '+' : '-', list[k]); \ (k) ? plus_count++ : minus_count++; \ diff = 1; \ } while (0) i[0] = i[1] = 0; diff = 0; while (i[0] < list_length[0] && i[1] < list_length[1]) { int c = cmp(list[0], list[1]); if (c == 0) { if (check) { if (start_file) { start_file(list[0]); } diff |= check(name, list[0], list[1]); if (start_file) { diff_output_end_file(&output); } } INC(0); INC(1); } else if (c < 0) { PRINT(0); INC(0); } else { PRINT(1); INC(1); } } for (j = 0; j < 2; j++) { while (i[j] < list_length[j]) { PRINT(j); INC(j); } } return diff; } static int ef_read(zip_t *za, zip_uint64_t idx, struct entry *e) { zip_int16_t n_local, n_central; zip_uint16_t i; if ((n_local = zip_file_extra_fields_count(za, idx, ZIP_FL_LOCAL)) < 0 || (n_central = zip_file_extra_fields_count(za, idx, ZIP_FL_CENTRAL)) < 0) { return -1; } e->n_extra_fields = (zip_uint16_t)(n_local + n_central); if ((e->extra_fields = (struct ef *)malloc(sizeof(e->extra_fields[0]) * e->n_extra_fields)) == NULL) return -1; for (i = 0; i < n_local; i++) { e->extra_fields[i].name = e->name; e->extra_fields[i].data = zip_file_extra_field_get(za, idx, i, &e->extra_fields[i].id, &e->extra_fields[i].size, ZIP_FL_LOCAL); if (e->extra_fields[i].data == NULL) return -1; e->extra_fields[i].flags = ZIP_FL_LOCAL; } for (; i < e->n_extra_fields; i++) { e->extra_fields[i].name = e->name; e->extra_fields[i].data = zip_file_extra_field_get(za, idx, (zip_uint16_t)(i - n_local), &e->extra_fields[i].id, &e->extra_fields[i].size, ZIP_FL_CENTRAL); if (e->extra_fields[i].data == NULL) return -1; e->extra_fields[i].flags = ZIP_FL_CENTRAL; } qsort(e->extra_fields, e->n_extra_fields, sizeof(e->extra_fields[0]), ef_order); return 0; } static int ef_compare(char *const name[2], const struct entry *e1, const struct entry *e2) { struct ef *ef[2]; zip_uint64_t n[2]; ef[0] = e1->extra_fields; ef[1] = e2->extra_fields; n[0] = e1->n_extra_fields; n[1] = e2->n_extra_fields; return compare_list(name, (const void **)ef, n, sizeof(struct ef), ef_order, NULL, NULL, ef_print, NULL); } static int ef_order(const void *ap, const void *bp) { const struct ef *a, *b; a = (struct ef *)ap; b = (struct ef *)bp; if (a->flags != b->flags) return a->flags - b->flags; if (a->id != b->id) return a->id - b->id; if (a->size != b->size) return a->size - b->size; return memcmp(a->data, b->data, a->size); } static void ef_print(char side, const void *p) { const struct ef *ef = (struct ef *)p; diff_output_data(&output, side, ef->data, ef->size, " %s extra field %s", ef->flags == ZIP_FL_LOCAL ? "local" : "central", map_enum(extra_fields, ef->id)); } static int entry_cmp(const void *p1, const void *p2) { const struct entry *e1, *e2; int c; e1 = (struct entry *)p1; e2 = (struct entry *)p2; if ((c = (ignore_case ? strcasecmp : strcmp)(e1->name, e2->name)) != 0) return c; if (e1->size != e2->size) { if (e1->size > e2->size) return 1; else return -1; } if (e1->crc != e2->crc) { return (int)e1->crc - (int)e2->crc; } if (compare_time_stamps && e1->last_modification_time != e2->last_modification_time) { return (int)(e1->last_modification_time - e2->last_modification_time); } return 0; } static int entry_ignore(const void *p, int last, const void *o) { const struct entry *e = (const struct entry *)p; const struct entry *other = (const struct entry *)o; size_t length = strlen(e[0].name); if (length == 0 || e[0].name[length - 1] != '/') { /* not a directory */ return 0; } if (other != NULL && strlen(other->name) > length && strncmp(other->name, e[0].name, length) == 0) { /* not empty in other archive */ return 1; } if (last || (strlen(e[1].name) < length || strncmp(e[0].name, e[1].name, length) != 0)) { /* empty in this archive */ return 0; } /* not empty in this archive */ return 1; } static int entry_paranoia_checks(char *const name[2], const void *p1, const void *p2) { const struct entry *e1, *e2; int ret; e1 = (struct entry *)p1; e2 = (struct entry *)p2; ret = 0; if (e1->comp_method != e2->comp_method) { diff_output(&output, '-', " compression method %s", map_enum(comp_methods, e1->comp_method)); diff_output(&output, '+', " compression method %s", map_enum(comp_methods, e2->comp_method)); ret = 1; } if (ef_compare(name, e1, e2) != 0) { ret = 1; } if (comment_compare(e1->comment, e1->comment_length, e2->comment, e2->comment_length) != 0) { diff_output_data(&output, '-', (const zip_uint8_t *)e1->comment, e1->comment_length, " comment"); diff_output_data(&output, '+', (const zip_uint8_t *)e2->comment, e2->comment_length, " comment"); ret = 1; } return ret; } static void entry_print(char side, const void *p) { const struct entry *e = (struct entry *)p; diff_output_file(&output, side, e->name, e->size, e->crc, e->last_modification_time); } static void entry_start_file(const void *p) { const struct entry *e = (struct entry *)p; diff_output_start_file(&output, e->name, e->size, e->crc, e->last_modification_time); } static int test_file(zip_t *za, zip_uint64_t idx, const char *zipname, const char *filename, zip_uint64_t size, zip_uint32_t crc) { zip_file_t *zf; char buf[8192]; zip_uint64_t nsize; zip_int64_t n; zip_uint32_t ncrc; if ((zf = zip_fopen_index(za, idx, 0)) == NULL) { fprintf(stderr, "%s: %s: cannot open file %s (index %" PRIu64 "): %s\n", progname, zipname, filename, idx, zip_strerror(za)); return -1; } ncrc = (zip_uint32_t)crc32(0, NULL, 0); nsize = 0; while ((n = zip_fread(zf, buf, sizeof(buf))) > 0) { nsize += (zip_uint64_t)n; ncrc = (zip_uint32_t)crc32(ncrc, (const Bytef *)buf, (unsigned int)n); } if (n < 0) { fprintf(stderr, "%s: %s: error reading file %s (index %" PRIu64 "): %s\n", progname, zipname, filename, idx, zip_file_strerror(zf)); zip_fclose(zf); return -1; } zip_fclose(zf); if (nsize != size) { fprintf(stderr, "%s: %s: file %s (index %" PRIu64 "): unexpected length %" PRId64 " (should be %" PRId64 ")\n", progname, zipname, filename, idx, nsize, size); return -2; } if (ncrc != crc) { fprintf(stderr, "%s: %s: file %s (index %" PRIu64 "): unexpected length %x (should be %x)\n", progname, zipname, filename, idx, ncrc, crc); return -2; } return 0; } static const char * map_enum(const enum_map_t *map, uint32_t value) { static char unknown[16]; size_t i = 0; while (map[i].value < UINT32_MAX) { if (map[i].value == value) { return map[i].name; } i++; } snprintf(unknown, sizeof(unknown), "unknown (%u)", value); unknown[sizeof(unknown) - 1] = '\0'; return unknown; } ================================================ FILE: external/libzip/src/zipmerge.c ================================================ /* zipmerge.c -- merge zip archives Copyright (C) 2004-2023 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include "config.h" #ifndef HAVE_GETOPT #include "getopt.h" #endif #include "zip.h" char *progname; #define PROGRAM "zipmerge" #define USAGE "usage: %s [-DhIikSsV] target-zip zip...\n" char help_head[] = PROGRAM " (" PACKAGE ") by Dieter Baron and Thomas Klausner\n\n"; char help[] = "\n\ -h display this help message\n\ -V display version number\n\ -D ignore directory component in file names\n\ -I ignore case in file names\n\ -i ask before overwriting files\n\ -k don't compress when adding uncompressed files\n\ -S don't overwrite identical files\n\ -s overwrite identical files without asking\n\ \n\ Report bugs to .\n"; char version_string[] = PROGRAM " (" PACKAGE " " VERSION ")\n\ Copyright (C) 2004-2023 Dieter Baron and Thomas Klausner\n\ " PACKAGE " comes with ABSOLUTELY NO WARRANTY, to the extent permitted by law.\n"; #define OPTIONS "hVDiIksS" #define CONFIRM_ALL_YES 0x001 #define CONFIRM_ALL_NO 0x002 #define CONFIRM_SAME_YES 0x010 #define CONFIRM_SAME_NO 0x020 int confirm; zip_flags_t name_flags; int keep_stored; static int confirm_replace(zip_t *, const char *, zip_uint64_t, zip_t *, const char *, zip_uint64_t); static void copy_extra_fields(zip_t *destination_archive, zip_uint64_t destination_index, zip_t *source_archive, zip_uint64_t source_index, zip_flags_t flags); static int copy_file(zip_t *destination_archive, zip_int64_t destination_index, zip_t *source_archive, zip_uint64_t source_index, const char* name); static zip_t *merge_zip(zip_t *, const char *, const char *); int main(int argc, char *argv[]) { zip_t *za; zip_t **zs; int c, err; unsigned int i, n; char *tname; progname = argv[0]; confirm = CONFIRM_ALL_YES; name_flags = 0; keep_stored = 0; while ((c = getopt(argc, argv, OPTIONS)) != -1) { switch (c) { case 'D': name_flags |= ZIP_FL_NODIR; break; case 'I': name_flags |= ZIP_FL_NOCASE; break; case 'i': confirm &= ~CONFIRM_ALL_YES; break; case 'k': keep_stored = 1; break; case 'S': confirm &= ~CONFIRM_SAME_YES; confirm |= CONFIRM_SAME_NO; break; case 's': confirm &= ~CONFIRM_SAME_NO; confirm |= CONFIRM_SAME_YES; break; case 'h': fputs(help_head, stdout); printf(USAGE, progname); fputs(help, stdout); exit(0); case 'V': fputs(version_string, stdout); exit(0); default: fprintf(stderr, USAGE, progname); exit(2); } } if (argc < optind + 2) { fprintf(stderr, USAGE, progname); exit(2); } tname = argv[optind++]; argv += optind; n = (unsigned int)(argc - optind); if ((zs = (zip_t **)malloc(sizeof(zs[0]) * n)) == NULL) { fprintf(stderr, "%s: out of memory\n", progname); exit(1); } if ((za = zip_open(tname, ZIP_CREATE, &err)) == NULL) { zip_error_t error; zip_error_init_with_code(&error, err); fprintf(stderr, "%s: can't open zip archive '%s': %s\n", progname, tname, zip_error_strerror(&error)); zip_error_fini(&error); exit(1); } for (i = 0; i < n; i++) { if ((zs[i] = merge_zip(za, tname, argv[i])) == NULL) exit(1); } if (zip_close(za) < 0) { fprintf(stderr, "%s: cannot write zip archive '%s': %s\n", progname, tname, zip_strerror(za)); exit(1); } for (i = 0; i < n; i++) zip_close(zs[i]); exit(0); } static int confirm_replace(zip_t *za, const char *tname, zip_uint64_t it, zip_t *zs, const char *sname, zip_uint64_t is) { char line[1024]; struct zip_stat st, ss; if (confirm & CONFIRM_ALL_YES) return 1; else if (confirm & CONFIRM_ALL_NO) return 0; if (zip_stat_index(za, it, ZIP_FL_UNCHANGED, &st) < 0) { fprintf(stderr, "%s: cannot stat file %" PRIu64 " in '%s': %s\n", progname, it, tname, zip_strerror(za)); return -1; } if (zip_stat_index(zs, is, 0, &ss) < 0) { fprintf(stderr, "%s: cannot stat file %" PRIu64 " in '%s': %s\n", progname, is, sname, zip_strerror(zs)); return -1; } if (st.size == ss.size && st.crc == ss.crc) { if (confirm & CONFIRM_SAME_YES) return 1; else if (confirm & CONFIRM_SAME_NO) return 0; } printf("replace '%s' (%" PRIu64 " / %08x) in `%s'\n" " with '%s' (%" PRIu64 " / %08x) from `%s'? ", st.name, st.size, st.crc, tname, ss.name, ss.size, ss.crc, sname); fflush(stdout); if (fgets(line, sizeof(line), stdin) == NULL) { fprintf(stderr, "%s: read error from stdin: %s\n", progname, strerror(errno)); return -1; } if (tolower((unsigned char)line[0]) == 'y') return 1; return 0; } static zip_t * merge_zip(zip_t *za, const char *tname, const char *sname) { zip_t *zs; zip_int64_t ret, idx; zip_uint64_t i; int err; const char *fname; if ((zs = zip_open(sname, 0, &err)) == NULL) { zip_error_t error; zip_error_init_with_code(&error, err); fprintf(stderr, "%s: can't open zip archive '%s': %s\n", progname, sname, zip_error_strerror(&error)); zip_error_fini(&error); return NULL; } ret = zip_get_num_entries(zs, 0); if (ret < 0) { fprintf(stderr, "%s: cannot get number of entries for '%s': %s\n", progname, sname, zip_strerror(za)); return NULL; } for (i = 0; i < (zip_uint64_t)ret; i++) { fname = zip_get_name(zs, i, 0); if ((idx = zip_name_locate(za, fname, name_flags)) >= 0) { switch (confirm_replace(za, tname, (zip_uint64_t)idx, zs, sname, i)) { case 0: break; case 1: if (copy_file(za, idx, zs, i, NULL) < 0) { fprintf(stderr, "%s: cannot replace '%s' in `%s': %s\n", progname, fname, tname, zip_strerror(za)); zip_close(zs); return NULL; } break; case -1: zip_close(zs); return NULL; default: fprintf(stderr, "%s: internal error: " "unexpected return code from confirm (%d)\n", progname, err); zip_close(zs); return NULL; } } else { if (copy_file(za, -1, zs, i, fname) < 0) { fprintf(stderr, "%s: cannot add '%s' to `%s': %s\n", progname, fname, tname, zip_strerror(za)); zip_close(zs); return NULL; } } } return zs; } static int copy_file(zip_t *destination_archive, zip_int64_t destination_index, zip_t *source_archive, zip_uint64_t source_index, const char* name) { zip_source_t *source = zip_source_zip_file(destination_archive, source_archive, source_index, ZIP_FL_COMPRESSED, 0, -1, NULL); if (source == NULL) { return -1; } if (destination_index >= 0) { if (zip_file_replace(destination_archive, (zip_uint64_t)destination_index, source, 0) < 0) { zip_source_free(source); return -1; } } else { destination_index = zip_file_add(destination_archive, name, source, 0); if (destination_index < 0) { zip_source_free(source); return -1; } } copy_extra_fields(destination_archive, (zip_uint64_t)destination_index, source_archive, source_index, ZIP_FL_CENTRAL); copy_extra_fields(destination_archive, (zip_uint64_t)destination_index, source_archive, source_index, ZIP_FL_LOCAL); if (keep_stored) { zip_stat_t st; if (zip_stat_index(source_archive, source_index, 0, &st) == 0 && (st.valid & ZIP_STAT_COMP_METHOD) && st.comp_method == ZIP_CM_STORE) { zip_set_file_compression(destination_archive, destination_index, ZIP_CM_STORE, 0); } } return 0; } static void copy_extra_fields(zip_t *destination_archive, zip_uint64_t destination_index, zip_t *source_archive, zip_uint64_t source_index, zip_flags_t flags) { zip_int16_t n; zip_uint16_t i, id, length; const zip_uint8_t *data; if ((n = zip_file_extra_fields_count(source_archive, source_index, flags)) < 0) { return; } for (i = 0; i < n; i++) { if ((data = zip_file_extra_field_get(source_archive, source_index, i, &id, &length, flags)) == NULL) { continue; } zip_file_extra_field_set(destination_archive, destination_index, id, ZIP_EXTRA_FIELD_NEW, data, length, flags); } } ================================================ FILE: external/libzip/src/ziptool.c ================================================ /* ziptool.c -- tool for modifying zip archive in multiple ways Copyright (C) 2012-2024 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #include "compat.h" #include #include #include #include #ifdef HAVE_UNISTD_H #include #endif #ifdef _WIN32 /* WIN32 needs for _O_BINARY */ #include #ifndef STDIN_FILENO #define STDIN_FILENO _fileno(stdin) #endif #endif #ifndef HAVE_GETOPT #include "getopt.h" #endif extern int optopt; #include "zip.h" typedef struct dispatch_table_s { const char *cmdline_name; int argument_count; const char *arg_names; const char *description; int (*function)(char *argv[]); } dispatch_table_t; static zip_flags_t get_flags(const char *arg); static zip_int32_t get_compression_method(const char *arg); static zip_uint16_t get_encryption_method(const char *arg); static void hexdump(const zip_uint8_t *data, zip_uint16_t len); static int parse_archive_flag(const char* arg); int ziptool_post_close(const char *archive); static const char* decode_filename(const char* name); static const char* encode_filename(const char* name); #ifndef FOR_REGRESS #define OPTIONS_REGRESS "" #define USAGE_REGRESS "" #endif zip_t *za, *z_in[16]; unsigned int z_in_count; zip_flags_t stat_flags; int hex_encoded_filenames = 0; // Can only be set in ziptool_regress. static int cat_impl_backend(zip_uint64_t idx, zip_uint64_t start, zip_uint64_t len, FILE *out) { zip_error_t error; zip_source_t *src; zip_int64_t n; char buf[8192]; zip_error_init(&error); /* we can't pass 0 as a len to zip_source_zip_create because it will try to give us compressed data */ if (len == 0) { struct zip_stat sb; if (zip_stat_index(za, idx, stat_flags, &sb) < 0) { fprintf(stderr, "zip_stat_index failed on '%" PRIu64 "' failed: %s\n", idx, zip_strerror(za)); return -1; } if (!(sb.valid & ZIP_STAT_SIZE)) { fprintf(stderr, "can't cat file at index '%" PRIu64 "' with unknown size\n", idx); return -1; } len = sb.size; } if ((src = zip_source_zip_file_create(za, idx, 0, start, len, NULL, &error)) == NULL) { fprintf(stderr, "can't open file at index '%" PRIu64 "': %s\n", idx, zip_error_strerror(&error)); zip_error_fini(&error); return -1; } zip_error_fini(&error); if (zip_source_open(src) < 0) { fprintf(stderr, "can't open file at index '%" PRIu64 "': %s\n", idx, zip_error_strerror(zip_source_error(src))); zip_source_free(src); return -1; } while ((n = zip_source_read(src, buf, sizeof(buf))) > 0) { if (fwrite(buf, (size_t)n, 1, out) != 1) { fprintf(stderr, "can't write file contents: %s\n", strerror(errno)); zip_source_free(src); return -1; } } if (n == -1) { fprintf(stderr, "can't read file at index '%" PRIu64 "': %s\n", idx, zip_error_strerror(zip_source_error(src))); zip_source_free(src); return -1; } if (zip_source_close(src) < 0) { fprintf(stderr, "can't close file at index '%" PRIu64 "': %s\n", idx, zip_error_strerror(zip_source_error(src))); zip_source_free(src); return -1; } zip_source_free(src); return 0; } static int cat_impl(zip_uint64_t idx, zip_uint64_t start, zip_uint64_t len) { #ifdef _WIN32 /* Need to set stdout to binary mode for Windows */ setmode(fileno(stdout), _O_BINARY); #endif return cat_impl_backend(idx, start, len, stdout); } static int add(char *argv[]) { zip_source_t *zs; if ((zs = zip_source_buffer(za, argv[1], strlen(argv[1]), 0)) == NULL) { fprintf(stderr, "can't create zip_source from buffer: %s\n", zip_strerror(za)); return -1; } if (zip_file_add(za, decode_filename(argv[0]), zs, 0) == -1) { zip_source_free(zs); fprintf(stderr, "can't add file '%s': %s\n", argv[0], zip_strerror(za)); return -1; } return 0; } static int add_dir(char *argv[]) { /* add directory */ if (zip_dir_add(za, decode_filename(argv[0]), 0) < 0) { fprintf(stderr, "can't add directory '%s': %s\n", argv[0], zip_strerror(za)); return -1; } return 0; } static int add_file(char *argv[]) { zip_source_t *zs; zip_uint64_t start = strtoull(argv[2], NULL, 10); zip_int64_t len = strtoll(argv[3], NULL, 10); if (strcmp(argv[1], "/dev/stdin") == 0) { if ((zs = zip_source_filep(za, stdin, start, len)) == NULL) { fprintf(stderr, "can't create zip_source from stdin: %s\n", zip_strerror(za)); return -1; } } else { if ((zs = zip_source_file(za, argv[1], start, len)) == NULL) { fprintf(stderr, "can't create zip_source from file: %s\n", zip_strerror(za)); return -1; } } if (zip_file_add(za, decode_filename(argv[0]), zs, 0) == -1) { zip_source_free(zs); fprintf(stderr, "can't add file '%s': %s\n", argv[0], zip_strerror(za)); return -1; } return 0; } static int add_from_zip(char *argv[]) { zip_uint64_t idx, start; zip_int64_t len; int err; zip_source_t *zs; zip_flags_t flags = 0; /* add from another zip file */ idx = strtoull(argv[2], NULL, 10); start = strtoull(argv[3], NULL, 10); len = strtoll(argv[4], NULL, 10); if ((z_in[z_in_count] = zip_open(argv[1], ZIP_CHECKCONS, &err)) == NULL) { zip_error_t error; zip_error_init_with_code(&error, err); fprintf(stderr, "can't open zip archive '%s': %s\n", argv[1], zip_error_strerror(&error)); zip_error_fini(&error); return -1; } if (start == 0 && len == -1) { flags = ZIP_FL_COMPRESSED; } if ((zs = zip_source_zip_file(za, z_in[z_in_count], idx, flags, start, len, NULL)) == NULL) { fprintf(stderr, "error creating file source from '%s' index '%" PRIu64 "': %s\n", argv[1], idx, zip_strerror(za)); zip_close(z_in[z_in_count]); return -1; } if (zip_file_add(za, decode_filename(argv[0]), zs, 0) == -1) { fprintf(stderr, "can't add file '%s': %s\n", argv[0], zip_strerror(za)); zip_source_free(zs); zip_close(z_in[z_in_count]); return -1; } z_in_count++; return 0; } static int cat(char *argv[]) { /* output file contents to stdout */ zip_uint64_t idx; idx = strtoull(argv[0], NULL, 10); return cat_impl(idx, 0, 0); } static int cat_partial(char *argv[]) { /* output partial file contents to stdout */ zip_uint64_t idx; zip_uint64_t start; zip_uint64_t len; idx = strtoull(argv[0], NULL, 10); start = strtoull(argv[1], NULL, 10); len = strtoull(argv[2], NULL, 10); return cat_impl(idx, start, len); } static int count_extra(char *argv[]) { zip_int16_t count; zip_uint64_t idx; zip_flags_t ceflags = 0; idx = strtoull(argv[0], NULL, 10); ceflags = get_flags(argv[1]); if ((count = zip_file_extra_fields_count(za, idx, ceflags)) < 0) { fprintf(stderr, "can't get extra field count for file at index '%" PRIu64 "': %s\n", idx, zip_strerror(za)); return -1; } else { printf("Extra field count: %d\n", count); } return 0; } static int count_extra_by_id(char *argv[]) { zip_int16_t count; zip_uint16_t eid; zip_flags_t ceflags = 0; zip_uint64_t idx; idx = strtoull(argv[0], NULL, 10); eid = (zip_uint16_t)strtoull(argv[1], NULL, 10); ceflags = get_flags(argv[2]); if ((count = zip_file_extra_fields_count_by_id(za, idx, eid, ceflags)) < 0) { fprintf(stderr, "can't get extra field count for file at index '%" PRIu64 "' and for id '%d': %s\n", idx, eid, zip_strerror(za)); return -1; } else { printf("Extra field count: %d\n", count); } return 0; } static int delete (char *argv[]) { zip_uint64_t idx; idx = strtoull(argv[0], NULL, 10); if (zip_delete(za, idx) < 0) { fprintf(stderr, "can't delete file at index '%" PRIu64 "': %s\n", idx, zip_strerror(za)); return -1; } return 0; } static int delete_extra(char *argv[]) { zip_flags_t geflags; zip_uint16_t eid; zip_uint64_t idx; idx = strtoull(argv[0], NULL, 10); eid = (zip_uint16_t)strtoull(argv[1], NULL, 10); geflags = get_flags(argv[2]); if ((zip_file_extra_field_delete(za, idx, eid, geflags)) < 0) { fprintf(stderr, "can't delete extra field data for file at index '%" PRIu64 "', extra field id '%d': %s\n", idx, eid, zip_strerror(za)); return -1; } return 0; } static int delete_extra_by_id(char *argv[]) { zip_flags_t geflags; zip_uint16_t eid, eidx; zip_uint64_t idx; idx = strtoull(argv[0], NULL, 10); eid = (zip_uint16_t)strtoull(argv[1], NULL, 10); eidx = (zip_uint16_t)strtoull(argv[2], NULL, 10); geflags = get_flags(argv[3]); if ((zip_file_extra_field_delete_by_id(za, idx, eid, eidx, geflags)) < 0) { fprintf(stderr, "can't delete extra field data for file at index '%" PRIu64 "', extra field id '%d', extra field idx '%d': %s\n", idx, eid, eidx, zip_strerror(za)); return -1; } return 0; } static int get_archive_comment(char *argv[]) { const char *comment; int len; /* get archive comment */ if ((comment = zip_get_archive_comment(za, &len, 0)) == NULL || len == 0) printf("No archive comment\n"); else printf("Archive comment: %.*s\n", len, encode_filename(comment)); return 0; } static int get_archive_flag(char *argv[]) { int flag = parse_archive_flag(argv[0]); if (flag < 0) { fprintf(stderr, "invalid archive flag '%s'\n", argv[0]); return -1; } printf("%d\n", zip_get_archive_flag(za, flag, 0)); return 0; } static int get_extra(char *argv[]) { zip_flags_t geflags; zip_uint16_t id, eidx, eflen; const zip_uint8_t *efdata; zip_uint64_t idx; /* get extra field data */ idx = strtoull(argv[0], NULL, 10); eidx = (zip_uint16_t)strtoull(argv[1], NULL, 10); geflags = get_flags(argv[2]); if ((efdata = zip_file_extra_field_get(za, idx, eidx, &id, &eflen, geflags)) == NULL) { fprintf(stderr, "can't get extra field data for file at index %" PRIu64 ", extra field %d, flags %u: %s\n", idx, eidx, geflags, zip_strerror(za)); return -1; } printf("Extra field 0x%04x: len %d", id, eflen); if (eflen > 0) { printf(", data "); hexdump(efdata, eflen); } printf("\n"); return 0; } static int get_extra_by_id(char *argv[]) { zip_flags_t geflags; zip_uint16_t eid, eidx, eflen; const zip_uint8_t *efdata; zip_uint64_t idx; idx = strtoull(argv[0], NULL, 10); eid = (zip_uint16_t)strtoull(argv[1], NULL, 10); eidx = (zip_uint16_t)strtoull(argv[2], NULL, 10); geflags = get_flags(argv[3]); if ((efdata = zip_file_extra_field_get_by_id(za, idx, eid, eidx, &eflen, geflags)) == NULL) { fprintf(stderr, "can't get extra field data for file at index %" PRIu64 ", extra field id %d, ef index %d, flags %u: %s\n", idx, eid, eidx, geflags, zip_strerror(za)); return -1; } printf("Extra field 0x%04x: len %d", eid, eflen); if (eflen > 0) { printf(", data "); hexdump(efdata, eflen); } printf("\n"); return 0; } static int get_file_comment(char *argv[]) { const char *comment; zip_uint32_t len; zip_uint64_t idx; /* get file comment */ idx = strtoull(argv[0], NULL, 10); if ((comment = zip_file_get_comment(za, idx, &len, 0)) == NULL) { fprintf(stderr, "can't get comment for '%s': %s\n", zip_get_name(za, idx, 0), zip_strerror(za)); return -1; } else if (len == 0) printf("No comment for '%s'\n", zip_get_name(za, idx, 0)); else printf("File comment for '%s': %.*s\n", zip_get_name(za, idx, 0), (int)len, comment); return 0; } static int get_num_entries(char *argv[]) { zip_int64_t count; zip_flags_t flags; /* get number of entries in archive */ flags = get_flags(argv[0]); count = zip_get_num_entries(za, flags); printf("%" PRId64 " entr%s in archive\n", count, count == 1 ? "y" : "ies"); return 0; } static int name_locate(char *argv[]) { zip_flags_t flags; zip_int64_t idx; flags = get_flags(argv[1]); if ((idx = zip_name_locate(za, decode_filename(argv[0]), flags)) < 0) { fprintf(stderr, "can't find entry with name '%s' using flags '%s'\n", argv[0], argv[1]); } else { printf("name '%s' using flags '%s' found at index %" PRId64 "\n", argv[0], argv[1], idx); } return 0; } struct progress_userdata_s { double percentage; double limit; }; struct progress_userdata_s progress_userdata; static void progress_callback(zip_t *archive, double percentage, void *ud) { printf("%.1f%% done\n", percentage * 100); progress_userdata.percentage = percentage; } static int print_progress(char *argv[]) { zip_register_progress_callback_with_state(za, 0.001, progress_callback, NULL, NULL); return 0; } static int zrename(char *argv[]) { zip_uint64_t idx; idx = strtoull(argv[0], NULL, 10); if (zip_file_rename(za, idx, decode_filename(argv[1]), 0) < 0) { fprintf(stderr, "can't rename file at index '%" PRIu64 "' to '%s': %s\n", idx, argv[1], zip_strerror(za)); return -1; } return 0; } static int replace_file_contents(char *argv[]) { /* replace file contents with data from command line */ const char *content; zip_source_t *s; zip_uint64_t idx; idx = strtoull(argv[0], NULL, 10); content = argv[1]; if ((s = zip_source_buffer(za, content, strlen(content), 0)) == NULL || zip_file_replace(za, idx, s, 0) < 0) { zip_source_free(s); fprintf(stderr, "error replacing file data: %s\n", zip_strerror(za)); return -1; } return 0; } static int set_extra(char *argv[]) { zip_flags_t geflags; zip_uint16_t eid, eidx; const zip_uint8_t *efdata; zip_uint64_t idx; idx = strtoull(argv[0], NULL, 10); eid = (zip_uint16_t)strtoull(argv[1], NULL, 10); eidx = (zip_uint16_t)strtoull(argv[2], NULL, 10); geflags = get_flags(argv[3]); efdata = (zip_uint8_t *)argv[4]; if ((zip_file_extra_field_set(za, idx, eid, eidx, efdata, (zip_uint16_t)strlen((const char *)efdata), geflags)) < 0) { fprintf(stderr, "can't set extra field data for file at index '%" PRIu64 "', extra field id '%d', index '%d': %s\n", idx, eid, eidx, zip_strerror(za)); return -1; } return 0; } static int set_archive_comment(char *argv[]) { if (zip_set_archive_comment(za, argv[0], (zip_uint16_t)strlen(argv[0])) < 0) { fprintf(stderr, "can't set archive comment to '%s': %s\n", argv[0], zip_strerror(za)); return -1; } return 0; } static int set_archive_flag(char *argv[]) { int flag = parse_archive_flag(argv[0]); if (flag < 0) { fprintf(stderr, "invalid archive flag '%s'\n", argv[0]); return -1; } int value = strcasecmp(argv[1], "1") == 0 || strcasecmp(argv[1], "true") == 0 || strcasecmp(argv[1], "yes") == 0; if (zip_set_archive_flag(za, flag, value) < 0) { fprintf(stderr, "can't set archive flag '%s' to %d: %s\n", argv[0], value, zip_strerror(za)); return -1; } return 0; } static int set_file_comment(char *argv[]) { zip_uint64_t idx; idx = strtoull(argv[0], NULL, 10); if (zip_file_set_comment(za, idx, argv[1], (zip_uint16_t)strlen(argv[1]), 0) < 0) { fprintf(stderr, "can't set file comment at index '%" PRIu64 "' to '%s': %s\n", idx, argv[1], zip_strerror(za)); return -1; } return 0; } static int set_file_compression(char *argv[]) { zip_int32_t method; zip_uint32_t flags; zip_uint64_t idx; idx = strtoull(argv[0], NULL, 10); method = get_compression_method(argv[1]); flags = (zip_uint32_t)strtoull(argv[2], NULL, 10); if (zip_set_file_compression(za, idx, method, flags) < 0) { fprintf(stderr, "can't set file compression method at index '%" PRIu64 "' to '%s', flags '%" PRIu32 "': %s\n", idx, argv[1], flags, zip_strerror(za)); return -1; } return 0; } static int set_file_encryption(char *argv[]) { zip_uint16_t method; zip_uint64_t idx; char *password; idx = strtoull(argv[0], NULL, 10); method = get_encryption_method(argv[1]); password = argv[2]; if (strlen(password) == 0) { password = NULL; } if (zip_file_set_encryption(za, idx, method, password) < 0) { fprintf(stderr, "can't set file encryption method at index '%" PRIu64 "' to '%s': %s\n", idx, argv[1], zip_strerror(za)); return -1; } return 0; } static int set_file_dostime(char *argv[]) { /* set file last modification time (mtime) directly */ zip_uint16_t dostime, dosdate; zip_uint64_t idx; idx = strtoull(argv[0], NULL, 10); dostime = (zip_uint16_t)strtoull(argv[1], NULL, 10); dosdate = (zip_uint16_t)strtoull(argv[2], NULL, 10); if (zip_file_set_dostime(za, idx, dostime, dosdate, 0) < 0) { fprintf(stderr, "can't set file dostime at index '%" PRIu64 "' to '%d'/'%d': %s\n", idx, (int)dostime, (int)dosdate, zip_strerror(za)); return -1; } return 0; } static int set_file_mtime(char *argv[]) { /* set file last modification time (mtime) */ time_t mtime; zip_uint64_t idx; idx = strtoull(argv[0], NULL, 10); mtime = (time_t)strtoull(argv[1], NULL, 10); if (zip_file_set_mtime(za, idx, mtime, 0) < 0) { fprintf(stderr, "can't set file mtime at index '%" PRIu64 "' to '%lld': %s\n", idx, (long long)mtime, zip_strerror(za)); return -1; } return 0; } static int set_file_mtime_all(char *argv[]) { /* set last modification time (mtime) for all files */ time_t mtime; zip_int64_t num_entries; zip_uint64_t idx; mtime = (time_t)strtoull(argv[0], NULL, 10); if ((num_entries = zip_get_num_entries(za, 0)) < 0) { fprintf(stderr, "can't get number of entries: %s\n", zip_strerror(za)); return -1; } for (idx = 0; idx < (zip_uint64_t)num_entries; idx++) { if (zip_file_set_mtime(za, idx, mtime, 0) < 0) { fprintf(stderr, "can't set file mtime at index '%" PRIu64 "' to '%lld': %s\n", idx, (long long)mtime, zip_strerror(za)); return -1; } } return 0; } static int set_password(char *argv[]) { /* set default password */ if (zip_set_default_password(za, argv[0]) < 0) { fprintf(stderr, "can't set default password to '%s'\n", argv[0]); return -1; } return 0; } static int zstat(char *argv[]) { zip_uint64_t idx; char buf[100]; struct zip_stat sb; idx = strtoull(argv[0], NULL, 10); if (zip_stat_index(za, idx, stat_flags, &sb) < 0) { fprintf(stderr, "zip_stat_index failed on '%" PRIu64 "' failed: %s\n", idx, zip_strerror(za)); return -1; } if (sb.valid & ZIP_STAT_NAME) printf("name: '%s'\n", encode_filename(sb.name)); if (sb.valid & ZIP_STAT_INDEX) printf("index: '%" PRIu64 "'\n", sb.index); if (sb.valid & ZIP_STAT_SIZE) printf("size: '%" PRIu64 "'\n", sb.size); if (sb.valid & ZIP_STAT_COMP_SIZE) printf("compressed size: '%" PRIu64 "'\n", sb.comp_size); if (sb.valid & ZIP_STAT_MTIME) { struct tm *tpm; struct tm tm; tpm = zip_localtime(&sb.mtime, &tm); if (tpm == NULL) { printf("mtime: \n"); } else { strftime(buf, sizeof(buf), "%a %b %d %Y %H:%M:%S", tpm); printf("mtime: '%s'\n", buf); } } if (sb.valid & ZIP_STAT_CRC) printf("crc: '%0x'\n", sb.crc); if (sb.valid & ZIP_STAT_COMP_METHOD) printf("compression method: '%d'\n", sb.comp_method); if (sb.valid & ZIP_STAT_ENCRYPTION_METHOD) printf("encryption method: '%d'\n", sb.encryption_method); if (sb.valid & ZIP_STAT_FLAGS) printf("flags: '%ld'\n", (long)sb.flags); printf("\n"); return 0; } static int parse_archive_flag(const char* arg) { if (strcasecmp(arg, "rdonly") == 0) { return ZIP_AFL_RDONLY; } else if (strcasecmp(arg, "is-torrentzip") == 0) { return ZIP_AFL_IS_TORRENTZIP; } else if (strcasecmp(arg, "want-torrentzip") == 0) { return ZIP_AFL_WANT_TORRENTZIP; } else if (strcasecmp(arg, "create-or-keep-file-for-empty-archive") == 0) { return ZIP_AFL_CREATE_OR_KEEP_FILE_FOR_EMPTY_ARCHIVE; } return -1; } static zip_flags_t get_flags(const char *arg) { zip_flags_t flags = 0; if (strchr(arg, 'C') != NULL) flags |= ZIP_FL_NOCASE; if (strchr(arg, 'c') != NULL) flags |= ZIP_FL_CENTRAL; if (strchr(arg, 'd') != NULL) flags |= ZIP_FL_NODIR; if (strchr(arg, 'l') != NULL) flags |= ZIP_FL_LOCAL; if (strchr(arg, 'u') != NULL) flags |= ZIP_FL_UNCHANGED; if (strchr(arg, '8') != NULL) flags |= ZIP_FL_ENC_UTF_8; if (strchr(arg, '4') != NULL) flags |= ZIP_FL_ENC_CP437; if (strchr(arg, 'r') != NULL) flags |= ZIP_FL_ENC_RAW; if (strchr(arg, 's') != NULL) flags |= ZIP_FL_ENC_STRICT; return flags; } static zip_int32_t get_compression_method(const char *arg) { if (strcasecmp(arg, "default") == 0) return ZIP_CM_DEFAULT; else if (strcasecmp(arg, "store") == 0) return ZIP_CM_STORE; else if (strcasecmp(arg, "deflate") == 0) return ZIP_CM_DEFLATE; #if defined(HAVE_LIBBZ2) else if (strcasecmp(arg, "bzip2") == 0) return ZIP_CM_BZIP2; #endif #if defined(HAVE_LIBLZMA) /* Disabled - because 7z isn't able to unpack ZIP+LZMA ZIP+LZMA2 archives made this way - and vice versa. else if (strcasecmp(arg, "lzma2") == 0) return ZIP_CM_LZMA2; */ else if (strcasecmp(arg, "lzma") == 0) return ZIP_CM_LZMA; else if (strcasecmp(arg, "xz") == 0) return ZIP_CM_XZ; #endif #if defined(HAVE_LIBZSTD) else if (strcasecmp(arg, "zstd") == 0) return ZIP_CM_ZSTD; #endif else if (strcasecmp(arg, "unknown") == 0) return 100; return 0; /* TODO: error handling */ } static zip_uint16_t get_encryption_method(const char *arg) { if (strcasecmp(arg, "none") == 0) return ZIP_EM_NONE; else if (strcasecmp(arg, "PKWARE") == 0) return ZIP_EM_TRAD_PKWARE; else if (strcasecmp(arg, "AES-128") == 0) return ZIP_EM_AES_128; else if (strcasecmp(arg, "AES-192") == 0) return ZIP_EM_AES_192; else if (strcasecmp(arg, "AES-256") == 0) return ZIP_EM_AES_256; else if (strcasecmp(arg, "unknown") == 0) return 100; return (zip_uint16_t)-1; /* TODO: error handling */ } static void hexdump(const zip_uint8_t *data, zip_uint16_t len) { zip_uint16_t i; if (len <= 0) return; printf("0x"); for (i = 0; i < len; i++) printf("%02x", data[i]); } static zip_t * read_from_file(const char *archive, int flags, zip_error_t *error, zip_uint64_t offset, zip_uint64_t length) { zip_t *zaa; zip_source_t *source; int err; if (offset == 0 && length == 0) { if (strcmp(archive, "/dev/stdin") == 0) { zaa = zip_fdopen(STDIN_FILENO, flags & ~ZIP_CREATE, &err); } else { zaa = zip_open(archive, flags, &err); } if (zaa == NULL) { zip_error_set(error, err, errno); return NULL; } } else { if (length > ZIP_INT64_MAX) { zip_error_set(error, ZIP_ER_INVAL, 0); return NULL; } if ((source = zip_source_file_create(archive, offset, (zip_int64_t)length, error)) == NULL || (zaa = zip_open_from_source(source, flags, error)) == NULL) { zip_source_free(source); return NULL; } } return zaa; } dispatch_table_t dispatch_table[] = {{"add", 2, "name content", "add file called name using content", add}, {"add_dir", 1, "name", "add directory", add_dir}, {"add_file", 4, "name file_to_add offset len", "add file to archive, len bytes starting from offset", add_file}, {"add_from_zip", 5, "name archivename index offset len", "add file from another archive, len bytes starting from offset", add_from_zip}, {"cat", 1, "index", "output file contents to stdout", cat}, {"cat_partial", 3, "index start length", "output partial file contents to stdout", cat_partial}, {"count_extra", 2, "index flags", "show number of extra fields for archive entry", count_extra}, {"count_extra_by_id", 3, "index extra_id flags", "show number of extra fields of type extra_id for archive entry", count_extra_by_id}, {"delete", 1, "index", "remove entry", delete}, {"delete_extra", 3, "index extra_idx flags", "remove extra field", delete_extra}, {"delete_extra_by_id", 4, "index extra_id extra_index flags", "remove extra field of type extra_id", delete_extra_by_id}, {"get_archive_comment", 0, "", "show archive comment", get_archive_comment}, {"get_archive_flag", 1, "flag", "show archive flag", get_archive_flag}, {"get_extra", 3, "index extra_index flags", "show extra field", get_extra}, {"get_extra_by_id", 4, "index extra_id extra_index flags", "show extra field of type extra_id", get_extra_by_id}, {"get_file_comment", 1, "index", "get file comment", get_file_comment}, {"get_num_entries", 1, "flags", "get number of entries in archive", get_num_entries}, {"name_locate", 2, "name flags", "find entry in archive", name_locate}, {"print_progress", 0, "", "print progress during zip_close()", print_progress}, {"rename", 2, "index name", "rename entry", zrename}, {"replace_file_contents", 2, "index data", "replace entry with data", replace_file_contents}, {"set_archive_comment", 1, "comment", "set archive comment", set_archive_comment}, {"set_archive_flag", 2, "flag", "set archive flag", set_archive_flag}, {"set_extra", 5, "index extra_id extra_index flags value", "set extra field", set_extra}, {"set_file_comment", 2, "index comment", "set file comment", set_file_comment}, {"set_file_compression", 3, "index method compression_flags", "set file compression method", set_file_compression}, {"set_file_dostime", 3, "index time date", "set file modification time and date (DOS format)", set_file_dostime}, {"set_file_encryption", 3, "index method password", "set file encryption method", set_file_encryption}, {"set_file_mtime", 2, "index timestamp", "set file modification time", set_file_mtime}, {"set_file_mtime_all", 1, "timestamp", "set file modification time for all files", set_file_mtime_all}, {"set_password", 1, "password", "set default password for encryption", set_password}, {"stat", 1, "index", "print information about entry", zstat} #ifdef DISPATCH_REGRESS , DISPATCH_REGRESS #endif }; static int dispatch(int argc, char *argv[]) { unsigned int i; for (i = 0; i < sizeof(dispatch_table) / sizeof(dispatch_table_t); i++) { if (strcmp(dispatch_table[i].cmdline_name, argv[0]) == 0) { argc--; argv++; /* 1 for the command, argument_count for the arguments */ if (argc < dispatch_table[i].argument_count) { fprintf(stderr, "not enough arguments for command '%s': %d available, %d needed\n", dispatch_table[i].cmdline_name, argc, dispatch_table[i].argument_count); return -1; } if (dispatch_table[i].function(argv) == 0) return 1 + dispatch_table[i].argument_count; return -1; } } fprintf(stderr, "unknown command '%s'\n", argv[0]); return -1; } static void usage(const char *progname, const char *reason) { unsigned int i; FILE *out; if (reason == NULL) out = stdout; else out = stderr; fprintf(out, "usage: %s [-ceghnrst]" USAGE_REGRESS " [-l len] [-o offset] archive command1 [args] [command2 [args] ...]\n", progname); if (reason != NULL) { fprintf(out, "%s\n", reason); exit(1); } fprintf(out, "\nSupported options are:\n" "\t-c\t\tcheck consistency\n" "\t-e\t\terror if archive already exists (only useful with -n)\n" #ifdef FOR_REGRESS "\t-F size\t\tfragment size for in memory archive\n" #endif "\t-g\t\tguess file name encoding (for stat)\n" #ifdef FOR_REGRESS "\t-H\t\twrite files with holes compactly\n" #endif "\t-h\t\tdisplay this usage\n" "\t-l len\t\tonly use len bytes of file\n" #ifdef FOR_REGRESS "\t-m\t\tread archive into memory, and modify there; write out at end\n" #endif "\t-n\t\tcreate archive if it doesn't exist\n" "\t-o offset\tstart reading file at offset\n" "\t-r\t\tprint raw file name encoding without translation (for stat)\n" "\t-s\t\tfollow file name convention strictly (for stat)\n" "\t-t\t\tdisregard current archive contents, if any\n"); fprintf(out, "\nSupported commands and arguments are:\n"); for (i = 0; i < sizeof(dispatch_table) / sizeof(dispatch_table_t); i++) { fprintf(out, "\t%s %s\n\t %s\n\n", dispatch_table[i].cmdline_name, dispatch_table[i].arg_names, dispatch_table[i].description); } fprintf(out, "\nSupported flags are:\n" "\t0\t(no flags)\n" "\t4\tZIP_FL_ENC_CP437\n" "\t8\tZIP_FL_ENC_UTF_8\n" "\tC\tZIP_FL_NOCASE\n" "\tc\tZIP_FL_CENTRAL\n" "\td\tZIP_FL_NODIR\n" "\tl\tZIP_FL_LOCAL\n" "\tr\tZIP_FL_ENC_RAW\n" "\ts\tZIP_FL_ENC_STRICT\n" "\tu\tZIP_FL_UNCHANGED\n"); fprintf(out, "\nSupported archive flags are:\n" "\tcreate-or-keep-empty-file-for-archive\n" "\tis-torrentzip\n" "\trdonly\n" "\twant-torrentzip\n"); fprintf(out, "\nSupported compression methods are:\n" "\tdefault\n"); if (zip_compression_method_supported(ZIP_CM_BZIP2, 1)) { fprintf(out, "\tbzip2\n"); } fprintf(out, "\tdeflate\n" "\tstore\n"); if (zip_compression_method_supported(ZIP_CM_XZ, 1)) { fprintf(out, "\txz\n"); } if (zip_compression_method_supported(ZIP_CM_ZSTD, 1)) { fprintf(out, "\tzstd\n"); } fprintf(out, "\nSupported encryption methods are:\n" "\tnone\n"); if (zip_encryption_method_supported(ZIP_EM_AES_128, 1)) { fprintf(out, "\tAES-128\n"); } if (zip_encryption_method_supported(ZIP_EM_AES_192, 1)) { fprintf(out, "\tAES-192\n"); } if (zip_encryption_method_supported(ZIP_EM_AES_256, 1)) { fprintf(out, "\tAES-256\n"); } fprintf(out, "\tPKWARE\n"); fprintf(out, "\nThe index is zero-based.\n"); exit(0); } #ifndef FOR_REGRESS #define ziptool_open read_from_file int ziptool_post_close(const char *archive) { return 0; } #endif int main(int argc, char *argv[]) { const char *archive; unsigned int i; int c, arg, err, flags; const char *prg; zip_uint64_t len = 0, offset = 0; zip_error_t error; flags = 0; prg = argv[0]; while ((c = getopt(argc, argv, "ceghl:no:rst" OPTIONS_REGRESS)) != -1) { switch (c) { case 'c': flags |= ZIP_CHECKCONS; break; case 'e': flags |= ZIP_EXCL; break; case 'g': stat_flags = ZIP_FL_ENC_GUESS; break; case 'h': usage(prg, NULL); break; case 'l': len = strtoull(optarg, NULL, 10); break; case 'n': flags |= ZIP_CREATE; break; case 'o': offset = strtoull(optarg, NULL, 10); break; case 'r': stat_flags = ZIP_FL_ENC_RAW; break; case 's': stat_flags = ZIP_FL_ENC_STRICT; break; case 't': flags |= ZIP_TRUNCATE; break; #ifdef GETOPT_REGRESS GETOPT_REGRESS #endif default: { char reason[128]; snprintf(reason, sizeof(reason), "invalid option -%c", optopt); usage(prg, reason); } } } if (optind >= argc - 1) usage(prg, "too few arguments"); arg = optind; archive = argv[arg++]; if (flags == 0) flags = ZIP_CREATE; zip_error_init(&error); za = ziptool_open(archive, flags, &error, offset, len); if (za == NULL) { fprintf(stderr, "can't open zip archive '%s': %s\n", archive, zip_error_strerror(&error)); zip_error_fini(&error); return 1; } zip_error_fini(&error); #ifdef REGRESS_PREPARE_ARGS REGRESS_PREPARE_ARGS #endif err = 0; while (arg < argc) { int ret; ret = dispatch(argc - arg, argv + arg); if (ret > 0) { arg += ret; } else { err = 1; break; } } #ifdef PRECLOSE_REGRESS PRECLOSE_REGRESS; #endif if (zip_close(za) == -1) { fprintf(stderr, "can't close zip archive '%s': %s\n", archive, zip_strerror(za)); return 1; } if (ziptool_post_close(archive) < 0) { err = 1; } for (i = 0; i < z_in_count; i++) { if (zip_close(z_in[i]) < 0) { err = 1; } } return err; } #define BIN2HEX(n) ((n) >= 10 ? (n) + 'a' - 10 : (n) + '0') #define HEX2BIN(c) (((c) >= '0' && (c) <= '9') ? (c) - '0' : ((c) >= 'A' && (c) <= 'F') ? (c) - 'A' + 10 : (c) - 'a' + 10) #define FILENAME_BUFFER_LENGTH (2 * 64 * 1024) static char filename_buffer[FILENAME_BUFFER_LENGTH + 1]; static const char* encode_filename(const char* name) { char *t = filename_buffer; if (!hex_encoded_filenames) { const char* s = name; if (strlen(name) > FILENAME_BUFFER_LENGTH) { fprintf(stderr, "internal buffer limit reached, increase buffer size\n"); exit(1); } while (*s != '\0') { if (s[0] == '\r' && s[1] == '\n') { s++; continue; } *(t++) = *(s++); } } else { const unsigned char *s = (const unsigned char *)name; if (strlen(name) > FILENAME_BUFFER_LENGTH / 2) { fprintf(stderr, "internal buffer limit reached, increase buffer size\n"); exit(1); } while (*s != '\0') { *(t++) = BIN2HEX(*s >> 4); *(t++) = BIN2HEX(*s & 0xf); s += 1; } } *t = '\0'; return filename_buffer; } static const char* decode_filename(const char* name) { if (!hex_encoded_filenames) { return name; } if (strlen(name) > FILENAME_BUFFER_LENGTH * 2) { fprintf(stderr, "internal buffer limit reached, increase buffer size\n"); exit(1); } // TODO: check that strlen(name) % 2 == 0 // TODO: check with strspn that s is all hex digits unsigned char *t = (unsigned char*)filename_buffer; const char *s = name; while (*s != '\0') { *(t++) = (HEX2BIN(s[0]) << 4) | HEX2BIN(s[1]); s += 2; } *t = '\0'; return filename_buffer; } ================================================ FILE: external/libzip/vcpkg.json ================================================ { "dependencies": [ "bzip2", "liblzma", "zlib", "zstd" ] } ================================================ FILE: external/libzip/zipconf.h.in ================================================ #ifndef _HAD_ZIPCONF_H #define _HAD_ZIPCONF_H /* zipconf.h -- platform specific include file This file was generated automatically by CMake based on ../cmake-zipconf.h.in. */ #define LIBZIP_VERSION "${libzip_VERSION}" #define LIBZIP_VERSION_MAJOR ${libzip_VERSION_MAJOR} #define LIBZIP_VERSION_MINOR ${libzip_VERSION_MINOR} #define LIBZIP_VERSION_MICRO ${libzip_VERSION_PATCH} #cmakedefine ZIP_STATIC ${LIBZIP_TYPES_INCLUDE} typedef ${ZIP_INT8_T} zip_int8_t; typedef ${ZIP_UINT8_T} zip_uint8_t; typedef ${ZIP_INT16_T} zip_int16_t; typedef ${ZIP_UINT16_T} zip_uint16_t; typedef ${ZIP_INT32_T} zip_int32_t; typedef ${ZIP_UINT32_T} zip_uint32_t; typedef ${ZIP_INT64_T} zip_int64_t; typedef ${ZIP_UINT64_T} zip_uint64_t; #define ZIP_INT8_MIN (-ZIP_INT8_MAX-1) #define ZIP_INT8_MAX 0x7f #define ZIP_UINT8_MAX 0xff #define ZIP_INT16_MIN (-ZIP_INT16_MAX-1) #define ZIP_INT16_MAX 0x7fff #define ZIP_UINT16_MAX 0xffff #define ZIP_INT32_MIN (-ZIP_INT32_MAX-1L) #define ZIP_INT32_MAX 0x7fffffffL #define ZIP_UINT32_MAX 0xffffffffLU #define ZIP_INT64_MIN (-ZIP_INT64_MAX-1LL) #define ZIP_INT64_MAX 0x7fffffffffffffffLL #define ZIP_UINT64_MAX 0xffffffffffffffffULL #endif /* zipconf.h */ ================================================ FILE: external/pdfium/README.md ================================================ # PDFium prebuilts This folder is populated by `app/scripts/vendor_doc_deps.sh` or `app/scripts/vendor_doc_deps.ps1`. Expected layout: - linux-x64/ - windows-x64/ - macos-arm64/ - macos-x64/ Each folder should contain `include/` and the platform PDFium library under `lib/`: - Linux: `lib/libpdfium.so` - Windows: `bin/pdfium.dll` + `lib/pdfium.dll.lib` - macOS: `lib/libpdfium.dylib` (arm64 or x64) ================================================ FILE: external/pdfium/linux-x64/LICENSE ================================================ Copyright 2014-2025 Benoit Blanchon Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. This package also includes third-party software. See the licenses/ directory for their respective licenses. ================================================ FILE: external/pdfium/linux-x64/PDFiumConfig.cmake ================================================ # PDFium Package Configuration for CMake # # To use PDFium in your CMake project: # # 1. set the environment variable PDFium_DIR to the folder containing this file. # 2. in your CMakeLists.txt, add # find_package(PDFium) # 3. then link your executable with PDFium # target_link_libraries(my_exe pdfium) include(FindPackageHandleStandardArgs) find_path(PDFium_INCLUDE_DIR NAMES "fpdfview.h" PATHS "${CMAKE_CURRENT_LIST_DIR}" PATH_SUFFIXES "include" ) set(PDFium_VERSION "147.0.7713.0") if(WIN32) find_file(PDFium_LIBRARY NAMES "pdfium.dll" PATHS "${CMAKE_CURRENT_LIST_DIR}" PATH_SUFFIXES "bin") find_file(PDFium_IMPLIB NAMES "pdfium.dll.lib" PATHS "${CMAKE_CURRENT_LIST_DIR}" PATH_SUFFIXES "lib") add_library(pdfium SHARED IMPORTED) set_target_properties(pdfium PROPERTIES IMPORTED_LOCATION "${PDFium_LIBRARY}" IMPORTED_IMPLIB "${PDFium_IMPLIB}" INTERFACE_INCLUDE_DIRECTORIES "${PDFium_INCLUDE_DIR};${PDFium_INCLUDE_DIR}/cpp" ) find_package_handle_standard_args(PDFium REQUIRED_VARS PDFium_LIBRARY PDFium_IMPLIB PDFium_INCLUDE_DIR VERSION_VAR PDFium_VERSION ) else() find_library(PDFium_LIBRARY NAMES "pdfium" PATHS "${CMAKE_CURRENT_LIST_DIR}" PATH_SUFFIXES "lib") add_library(pdfium SHARED IMPORTED) set_target_properties(pdfium PROPERTIES IMPORTED_LOCATION "${PDFium_LIBRARY}" INTERFACE_INCLUDE_DIRECTORIES "${PDFium_INCLUDE_DIR};${PDFium_INCLUDE_DIR}/cpp" ) find_package_handle_standard_args(PDFium REQUIRED_VARS PDFium_LIBRARY PDFium_INCLUDE_DIR VERSION_VAR PDFium_VERSION ) endif() ================================================ FILE: external/pdfium/linux-x64/VERSION ================================================ MAJOR=147 MINOR=0 BUILD=7713 PATCH=0 ================================================ FILE: external/pdfium/linux-x64/args.gn ================================================ clang_use_chrome_plugins = false is_component_build = false is_debug = false pdf_enable_v8 = false pdf_enable_xfa = false pdf_is_standalone = true pdf_use_partition_alloc = false target_cpu = "x64" target_os = "linux" treat_warnings_as_errors = false ================================================ FILE: external/pdfium/linux-x64/include/cpp/fpdf_deleters.h ================================================ // Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef PUBLIC_CPP_FPDF_DELETERS_H_ #define PUBLIC_CPP_FPDF_DELETERS_H_ #include "../fpdf_annot.h" #include "../fpdf_dataavail.h" #include "../fpdf_edit.h" #include "../fpdf_formfill.h" #include "../fpdf_javascript.h" #include "../fpdf_structtree.h" #include "../fpdf_text.h" #include "../fpdf_transformpage.h" #include "../fpdfview.h" // Custom deleters for using FPDF_* types with std::unique_ptr<>. struct FPDFAnnotationDeleter { inline void operator()(FPDF_ANNOTATION annot) { FPDFPage_CloseAnnot(annot); } }; struct FPDFAvailDeleter { inline void operator()(FPDF_AVAIL avail) { FPDFAvail_Destroy(avail); } }; struct FPDFBitmapDeleter { inline void operator()(FPDF_BITMAP bitmap) { FPDFBitmap_Destroy(bitmap); } }; struct FPDFClipPathDeleter { inline void operator()(FPDF_CLIPPATH clip_path) { FPDF_DestroyClipPath(clip_path); } }; struct FPDFDocumentDeleter { inline void operator()(FPDF_DOCUMENT doc) { FPDF_CloseDocument(doc); } }; struct FPDFFontDeleter { inline void operator()(FPDF_FONT font) { FPDFFont_Close(font); } }; struct FPDFFormHandleDeleter { inline void operator()(FPDF_FORMHANDLE form) { FPDFDOC_ExitFormFillEnvironment(form); } }; struct FPDFJavaScriptActionDeleter { inline void operator()(FPDF_JAVASCRIPT_ACTION javascript) { FPDFDoc_CloseJavaScriptAction(javascript); } }; struct FPDFPageDeleter { inline void operator()(FPDF_PAGE page) { FPDF_ClosePage(page); } }; struct FPDFPageLinkDeleter { inline void operator()(FPDF_PAGELINK pagelink) { FPDFLink_CloseWebLinks(pagelink); } }; struct FPDFPageObjectDeleter { inline void operator()(FPDF_PAGEOBJECT object) { FPDFPageObj_Destroy(object); } }; struct FPDFStructTreeDeleter { inline void operator()(FPDF_STRUCTTREE tree) { FPDF_StructTree_Close(tree); } }; struct FPDFTextFindDeleter { inline void operator()(FPDF_SCHHANDLE handle) { FPDFText_FindClose(handle); } }; struct FPDFTextPageDeleter { inline void operator()(FPDF_TEXTPAGE text) { FPDFText_ClosePage(text); } }; #endif // PUBLIC_CPP_FPDF_DELETERS_H_ ================================================ FILE: external/pdfium/linux-x64/include/cpp/fpdf_scopers.h ================================================ // Copyright 2018 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef PUBLIC_CPP_FPDF_SCOPERS_H_ #define PUBLIC_CPP_FPDF_SCOPERS_H_ #include #include #include "fpdf_deleters.h" // Versions of FPDF types that clean up the object at scope exit. using ScopedFPDFAnnotation = std::unique_ptr::type, FPDFAnnotationDeleter>; using ScopedFPDFAvail = std::unique_ptr::type, FPDFAvailDeleter>; using ScopedFPDFBitmap = std::unique_ptr::type, FPDFBitmapDeleter>; using ScopedFPDFClipPath = std::unique_ptr::type, FPDFClipPathDeleter>; using ScopedFPDFDocument = std::unique_ptr::type, FPDFDocumentDeleter>; using ScopedFPDFFont = std::unique_ptr::type, FPDFFontDeleter>; using ScopedFPDFFormHandle = std::unique_ptr::type, FPDFFormHandleDeleter>; using ScopedFPDFJavaScriptAction = std::unique_ptr::type, FPDFJavaScriptActionDeleter>; using ScopedFPDFPage = std::unique_ptr::type, FPDFPageDeleter>; using ScopedFPDFPageLink = std::unique_ptr::type, FPDFPageLinkDeleter>; using ScopedFPDFPageObject = std::unique_ptr::type, FPDFPageObjectDeleter>; using ScopedFPDFStructTree = std::unique_ptr::type, FPDFStructTreeDeleter>; using ScopedFPDFTextFind = std::unique_ptr::type, FPDFTextFindDeleter>; using ScopedFPDFTextPage = std::unique_ptr::type, FPDFTextPageDeleter>; #endif // PUBLIC_CPP_FPDF_SCOPERS_H_ ================================================ FILE: external/pdfium/linux-x64/include/fpdf_annot.h ================================================ // Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef PUBLIC_FPDF_ANNOT_H_ #define PUBLIC_FPDF_ANNOT_H_ #include // NOLINTNEXTLINE(build/include) #include "fpdfview.h" // NOLINTNEXTLINE(build/include) #include "fpdf_formfill.h" #ifdef __cplusplus extern "C" { #endif // __cplusplus #define FPDF_ANNOT_UNKNOWN 0 #define FPDF_ANNOT_TEXT 1 #define FPDF_ANNOT_LINK 2 #define FPDF_ANNOT_FREETEXT 3 #define FPDF_ANNOT_LINE 4 #define FPDF_ANNOT_SQUARE 5 #define FPDF_ANNOT_CIRCLE 6 #define FPDF_ANNOT_POLYGON 7 #define FPDF_ANNOT_POLYLINE 8 #define FPDF_ANNOT_HIGHLIGHT 9 #define FPDF_ANNOT_UNDERLINE 10 #define FPDF_ANNOT_SQUIGGLY 11 #define FPDF_ANNOT_STRIKEOUT 12 #define FPDF_ANNOT_STAMP 13 #define FPDF_ANNOT_CARET 14 #define FPDF_ANNOT_INK 15 #define FPDF_ANNOT_POPUP 16 #define FPDF_ANNOT_FILEATTACHMENT 17 #define FPDF_ANNOT_SOUND 18 #define FPDF_ANNOT_MOVIE 19 #define FPDF_ANNOT_WIDGET 20 #define FPDF_ANNOT_SCREEN 21 #define FPDF_ANNOT_PRINTERMARK 22 #define FPDF_ANNOT_TRAPNET 23 #define FPDF_ANNOT_WATERMARK 24 #define FPDF_ANNOT_THREED 25 #define FPDF_ANNOT_RICHMEDIA 26 #define FPDF_ANNOT_XFAWIDGET 27 #define FPDF_ANNOT_REDACT 28 // Refer to PDF Reference (6th edition) table 8.16 for all annotation flags. #define FPDF_ANNOT_FLAG_NONE 0 #define FPDF_ANNOT_FLAG_INVISIBLE (1 << 0) #define FPDF_ANNOT_FLAG_HIDDEN (1 << 1) #define FPDF_ANNOT_FLAG_PRINT (1 << 2) #define FPDF_ANNOT_FLAG_NOZOOM (1 << 3) #define FPDF_ANNOT_FLAG_NOROTATE (1 << 4) #define FPDF_ANNOT_FLAG_NOVIEW (1 << 5) #define FPDF_ANNOT_FLAG_READONLY (1 << 6) #define FPDF_ANNOT_FLAG_LOCKED (1 << 7) #define FPDF_ANNOT_FLAG_TOGGLENOVIEW (1 << 8) #define FPDF_ANNOT_APPEARANCEMODE_NORMAL 0 #define FPDF_ANNOT_APPEARANCEMODE_ROLLOVER 1 #define FPDF_ANNOT_APPEARANCEMODE_DOWN 2 #define FPDF_ANNOT_APPEARANCEMODE_COUNT 3 // Refer to PDF Reference version 1.7 table 8.70 for field flags common to all // interactive form field types. #define FPDF_FORMFLAG_NONE 0 #define FPDF_FORMFLAG_READONLY (1 << 0) #define FPDF_FORMFLAG_REQUIRED (1 << 1) #define FPDF_FORMFLAG_NOEXPORT (1 << 2) // Refer to PDF Reference version 1.7 table 8.77 for field flags specific to // interactive form text fields. #define FPDF_FORMFLAG_TEXT_MULTILINE (1 << 12) #define FPDF_FORMFLAG_TEXT_PASSWORD (1 << 13) // Refer to PDF Reference version 1.7 table 8.79 for field flags specific to // interactive form choice fields. #define FPDF_FORMFLAG_CHOICE_COMBO (1 << 17) #define FPDF_FORMFLAG_CHOICE_EDIT (1 << 18) #define FPDF_FORMFLAG_CHOICE_MULTI_SELECT (1 << 21) // Additional actions type of form field: // K, on key stroke, JavaScript action. // F, on format, JavaScript action. // V, on validate, JavaScript action. // C, on calculate, JavaScript action. #define FPDF_ANNOT_AACTION_KEY_STROKE 12 #define FPDF_ANNOT_AACTION_FORMAT 13 #define FPDF_ANNOT_AACTION_VALIDATE 14 #define FPDF_ANNOT_AACTION_CALCULATE 15 typedef enum FPDFANNOT_COLORTYPE { FPDFANNOT_COLORTYPE_Color = 0, FPDFANNOT_COLORTYPE_InteriorColor } FPDFANNOT_COLORTYPE; // Experimental API. // Check if an annotation subtype is currently supported for creation. // Currently supported subtypes: // - circle // - fileattachment // - freetext // - highlight // - ink // - link // - popup // - square, // - squiggly // - stamp // - strikeout // - text // - underline // // subtype - the subtype to be checked. // // Returns true if this subtype supported. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_IsSupportedSubtype(FPDF_ANNOTATION_SUBTYPE subtype); // Experimental API. // Create an annotation in |page| of the subtype |subtype|. If the specified // subtype is illegal or unsupported, then a new annotation will not be created. // Must call FPDFPage_CloseAnnot() when the annotation returned by this // function is no longer needed. // // page - handle to a page. // subtype - the subtype of the new annotation. // // Returns a handle to the new annotation object, or NULL on failure. FPDF_EXPORT FPDF_ANNOTATION FPDF_CALLCONV FPDFPage_CreateAnnot(FPDF_PAGE page, FPDF_ANNOTATION_SUBTYPE subtype); // Experimental API. // Get the number of annotations in |page|. // // page - handle to a page. // // Returns the number of annotations in |page|. FPDF_EXPORT int FPDF_CALLCONV FPDFPage_GetAnnotCount(FPDF_PAGE page); // Experimental API. // Get annotation in |page| at |index|. Must call FPDFPage_CloseAnnot() when the // annotation returned by this function is no longer needed. // // page - handle to a page. // index - the index of the annotation. // // Returns a handle to the annotation object, or NULL on failure. FPDF_EXPORT FPDF_ANNOTATION FPDF_CALLCONV FPDFPage_GetAnnot(FPDF_PAGE page, int index); // Experimental API. // Get the index of |annot| in |page|. This is the opposite of // FPDFPage_GetAnnot(). // // page - handle to the page that the annotation is on. // annot - handle to an annotation. // // Returns the index of |annot|, or -1 on failure. FPDF_EXPORT int FPDF_CALLCONV FPDFPage_GetAnnotIndex(FPDF_PAGE page, FPDF_ANNOTATION annot); // Experimental API. // Close an annotation. Must be called when the annotation returned by // FPDFPage_CreateAnnot() or FPDFPage_GetAnnot() is no longer needed. This // function does not remove the annotation from the document. // // annot - handle to an annotation. FPDF_EXPORT void FPDF_CALLCONV FPDFPage_CloseAnnot(FPDF_ANNOTATION annot); // Experimental API. // Remove the annotation in |page| at |index|. // // page - handle to a page. // index - the index of the annotation. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_RemoveAnnot(FPDF_PAGE page, int index); // Experimental API. // Get the subtype of an annotation. // // annot - handle to an annotation. // // Returns the annotation subtype. FPDF_EXPORT FPDF_ANNOTATION_SUBTYPE FPDF_CALLCONV FPDFAnnot_GetSubtype(FPDF_ANNOTATION annot); // Experimental API. // Check if an annotation subtype is currently supported for object extraction, // update, and removal. // Currently supported subtypes: ink and stamp. // // subtype - the subtype to be checked. // // Returns true if this subtype supported. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_IsObjectSupportedSubtype(FPDF_ANNOTATION_SUBTYPE subtype); // Experimental API. // Update |obj| in |annot|. |obj| must be in |annot| already and must have // been retrieved by FPDFAnnot_GetObject(). Currently, only ink and stamp // annotations are supported by this API. Also note that only path, image, and // text objects have APIs for modification; see FPDFPath_*(), FPDFText_*(), and // FPDFImageObj_*(). // // annot - handle to an annotation. // obj - handle to the object that |annot| needs to update. // // Return true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_UpdateObject(FPDF_ANNOTATION annot, FPDF_PAGEOBJECT obj); // Experimental API. // Add a new InkStroke, represented by an array of points, to the InkList of // |annot|. The API creates an InkList if one doesn't already exist in |annot|. // This API works only for ink annotations. Please refer to ISO 32000-1:2008 // spec, section 12.5.6.13. // // annot - handle to an annotation. // points - pointer to a FS_POINTF array representing input points. // point_count - number of elements in |points| array. This should not exceed // the maximum value that can be represented by an int32_t). // // Returns the 0-based index at which the new InkStroke is added in the InkList // of the |annot|. Returns -1 on failure. FPDF_EXPORT int FPDF_CALLCONV FPDFAnnot_AddInkStroke(FPDF_ANNOTATION annot, const FS_POINTF* points, size_t point_count); // Experimental API. // Removes an InkList in |annot|. // This API works only for ink annotations. // // annot - handle to an annotation. // // Return true on successful removal of /InkList entry from context of the // non-null ink |annot|. Returns false on failure. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_RemoveInkList(FPDF_ANNOTATION annot); // Experimental API. // Add |obj| to |annot|. |obj| must have been created by // FPDFPageObj_CreateNew{Path|Rect}() or FPDFPageObj_New{Text|Image}Obj(), and // will be owned by |annot|. Note that an |obj| cannot belong to more than one // |annot|. Currently, only ink and stamp annotations are supported by this API. // Also note that only path, image, and text objects have APIs for creation. // // annot - handle to an annotation. // obj - handle to the object that is to be added to |annot|. // // Return true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_AppendObject(FPDF_ANNOTATION annot, FPDF_PAGEOBJECT obj); // Experimental API. // Get the total number of objects in |annot|, including path objects, text // objects, external objects, image objects, and shading objects. // // annot - handle to an annotation. // // Returns the number of objects in |annot|. FPDF_EXPORT int FPDF_CALLCONV FPDFAnnot_GetObjectCount(FPDF_ANNOTATION annot); // Experimental API. // Get the object in |annot| at |index|. // // annot - handle to an annotation. // index - the index of the object. // // Return a handle to the object, or NULL on failure. FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV FPDFAnnot_GetObject(FPDF_ANNOTATION annot, int index); // Experimental API. // Remove the object in |annot| at |index|. // // annot - handle to an annotation. // index - the index of the object to be removed. // // Return true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_RemoveObject(FPDF_ANNOTATION annot, int index); // Experimental API. // Set the color of an annotation. Fails when called on annotations with // appearance streams already defined; instead use // FPDFPageObj_Set{Stroke|Fill}Color(). // // annot - handle to an annotation. // type - type of the color to be set. // R, G, B - buffer to hold the RGB value of the color. Ranges from 0 to 255. // A - buffer to hold the opacity. Ranges from 0 to 255. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetColor(FPDF_ANNOTATION annot, FPDFANNOT_COLORTYPE type, unsigned int R, unsigned int G, unsigned int B, unsigned int A); // Experimental API. // Get the color of an annotation. If no color is specified, default to yellow // for highlight annotation, black for all else. Fails when called on // annotations with appearance streams already defined; instead use // FPDFPageObj_Get{Stroke|Fill}Color(). // // annot - handle to an annotation. // type - type of the color requested. // R, G, B - buffer to hold the RGB value of the color. Ranges from 0 to 255. // A - buffer to hold the opacity. Ranges from 0 to 255. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_GetColor(FPDF_ANNOTATION annot, FPDFANNOT_COLORTYPE type, unsigned int* R, unsigned int* G, unsigned int* B, unsigned int* A); // Experimental API. // Check if the annotation is of a type that has attachment points // (i.e. quadpoints). Quadpoints are the vertices of the rectangle that // encompasses the texts affected by the annotation. They provide the // coordinates in the page where the annotation is attached. Only text markup // annotations (i.e. highlight, strikeout, squiggly, and underline) and link // annotations have quadpoints. // // annot - handle to an annotation. // // Returns true if the annotation is of a type that has quadpoints, false // otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_HasAttachmentPoints(FPDF_ANNOTATION annot); // Experimental API. // Replace the attachment points (i.e. quadpoints) set of an annotation at // |quad_index|. This index needs to be within the result of // FPDFAnnot_CountAttachmentPoints(). // If the annotation's appearance stream is defined and this annotation is of a // type with quadpoints, then update the bounding box too if the new quadpoints // define a bigger one. // // annot - handle to an annotation. // quad_index - index of the set of quadpoints. // quad_points - the quadpoints to be set. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetAttachmentPoints(FPDF_ANNOTATION annot, size_t quad_index, const FS_QUADPOINTSF* quad_points); // Experimental API. // Append to the list of attachment points (i.e. quadpoints) of an annotation. // If the annotation's appearance stream is defined and this annotation is of a // type with quadpoints, then update the bounding box too if the new quadpoints // define a bigger one. // // annot - handle to an annotation. // quad_points - the quadpoints to be set. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_AppendAttachmentPoints(FPDF_ANNOTATION annot, const FS_QUADPOINTSF* quad_points); // Experimental API. // Get the number of sets of quadpoints of an annotation. // // annot - handle to an annotation. // // Returns the number of sets of quadpoints, or 0 on failure. FPDF_EXPORT size_t FPDF_CALLCONV FPDFAnnot_CountAttachmentPoints(FPDF_ANNOTATION annot); // Experimental API. // Get the attachment points (i.e. quadpoints) of an annotation. // // annot - handle to an annotation. // quad_index - index of the set of quadpoints. // quad_points - receives the quadpoints; must not be NULL. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_GetAttachmentPoints(FPDF_ANNOTATION annot, size_t quad_index, FS_QUADPOINTSF* quad_points); // Experimental API. // Set the annotation rectangle defining the location of the annotation. If the // annotation's appearance stream is defined and this annotation is of a type // without quadpoints, then update the bounding box too if the new rectangle // defines a bigger one. // // annot - handle to an annotation. // rect - the annotation rectangle to be set. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetRect(FPDF_ANNOTATION annot, const FS_RECTF* rect); // Experimental API. // Get the annotation rectangle defining the location of the annotation. // // annot - handle to an annotation. // rect - receives the rectangle; must not be NULL. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_GetRect(FPDF_ANNOTATION annot, FS_RECTF* rect); // Experimental API. // Get the vertices of a polygon or polyline annotation. |buffer| is an array of // points of the annotation. If |length| is less than the returned length, or // |annot| or |buffer| is NULL, |buffer| will not be modified. // // annot - handle to an annotation, as returned by e.g. FPDFPage_GetAnnot() // buffer - buffer for holding the points. // length - length of the buffer in points. // // Returns the number of points if the annotation is of type polygon or // polyline, 0 otherwise. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFAnnot_GetVertices(FPDF_ANNOTATION annot, FS_POINTF* buffer, unsigned long length); // Experimental API. // Get the number of paths in the ink list of an ink annotation. // // annot - handle to an annotation, as returned by e.g. FPDFPage_GetAnnot() // // Returns the number of paths in the ink list if the annotation is of type ink, // 0 otherwise. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFAnnot_GetInkListCount(FPDF_ANNOTATION annot); // Experimental API. // Get a path in the ink list of an ink annotation. |buffer| is an array of // points of the path. If |length| is less than the returned length, or |annot| // or |buffer| is NULL, |buffer| will not be modified. // // annot - handle to an annotation, as returned by e.g. FPDFPage_GetAnnot() // path_index - index of the path // buffer - buffer for holding the points. // length - length of the buffer in points. // // Returns the number of points of the path if the annotation is of type ink, 0 // otherwise. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFAnnot_GetInkListPath(FPDF_ANNOTATION annot, unsigned long path_index, FS_POINTF* buffer, unsigned long length); // Experimental API. // Get the starting and ending coordinates of a line annotation. // // annot - handle to an annotation, as returned by e.g. FPDFPage_GetAnnot() // start - starting point // end - ending point // // Returns true if the annotation is of type line, |start| and |end| are not // NULL, false otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_GetLine(FPDF_ANNOTATION annot, FS_POINTF* start, FS_POINTF* end); // Experimental API. // Set the characteristics of the annotation's border (rounded rectangle). // // annot - handle to an annotation // horizontal_radius - horizontal corner radius, in default user space units // vertical_radius - vertical corner radius, in default user space units // border_width - border width, in default user space units // // Returns true if setting the border for |annot| succeeds, false otherwise. // // If |annot| contains an appearance stream that overrides the border values, // then the appearance stream will be removed on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetBorder(FPDF_ANNOTATION annot, float horizontal_radius, float vertical_radius, float border_width); // Experimental API. // Get the characteristics of the annotation's border (rounded rectangle). // // annot - handle to an annotation // horizontal_radius - horizontal corner radius, in default user space units // vertical_radius - vertical corner radius, in default user space units // border_width - border width, in default user space units // // Returns true if |horizontal_radius|, |vertical_radius| and |border_width| are // not NULL, false otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_GetBorder(FPDF_ANNOTATION annot, float* horizontal_radius, float* vertical_radius, float* border_width); // Experimental API. // Get the JavaScript of an event of the annotation's additional actions. // |buffer| is only modified if |buflen| is large enough to hold the whole // JavaScript string. If |buflen| is smaller, the total size of the JavaScript // is still returned, but nothing is copied. If there is no JavaScript for // |event| in |annot|, an empty string is written to |buf| and 2 is returned, // denoting the size of the null terminator in the buffer. On other errors, // nothing is written to |buffer| and 0 is returned. // // hHandle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment(). // annot - handle to an interactive form annotation. // event - event type, one of the FPDF_ANNOT_AACTION_* values. // buffer - buffer for holding the value string, encoded in UTF-16LE. // buflen - length of the buffer in bytes. // // Returns the length of the string value in bytes, including the 2-byte // null terminator. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFAnnot_GetFormAdditionalActionJavaScript(FPDF_FORMHANDLE hHandle, FPDF_ANNOTATION annot, int event, FPDF_WCHAR* buffer, unsigned long buflen); // Experimental API. // Check if |annot|'s dictionary has |key| as a key. // // annot - handle to an annotation. // key - the key to look for, encoded in UTF-8. // // Returns true if |key| exists. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_HasKey(FPDF_ANNOTATION annot, FPDF_BYTESTRING key); // Experimental API. // Get the type of the value corresponding to |key| in |annot|'s dictionary. // // annot - handle to an annotation. // key - the key to look for, encoded in UTF-8. // // Returns the type of the dictionary value. FPDF_EXPORT FPDF_OBJECT_TYPE FPDF_CALLCONV FPDFAnnot_GetValueType(FPDF_ANNOTATION annot, FPDF_BYTESTRING key); // Experimental API. // Set the string value corresponding to |key| in |annot|'s dictionary, // overwriting the existing value if any. The value type would be // FPDF_OBJECT_STRING after this function call succeeds. // // annot - handle to an annotation. // key - the key to the dictionary entry to be set, encoded in UTF-8. // value - the string value to be set, encoded in UTF-16LE. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetStringValue(FPDF_ANNOTATION annot, FPDF_BYTESTRING key, FPDF_WIDESTRING value); // Experimental API. // Get the string value corresponding to |key| in |annot|'s dictionary. |buffer| // is only modified if |buflen| is longer than the length of contents. Note that // if |key| does not exist in the dictionary or if |key|'s corresponding value // in the dictionary is not a string (i.e. the value is not of type // FPDF_OBJECT_STRING or FPDF_OBJECT_NAME), then an empty string would be copied // to |buffer| and the return value would be 2. On other errors, nothing would // be added to |buffer| and the return value would be 0. // // annot - handle to an annotation. // key - the key to the requested dictionary entry, encoded in UTF-8. // buffer - buffer for holding the value string, encoded in UTF-16LE. // buflen - length of the buffer in bytes. // // Returns the length of the string value in bytes. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFAnnot_GetStringValue(FPDF_ANNOTATION annot, FPDF_BYTESTRING key, FPDF_WCHAR* buffer, unsigned long buflen); // Experimental API. // Get the float value corresponding to |key| in |annot|'s dictionary. Writes // value to |value| and returns True if |key| exists in the dictionary and // |key|'s corresponding value is a number (FPDF_OBJECT_NUMBER), False // otherwise. // // annot - handle to an annotation. // key - the key to the requested dictionary entry, encoded in UTF-8. // value - receives the value, must not be NULL. // // Returns True if value found, False otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_GetNumberValue(FPDF_ANNOTATION annot, FPDF_BYTESTRING key, float* value); // Experimental API. // Set the AP (appearance string) in |annot|'s dictionary for a given // |appearanceMode|. // // annot - handle to an annotation. // appearanceMode - the appearance mode (normal, rollover or down) for which // to get the AP. // value - the string value to be set, encoded in UTF-16LE. If // nullptr is passed, the AP is cleared for that mode. If the // mode is Normal, APs for all modes are cleared. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetAP(FPDF_ANNOTATION annot, FPDF_ANNOT_APPEARANCEMODE appearanceMode, FPDF_WIDESTRING value); // Experimental API. // Get the AP (appearance string) from |annot|'s dictionary for a given // |appearanceMode|. // |buffer| is only modified if |buflen| is large enough to hold the whole AP // string. If |buflen| is smaller, the total size of the AP is still returned, // but nothing is copied. // If there is no appearance stream for |annot| in |appearanceMode|, an empty // string is written to |buf| and 2 is returned. // On other errors, nothing is written to |buffer| and 0 is returned. // // annot - handle to an annotation. // appearanceMode - the appearance mode (normal, rollover or down) for which // to get the AP. // buffer - buffer for holding the value string, encoded in UTF-16LE. // buflen - length of the buffer in bytes. // // Returns the length of the string value in bytes. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFAnnot_GetAP(FPDF_ANNOTATION annot, FPDF_ANNOT_APPEARANCEMODE appearanceMode, FPDF_WCHAR* buffer, unsigned long buflen); // Experimental API. // Get the annotation corresponding to |key| in |annot|'s dictionary. Common // keys for linking annotations include "IRT" and "Popup". Must call // FPDFPage_CloseAnnot() when the annotation returned by this function is no // longer needed. // // annot - handle to an annotation. // key - the key to the requested dictionary entry, encoded in UTF-8. // // Returns a handle to the linked annotation object, or NULL on failure. FPDF_EXPORT FPDF_ANNOTATION FPDF_CALLCONV FPDFAnnot_GetLinkedAnnot(FPDF_ANNOTATION annot, FPDF_BYTESTRING key); // Experimental API. // Get the annotation flags of |annot|. // // annot - handle to an annotation. // // Returns the annotation flags. FPDF_EXPORT int FPDF_CALLCONV FPDFAnnot_GetFlags(FPDF_ANNOTATION annot); // Experimental API. // Set the |annot|'s flags to be of the value |flags|. // // annot - handle to an annotation. // flags - the flag values to be set. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetFlags(FPDF_ANNOTATION annot, int flags); // Experimental API. // Get the annotation flags of |annot|. // // hHandle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment(). // annot - handle to an interactive form annotation. // // Returns the annotation flags specific to interactive forms. FPDF_EXPORT int FPDF_CALLCONV FPDFAnnot_GetFormFieldFlags(FPDF_FORMHANDLE handle, FPDF_ANNOTATION annot); // Experimental API. // Sets the form field flags for an interactive form annotation. // // handle - the handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment(). // annot - handle to an interactive form annotation. // flags - the form field flags to be set. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetFormFieldFlags(FPDF_FORMHANDLE handle, FPDF_ANNOTATION annot, int flags); // Experimental API. // Retrieves an interactive form annotation whose rectangle contains a given // point on a page. Must call FPDFPage_CloseAnnot() when the annotation returned // is no longer needed. // // // hHandle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment(). // page - handle to the page, returned by FPDF_LoadPage function. // point - position in PDF "user space". // // Returns the interactive form annotation whose rectangle contains the given // coordinates on the page. If there is no such annotation, return NULL. FPDF_EXPORT FPDF_ANNOTATION FPDF_CALLCONV FPDFAnnot_GetFormFieldAtPoint(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, const FS_POINTF* point); // Experimental API. // Gets the name of |annot|, which is an interactive form annotation. // |buffer| is only modified if |buflen| is longer than the length of contents. // In case of error, nothing will be added to |buffer| and the return value will // be 0. Note that return value of empty string is 2 for "\0\0". // // hHandle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment(). // annot - handle to an interactive form annotation. // buffer - buffer for holding the name string, encoded in UTF-16LE. // buflen - length of the buffer in bytes. // // Returns the length of the string value in bytes. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFAnnot_GetFormFieldName(FPDF_FORMHANDLE hHandle, FPDF_ANNOTATION annot, FPDF_WCHAR* buffer, unsigned long buflen); // Experimental API. // Gets the alternate name of |annot|, which is an interactive form annotation. // |buffer| is only modified if |buflen| is longer than the length of contents. // In case of error, nothing will be added to |buffer| and the return value will // be 0. Note that return value of empty string is 2 for "\0\0". // // hHandle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment(). // annot - handle to an interactive form annotation. // buffer - buffer for holding the alternate name string, encoded in // UTF-16LE. // buflen - length of the buffer in bytes. // // Returns the length of the string value in bytes. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFAnnot_GetFormFieldAlternateName(FPDF_FORMHANDLE hHandle, FPDF_ANNOTATION annot, FPDF_WCHAR* buffer, unsigned long buflen); // Experimental API. // Gets the form field type of |annot|, which is an interactive form annotation. // // hHandle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment(). // annot - handle to an interactive form annotation. // // Returns the type of the form field (one of the FPDF_FORMFIELD_* values) on // success. Returns -1 on error. // See field types in fpdf_formfill.h. FPDF_EXPORT int FPDF_CALLCONV FPDFAnnot_GetFormFieldType(FPDF_FORMHANDLE hHandle, FPDF_ANNOTATION annot); // Experimental API. // Gets the value of |annot|, which is an interactive form annotation. // |buffer| is only modified if |buflen| is longer than the length of contents. // In case of error, nothing will be added to |buffer| and the return value will // be 0. Note that return value of empty string is 2 for "\0\0". // // hHandle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment(). // annot - handle to an interactive form annotation. // buffer - buffer for holding the value string, encoded in UTF-16LE. // buflen - length of the buffer in bytes. // // Returns the length of the string value in bytes. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFAnnot_GetFormFieldValue(FPDF_FORMHANDLE hHandle, FPDF_ANNOTATION annot, FPDF_WCHAR* buffer, unsigned long buflen); // Experimental API. // Get the number of options in the |annot|'s "Opt" dictionary. Intended for // use with listbox and combobox widget annotations. // // hHandle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment. // annot - handle to an annotation. // // Returns the number of options in "Opt" dictionary on success. Return value // will be -1 if annotation does not have an "Opt" dictionary or other error. FPDF_EXPORT int FPDF_CALLCONV FPDFAnnot_GetOptionCount(FPDF_FORMHANDLE hHandle, FPDF_ANNOTATION annot); // Experimental API. // Get the string value for the label of the option at |index| in |annot|'s // "Opt" dictionary. Intended for use with listbox and combobox widget // annotations. |buffer| is only modified if |buflen| is longer than the length // of contents. If index is out of range or in case of other error, nothing // will be added to |buffer| and the return value will be 0. Note that // return value of empty string is 2 for "\0\0". // // hHandle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment. // annot - handle to an annotation. // index - numeric index of the option in the "Opt" array // buffer - buffer for holding the value string, encoded in UTF-16LE. // buflen - length of the buffer in bytes. // // Returns the length of the string value in bytes. // If |annot| does not have an "Opt" array, |index| is out of range or if any // other error occurs, returns 0. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFAnnot_GetOptionLabel(FPDF_FORMHANDLE hHandle, FPDF_ANNOTATION annot, int index, FPDF_WCHAR* buffer, unsigned long buflen); // Experimental API. // Determine whether or not the option at |index| in |annot|'s "Opt" dictionary // is selected. Intended for use with listbox and combobox widget annotations. // // handle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment. // annot - handle to an annotation. // index - numeric index of the option in the "Opt" array. // // Returns true if the option at |index| in |annot|'s "Opt" dictionary is // selected, false otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_IsOptionSelected(FPDF_FORMHANDLE handle, FPDF_ANNOTATION annot, int index); // Experimental API. // Get the float value of the font size for an |annot| with variable text. // If 0, the font is to be auto-sized: its size is computed as a function of // the height of the annotation rectangle. // // hHandle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment. // annot - handle to an annotation. // value - Required. Float which will be set to font size on success. // // Returns true if the font size was set in |value|, false on error or if // |value| not provided. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_GetFontSize(FPDF_FORMHANDLE hHandle, FPDF_ANNOTATION annot, float* value); // Experimental API. // Set the text color of an annotation. // // handle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment. // annot - handle to an annotation. // R - the red component for the text color. // G - the green component for the text color. // B - the blue component for the text color. // // Returns true if successful. // // Currently supported subtypes: freetext. // The range for the color components is 0 to 255. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetFontColor(FPDF_FORMHANDLE handle, FPDF_ANNOTATION annot, unsigned int R, unsigned int G, unsigned int B); // Experimental API. // Get the RGB value of the font color for an |annot| with variable text. // // hHandle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment. // annot - handle to an annotation. // R, G, B - buffer to hold the RGB value of the color. Ranges from 0 to 255. // // Returns true if the font color was set, false on error or if the font // color was not provided. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_GetFontColor(FPDF_FORMHANDLE hHandle, FPDF_ANNOTATION annot, unsigned int* R, unsigned int* G, unsigned int* B); // Experimental API. // Determine if |annot| is a form widget that is checked. Intended for use with // checkbox and radio button widgets. // // hHandle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment. // annot - handle to an annotation. // // Returns true if |annot| is a form widget and is checked, false otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_IsChecked(FPDF_FORMHANDLE hHandle, FPDF_ANNOTATION annot); // Experimental API. // Set the list of focusable annotation subtypes. Annotations of subtype // FPDF_ANNOT_WIDGET are by default focusable. New subtypes set using this API // will override the existing subtypes. // // hHandle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment. // subtypes - list of annotation subtype which can be tabbed over. // count - total number of annotation subtype in list. // Returns true if list of annotation subtype is set successfully, false // otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetFocusableSubtypes(FPDF_FORMHANDLE hHandle, const FPDF_ANNOTATION_SUBTYPE* subtypes, size_t count); // Experimental API. // Get the count of focusable annotation subtypes as set by host // for a |hHandle|. // // hHandle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment. // Returns the count of focusable annotation subtypes or -1 on error. // Note : Annotations of type FPDF_ANNOT_WIDGET are by default focusable. FPDF_EXPORT int FPDF_CALLCONV FPDFAnnot_GetFocusableSubtypesCount(FPDF_FORMHANDLE hHandle); // Experimental API. // Get the list of focusable annotation subtype as set by host. // // hHandle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment. // subtypes - receives the list of annotation subtype which can be tabbed // over. Caller must have allocated |subtypes| more than or // equal to the count obtained from // FPDFAnnot_GetFocusableSubtypesCount() API. // count - size of |subtypes|. // Returns true on success and set list of annotation subtype to |subtypes|, // false otherwise. // Note : Annotations of type FPDF_ANNOT_WIDGET are by default focusable. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_GetFocusableSubtypes(FPDF_FORMHANDLE hHandle, FPDF_ANNOTATION_SUBTYPE* subtypes, size_t count); // Experimental API. // Gets FPDF_LINK object for |annot|. Intended to use for link annotations. // // annot - handle to an annotation. // // Returns FPDF_LINK from the FPDF_ANNOTATION and NULL on failure, // if the input annot is NULL or input annot's subtype is not link. FPDF_EXPORT FPDF_LINK FPDF_CALLCONV FPDFAnnot_GetLink(FPDF_ANNOTATION annot); // Experimental API. // Gets the count of annotations in the |annot|'s control group. // A group of interactive form annotations is collectively called a form // control group. Here, |annot|, an interactive form annotation, should be // either a radio button or a checkbox. // // hHandle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment. // annot - handle to an annotation. // // Returns number of controls in its control group or -1 on error. FPDF_EXPORT int FPDF_CALLCONV FPDFAnnot_GetFormControlCount(FPDF_FORMHANDLE hHandle, FPDF_ANNOTATION annot); // Experimental API. // Gets the index of |annot| in |annot|'s control group. // A group of interactive form annotations is collectively called a form // control group. Here, |annot|, an interactive form annotation, should be // either a radio button or a checkbox. // // hHandle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment. // annot - handle to an annotation. // // Returns index of a given |annot| in its control group or -1 on error. FPDF_EXPORT int FPDF_CALLCONV FPDFAnnot_GetFormControlIndex(FPDF_FORMHANDLE hHandle, FPDF_ANNOTATION annot); // Experimental API. // Gets the export value of |annot| which is an interactive form annotation. // Intended for use with radio button and checkbox widget annotations. // |buffer| is only modified if |buflen| is longer than the length of contents. // In case of error, nothing will be added to |buffer| and the return value // will be 0. Note that return value of empty string is 2 for "\0\0". // // hHandle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment(). // annot - handle to an interactive form annotation. // buffer - buffer for holding the value string, encoded in UTF-16LE. // buflen - length of the buffer in bytes. // // Returns the length of the string value in bytes. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFAnnot_GetFormFieldExportValue(FPDF_FORMHANDLE hHandle, FPDF_ANNOTATION annot, FPDF_WCHAR* buffer, unsigned long buflen); // Experimental API. // Add a URI action to |annot|, overwriting the existing action, if any. // // annot - handle to a link annotation. // uri - the URI to be set, encoded in 7-bit ASCII. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetURI(FPDF_ANNOTATION annot, const char* uri); // Experimental API. // Get the attachment from |annot|. // // annot - handle to a file annotation. // // Returns the handle to the attachment object, or NULL on failure. FPDF_EXPORT FPDF_ATTACHMENT FPDF_CALLCONV FPDFAnnot_GetFileAttachment(FPDF_ANNOTATION annot); // Experimental API. // Add an embedded file with |name| to |annot|. // // annot - handle to a file annotation. // name - name of the new attachment. // // Returns a handle to the new attachment object, or NULL on failure. FPDF_EXPORT FPDF_ATTACHMENT FPDF_CALLCONV FPDFAnnot_AddFileAttachment(FPDF_ANNOTATION annot, FPDF_WIDESTRING name); #ifdef __cplusplus } // extern "C" #endif // __cplusplus #endif // PUBLIC_FPDF_ANNOT_H_ ================================================ FILE: external/pdfium/linux-x64/include/fpdf_attachment.h ================================================ // Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef PUBLIC_FPDF_ATTACHMENT_H_ #define PUBLIC_FPDF_ATTACHMENT_H_ // NOLINTNEXTLINE(build/include) #include "fpdfview.h" #ifdef __cplusplus extern "C" { #endif // __cplusplus // Experimental API. // Get the number of embedded files in |document|. // // document - handle to a document. // // Returns the number of embedded files in |document|. FPDF_EXPORT int FPDF_CALLCONV FPDFDoc_GetAttachmentCount(FPDF_DOCUMENT document); // Experimental API. // Add an embedded file with |name| in |document|. If |name| is empty, or if // |name| is the name of a existing embedded file in |document|, or if // |document|'s embedded file name tree is too deep (i.e. |document| has too // many embedded files already), then a new attachment will not be added. // // document - handle to a document. // name - name of the new attachment. // // Returns a handle to the new attachment object, or NULL on failure. FPDF_EXPORT FPDF_ATTACHMENT FPDF_CALLCONV FPDFDoc_AddAttachment(FPDF_DOCUMENT document, FPDF_WIDESTRING name); // Experimental API. // Get the embedded attachment at |index| in |document|. Note that the returned // attachment handle is only valid while |document| is open. // // document - handle to a document. // index - the index of the requested embedded file. // // Returns the handle to the attachment object, or NULL on failure. FPDF_EXPORT FPDF_ATTACHMENT FPDF_CALLCONV FPDFDoc_GetAttachment(FPDF_DOCUMENT document, int index); // Experimental API. // Delete the embedded attachment at |index| in |document|. Note that this does // not remove the attachment data from the PDF file; it simply removes the // file's entry in the embedded files name tree so that it does not appear in // the attachment list. This behavior may change in the future. // // document - handle to a document. // index - the index of the embedded file to be deleted. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFDoc_DeleteAttachment(FPDF_DOCUMENT document, int index); // Experimental API. // Get the name of the |attachment| file. |buffer| is only modified if |buflen| // is longer than the length of the file name. On errors, |buffer| is unmodified // and the returned length is 0. // // attachment - handle to an attachment. // buffer - buffer for holding the file name, encoded in UTF-16LE. // buflen - length of the buffer in bytes. // // Returns the length of the file name in bytes. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFAttachment_GetName(FPDF_ATTACHMENT attachment, FPDF_WCHAR* buffer, unsigned long buflen); // Experimental API. // Check if the params dictionary of |attachment| has |key| as a key. // // attachment - handle to an attachment. // key - the key to look for, encoded in UTF-8. // // Returns true if |key| exists. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAttachment_HasKey(FPDF_ATTACHMENT attachment, FPDF_BYTESTRING key); // Experimental API. // Get the type of the value corresponding to |key| in the params dictionary of // the embedded |attachment|. // // attachment - handle to an attachment. // key - the key to look for, encoded in UTF-8. // // Returns the type of the dictionary value. FPDF_EXPORT FPDF_OBJECT_TYPE FPDF_CALLCONV FPDFAttachment_GetValueType(FPDF_ATTACHMENT attachment, FPDF_BYTESTRING key); // Experimental API. // Set the string value corresponding to |key| in the params dictionary of the // embedded file |attachment|, overwriting the existing value if any. The value // type should be FPDF_OBJECT_STRING after this function call succeeds. // // attachment - handle to an attachment. // key - the key to the dictionary entry, encoded in UTF-8. // value - the string value to be set, encoded in UTF-16LE. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAttachment_SetStringValue(FPDF_ATTACHMENT attachment, FPDF_BYTESTRING key, FPDF_WIDESTRING value); // Experimental API. // Get the string value corresponding to |key| in the params dictionary of the // embedded file |attachment|. |buffer| is only modified if |buflen| is longer // than the length of the string value. Note that if |key| does not exist in the // dictionary or if |key|'s corresponding value in the dictionary is not a // string (i.e. the value is not of type FPDF_OBJECT_STRING or // FPDF_OBJECT_NAME), then an empty string would be copied to |buffer| and the // return value would be 2. On other errors, nothing would be added to |buffer| // and the return value would be 0. // // attachment - handle to an attachment. // key - the key to the requested string value, encoded in UTF-8. // buffer - buffer for holding the string value encoded in UTF-16LE. // buflen - length of the buffer in bytes. // // Returns the length of the dictionary value string in bytes. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFAttachment_GetStringValue(FPDF_ATTACHMENT attachment, FPDF_BYTESTRING key, FPDF_WCHAR* buffer, unsigned long buflen); // Experimental API. // Set the file data of |attachment|, overwriting the existing file data if any. // The creation date and checksum will be updated, while all other dictionary // entries will be deleted. Note that only contents with |len| smaller than // INT_MAX is supported. // // attachment - handle to an attachment. // contents - buffer holding the file data to write to |attachment|. // len - length of file data in bytes. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAttachment_SetFile(FPDF_ATTACHMENT attachment, FPDF_DOCUMENT document, const void* contents, unsigned long len); // Experimental API. // Get the file data of |attachment|. // When the attachment file data is readable, true is returned, and |out_buflen| // is updated to indicate the file data size. |buffer| is only modified if // |buflen| is non-null and long enough to contain the entire file data. Callers // must check both the return value and the input |buflen| is no less than the // returned |out_buflen| before using the data. // // Otherwise, when the attachment file data is unreadable or when |out_buflen| // is null, false is returned and |buffer| and |out_buflen| remain unmodified. // // attachment - handle to an attachment. // buffer - buffer for holding the file data from |attachment|. // buflen - length of the buffer in bytes. // out_buflen - pointer to the variable that will receive the minimum buffer // size to contain the file data of |attachment|. // // Returns true on success, false otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAttachment_GetFile(FPDF_ATTACHMENT attachment, void* buffer, unsigned long buflen, unsigned long* out_buflen); // Experimental API. // Get the MIME type (Subtype) of the embedded file |attachment|. |buffer| is // only modified if |buflen| is longer than the length of the MIME type string. // If the Subtype is not found or if there is no file stream, an empty string // would be copied to |buffer| and the return value would be 2. On other errors, // nothing would be added to |buffer| and the return value would be 0. // // attachment - handle to an attachment. // buffer - buffer for holding the MIME type string encoded in UTF-16LE. // buflen - length of the buffer in bytes. // // Returns the length of the MIME type string in bytes. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFAttachment_GetSubtype(FPDF_ATTACHMENT attachment, FPDF_WCHAR* buffer, unsigned long buflen); #ifdef __cplusplus } // extern "C" #endif // __cplusplus #endif // PUBLIC_FPDF_ATTACHMENT_H_ ================================================ FILE: external/pdfium/linux-x64/include/fpdf_catalog.h ================================================ // Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef PUBLIC_FPDF_CATALOG_H_ #define PUBLIC_FPDF_CATALOG_H_ // NOLINTNEXTLINE(build/include) #include "fpdfview.h" #ifdef __cplusplus extern "C" { #endif // __cplusplus // Experimental API. // // Determine if |document| represents a tagged PDF. // // For the definition of tagged PDF, See (see 10.7 "Tagged PDF" in PDF // Reference 1.7). // // document - handle to a document. // // Returns |true| iff |document| is a tagged PDF. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFCatalog_IsTagged(FPDF_DOCUMENT document); // Experimental API. // Gets the language of |document| from the catalog's /Lang entry. // // document - handle to a document. // buffer - a buffer for the language string. May be NULL. // buflen - the length of the buffer, in bytes. May be 0. // // Returns the number of bytes in the language string, including the // trailing NUL character. The number of bytes is returned regardless of the // |buffer| and |buflen| parameters. // // Regardless of the platform, the |buffer| is always in UTF-16LE // encoding. The string is terminated by a UTF16 NUL character. If // |buflen| is less than the required length, or |buffer| is NULL, // |buffer| will not be modified. // // If |document| has no /Lang entry, an empty string is written to |buffer| and // 2 is returned. On error, nothing is written to |buffer| and 0 is returned. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFCatalog_GetLanguage(FPDF_DOCUMENT document, FPDF_WCHAR* buffer, unsigned long buflen); // Experimental API. // Sets the language of |document| to |language|. // // document - handle to a document. // language - the language to set to. // // Returns TRUE on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFCatalog_SetLanguage(FPDF_DOCUMENT document, FPDF_WIDESTRING language); #ifdef __cplusplus } // extern "C" #endif // __cplusplus #endif // PUBLIC_FPDF_CATALOG_H_ ================================================ FILE: external/pdfium/linux-x64/include/fpdf_dataavail.h ================================================ // Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #ifndef PUBLIC_FPDF_DATAAVAIL_H_ #define PUBLIC_FPDF_DATAAVAIL_H_ #include // NOLINTNEXTLINE(build/include) #include "fpdfview.h" #define PDF_LINEARIZATION_UNKNOWN -1 #define PDF_NOT_LINEARIZED 0 #define PDF_LINEARIZED 1 #define PDF_DATA_ERROR -1 #define PDF_DATA_NOTAVAIL 0 #define PDF_DATA_AVAIL 1 #define PDF_FORM_ERROR -1 #define PDF_FORM_NOTAVAIL 0 #define PDF_FORM_AVAIL 1 #define PDF_FORM_NOTEXIST 2 #ifdef __cplusplus extern "C" { #endif // __cplusplus // Interface for checking whether sections of the file are available. typedef struct _FX_FILEAVAIL { // Version number of the interface. Must be 1. int version; // Reports if the specified data section is currently available. A section is // available if all bytes in the section are available. // // Interface Version: 1 // Implementation Required: Yes // // pThis - pointer to the interface structure. // offset - the offset of the data section in the file. // size - the size of the data section. // // Returns true if the specified data section at |offset| of |size| // is available. FPDF_BOOL (*IsDataAvail)(struct _FX_FILEAVAIL* pThis, size_t offset, size_t size); } FX_FILEAVAIL; // Create a document availability provider. // // file_avail - pointer to file availability interface. // file - pointer to a file access interface. // // Returns a handle to the document availability provider, or NULL on error. // // FPDFAvail_Destroy() must be called when done with the availability provider. FPDF_EXPORT FPDF_AVAIL FPDF_CALLCONV FPDFAvail_Create(FX_FILEAVAIL* file_avail, FPDF_FILEACCESS* file); // Destroy the |avail| document availability provider. // // avail - handle to document availability provider to be destroyed. FPDF_EXPORT void FPDF_CALLCONV FPDFAvail_Destroy(FPDF_AVAIL avail); // Download hints interface. Used to receive hints for further downloading. typedef struct _FX_DOWNLOADHINTS { // Version number of the interface. Must be 1. int version; // Add a section to be downloaded. // // Interface Version: 1 // Implementation Required: Yes // // pThis - pointer to the interface structure. // offset - the offset of the hint reported to be downloaded. // size - the size of the hint reported to be downloaded. // // The |offset| and |size| of the section may not be unique. Part of the // section might be already available. The download manager must deal with // overlapping sections. void (*AddSegment)(struct _FX_DOWNLOADHINTS* pThis, size_t offset, size_t size); } FX_DOWNLOADHINTS; // Checks if the document is ready for loading, if not, gets download hints. // // avail - handle to document availability provider. // hints - pointer to a download hints interface. // // Returns one of: // PDF_DATA_ERROR: A common error is returned. Data availability unknown. // PDF_DATA_NOTAVAIL: Data not yet available. // PDF_DATA_AVAIL: Data available. // // Applications should call this function whenever new data arrives, and process // all the generated download hints, if any, until the function returns // |PDF_DATA_ERROR| or |PDF_DATA_AVAIL|. // if hints is nullptr, the function just check current document availability. // // Once all data is available, call FPDFAvail_GetDocument() to get a document // handle. FPDF_EXPORT int FPDF_CALLCONV FPDFAvail_IsDocAvail(FPDF_AVAIL avail, FX_DOWNLOADHINTS* hints); // Get document from the availability provider. // // avail - handle to document availability provider. // password - password for decrypting the PDF file. Optional. // // Returns a handle to the document. // // When FPDFAvail_IsDocAvail() returns TRUE, call FPDFAvail_GetDocument() to // retrieve the document handle. // See the comments for FPDF_LoadDocument() regarding the encoding for // |password|. FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV FPDFAvail_GetDocument(FPDF_AVAIL avail, FPDF_BYTESTRING password); // Get the page number for the first available page in a linearized PDF. // // doc - document handle. // // Returns the zero-based index for the first available page. // // For most linearized PDFs, the first available page will be the first page, // however, some PDFs might make another page the first available page. // For non-linearized PDFs, this function will always return zero. FPDF_EXPORT int FPDF_CALLCONV FPDFAvail_GetFirstPageNum(FPDF_DOCUMENT doc); // Check if |page_index| is ready for loading, if not, get the // |FX_DOWNLOADHINTS|. // // avail - handle to document availability provider. // page_index - index number of the page. Zero for the first page. // hints - pointer to a download hints interface. Populated if // |page_index| is not available. // // Returns one of: // PDF_DATA_ERROR: A common error is returned. Data availability unknown. // PDF_DATA_NOTAVAIL: Data not yet available. // PDF_DATA_AVAIL: Data available. // // This function can be called only after FPDFAvail_GetDocument() is called. // Applications should call this function whenever new data arrives and process // all the generated download |hints|, if any, until this function returns // |PDF_DATA_ERROR| or |PDF_DATA_AVAIL|. Applications can then perform page // loading. // if hints is nullptr, the function just check current availability of // specified page. FPDF_EXPORT int FPDF_CALLCONV FPDFAvail_IsPageAvail(FPDF_AVAIL avail, int page_index, FX_DOWNLOADHINTS* hints); // Check if form data is ready for initialization, if not, get the // |FX_DOWNLOADHINTS|. // // avail - handle to document availability provider. // hints - pointer to a download hints interface. Populated if form is not // ready for initialization. // // Returns one of: // PDF_FORM_ERROR: A common eror, in general incorrect parameters. // PDF_FORM_NOTAVAIL: Data not available. // PDF_FORM_AVAIL: Data available. // PDF_FORM_NOTEXIST: No form data. // // This function can be called only after FPDFAvail_GetDocument() is called. // The application should call this function whenever new data arrives and // process all the generated download |hints|, if any, until the function // |PDF_FORM_ERROR|, |PDF_FORM_AVAIL| or |PDF_FORM_NOTEXIST|. // if hints is nullptr, the function just check current form availability. // // Applications can then perform page loading. It is recommend to call // FPDFDOC_InitFormFillEnvironment() when |PDF_FORM_AVAIL| is returned. FPDF_EXPORT int FPDF_CALLCONV FPDFAvail_IsFormAvail(FPDF_AVAIL avail, FX_DOWNLOADHINTS* hints); // Check whether a document is a linearized PDF. // // avail - handle to document availability provider. // // Returns one of: // PDF_LINEARIZED // PDF_NOT_LINEARIZED // PDF_LINEARIZATION_UNKNOWN // // FPDFAvail_IsLinearized() will return |PDF_LINEARIZED| or |PDF_NOT_LINEARIZED| // when we have 1k of data. If the files size less than 1k, it returns // |PDF_LINEARIZATION_UNKNOWN| as there is insufficient information to determine // if the PDF is linearlized. FPDF_EXPORT int FPDF_CALLCONV FPDFAvail_IsLinearized(FPDF_AVAIL avail); #ifdef __cplusplus } // extern "C" #endif // __cplusplus #endif // PUBLIC_FPDF_DATAAVAIL_H_ ================================================ FILE: external/pdfium/linux-x64/include/fpdf_doc.h ================================================ // Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #ifndef PUBLIC_FPDF_DOC_H_ #define PUBLIC_FPDF_DOC_H_ // NOLINTNEXTLINE(build/include) #include "fpdfview.h" #ifdef __cplusplus extern "C" { #endif // __cplusplus // Unsupported action type. #define PDFACTION_UNSUPPORTED 0 // Go to a destination within current document. #define PDFACTION_GOTO 1 // Go to a destination within another document. #define PDFACTION_REMOTEGOTO 2 // URI, including web pages and other Internet resources. #define PDFACTION_URI 3 // Launch an application or open a file. #define PDFACTION_LAUNCH 4 // Go to a destination in an embedded file. #define PDFACTION_EMBEDDEDGOTO 5 // View destination fit types. See pdfmark reference v9, page 48. #define PDFDEST_VIEW_UNKNOWN_MODE 0 #define PDFDEST_VIEW_XYZ 1 #define PDFDEST_VIEW_FIT 2 #define PDFDEST_VIEW_FITH 3 #define PDFDEST_VIEW_FITV 4 #define PDFDEST_VIEW_FITR 5 #define PDFDEST_VIEW_FITB 6 #define PDFDEST_VIEW_FITBH 7 #define PDFDEST_VIEW_FITBV 8 // The file identifier entry type. See section 14.4 "File Identifiers" of the // ISO 32000-1:2008 spec. typedef enum { FILEIDTYPE_PERMANENT = 0, FILEIDTYPE_CHANGING = 1 } FPDF_FILEIDTYPE; // Get the first child of |bookmark|, or the first top-level bookmark item. // // document - handle to the document. // bookmark - handle to the current bookmark. Pass NULL for the first top // level item. // // Returns a handle to the first child of |bookmark| or the first top-level // bookmark item. NULL if no child or top-level bookmark found. // Note that another name for the bookmarks is the document outline, as // described in ISO 32000-1:2008, section 12.3.3. FPDF_EXPORT FPDF_BOOKMARK FPDF_CALLCONV FPDFBookmark_GetFirstChild(FPDF_DOCUMENT document, FPDF_BOOKMARK bookmark); // Get the next sibling of |bookmark|. // // document - handle to the document. // bookmark - handle to the current bookmark. // // Returns a handle to the next sibling of |bookmark|, or NULL if this is the // last bookmark at this level. // // Note that the caller is responsible for handling circular bookmark // references, as may arise from malformed documents. FPDF_EXPORT FPDF_BOOKMARK FPDF_CALLCONV FPDFBookmark_GetNextSibling(FPDF_DOCUMENT document, FPDF_BOOKMARK bookmark); // Get the title of |bookmark|. // // bookmark - handle to the bookmark. // buffer - buffer for the title. May be NULL. // buflen - the length of the buffer in bytes. May be 0. // // Returns the number of bytes in the title, including the terminating NUL // character. The number of bytes is returned regardless of the |buffer| and // |buflen| parameters. // // Regardless of the platform, the |buffer| is always in UTF-16LE encoding. The // string is terminated by a UTF16 NUL character. If |buflen| is less than the // required length, or |buffer| is NULL, |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFBookmark_GetTitle(FPDF_BOOKMARK bookmark, void* buffer, unsigned long buflen); // Experimental API. // Get the number of chlidren of |bookmark|. // // bookmark - handle to the bookmark. // // Returns a signed integer that represents the number of sub-items the given // bookmark has. If the value is positive, child items shall be shown by default // (open state). If the value is negative, child items shall be hidden by // default (closed state). Please refer to PDF 32000-1:2008, Table 153. // Returns 0 if the bookmark has no children or is invalid. FPDF_EXPORT int FPDF_CALLCONV FPDFBookmark_GetCount(FPDF_BOOKMARK bookmark); // Find the bookmark with |title| in |document|. // // document - handle to the document. // title - the UTF-16LE encoded Unicode title for which to search. // // Returns the handle to the bookmark, or NULL if |title| can't be found. // // FPDFBookmark_Find() will always return the first bookmark found even if // multiple bookmarks have the same |title|. FPDF_EXPORT FPDF_BOOKMARK FPDF_CALLCONV FPDFBookmark_Find(FPDF_DOCUMENT document, FPDF_WIDESTRING title); // Get the destination associated with |bookmark|. // // document - handle to the document. // bookmark - handle to the bookmark. // // Returns the handle to the destination data, or NULL if no destination is // associated with |bookmark|. FPDF_EXPORT FPDF_DEST FPDF_CALLCONV FPDFBookmark_GetDest(FPDF_DOCUMENT document, FPDF_BOOKMARK bookmark); // Get the action associated with |bookmark|. // // bookmark - handle to the bookmark. // // Returns the handle to the action data, or NULL if no action is associated // with |bookmark|. // If this function returns a valid handle, it is valid as long as |bookmark| is // valid. // If this function returns NULL, FPDFBookmark_GetDest() should be called to get // the |bookmark| destination data. FPDF_EXPORT FPDF_ACTION FPDF_CALLCONV FPDFBookmark_GetAction(FPDF_BOOKMARK bookmark); // Get the type of |action|. // // action - handle to the action. // // Returns one of: // PDFACTION_UNSUPPORTED // PDFACTION_GOTO // PDFACTION_REMOTEGOTO // PDFACTION_URI // PDFACTION_LAUNCH FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFAction_GetType(FPDF_ACTION action); // Get the destination of |action|. // // document - handle to the document. // action - handle to the action. |action| must be a |PDFACTION_GOTO| or // |PDFACTION_REMOTEGOTO|. // // Returns a handle to the destination data, or NULL on error, typically // because the arguments were bad or the action was of the wrong type. // // In the case of |PDFACTION_REMOTEGOTO|, you must first call // FPDFAction_GetFilePath(), then load the document at that path, then pass // the document handle from that document as |document| to FPDFAction_GetDest(). FPDF_EXPORT FPDF_DEST FPDF_CALLCONV FPDFAction_GetDest(FPDF_DOCUMENT document, FPDF_ACTION action); // Get the file path of |action|. // // action - handle to the action. |action| must be a |PDFACTION_LAUNCH| or // |PDFACTION_REMOTEGOTO|. // buffer - a buffer for output the path string. May be NULL. // buflen - the length of the buffer, in bytes. May be 0. // // Returns the number of bytes in the file path, including the trailing NUL // character, or 0 on error, typically because the arguments were bad or the // action was of the wrong type. // // Regardless of the platform, the |buffer| is always in UTF-8 encoding. // If |buflen| is less than the returned length, or |buffer| is NULL, |buffer| // will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFAction_GetFilePath(FPDF_ACTION action, void* buffer, unsigned long buflen); // Get the URI path of |action|. // // document - handle to the document. // action - handle to the action. Must be a |PDFACTION_URI|. // buffer - a buffer for the path string. May be NULL. // buflen - the length of the buffer, in bytes. May be 0. // // Returns the number of bytes in the URI path, including the trailing NUL // character, or 0 on error, typically because the arguments were bad or the // action was of the wrong type. // // The |buffer| may contain badly encoded data. The caller should validate the // output. e.g. Check to see if it is UTF-8. // // If |buflen| is less than the returned length, or |buffer| is NULL, |buffer| // will not be modified. // // Historically, the documentation for this API claimed |buffer| is always // encoded in 7-bit ASCII, but did not actually enforce it. // https://pdfium.googlesource.com/pdfium.git/+/d609e84cee2e14a18333247485af91df48a40592 // added that enforcement, but that did not work well for real world PDFs that // used UTF-8. As of this writing, this API reverted back to its original // behavior prior to commit d609e84cee. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFAction_GetURIPath(FPDF_DOCUMENT document, FPDF_ACTION action, void* buffer, unsigned long buflen); // Get the page index of |dest|. // // document - handle to the document. // dest - handle to the destination. // // Returns the 0-based page index containing |dest|. Returns -1 on error. FPDF_EXPORT int FPDF_CALLCONV FPDFDest_GetDestPageIndex(FPDF_DOCUMENT document, FPDF_DEST dest); // Experimental API. // Get the view (fit type) specified by |dest|. // // dest - handle to the destination. // pNumParams - receives the number of view parameters, which is at most 4. // pParams - buffer to write the view parameters. Must be at least 4 // FS_FLOATs long. // Returns one of the PDFDEST_VIEW_* constants, PDFDEST_VIEW_UNKNOWN_MODE if // |dest| does not specify a view. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFDest_GetView(FPDF_DEST dest, unsigned long* pNumParams, FS_FLOAT* pParams); // Get the (x, y, zoom) location of |dest| in the destination page, if the // destination is in [page /XYZ x y zoom] syntax. // // dest - handle to the destination. // hasXVal - out parameter; true if the x value is not null // hasYVal - out parameter; true if the y value is not null // hasZoomVal - out parameter; true if the zoom value is not null // x - out parameter; the x coordinate, in page coordinates. // y - out parameter; the y coordinate, in page coordinates. // zoom - out parameter; the zoom value. // Returns TRUE on successfully reading the /XYZ value. // // Note the [x, y, zoom] values are only set if the corresponding hasXVal, // hasYVal or hasZoomVal flags are true. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFDest_GetLocationInPage(FPDF_DEST dest, FPDF_BOOL* hasXVal, FPDF_BOOL* hasYVal, FPDF_BOOL* hasZoomVal, FS_FLOAT* x, FS_FLOAT* y, FS_FLOAT* zoom); // Find a link at point (|x|,|y|) on |page|. // // page - handle to the document page. // x - the x coordinate, in the page coordinate system. // y - the y coordinate, in the page coordinate system. // // Returns a handle to the link, or NULL if no link found at the given point. // // You can convert coordinates from screen coordinates to page coordinates using // FPDF_DeviceToPage(). FPDF_EXPORT FPDF_LINK FPDF_CALLCONV FPDFLink_GetLinkAtPoint(FPDF_PAGE page, double x, double y); // Find the Z-order of link at point (|x|,|y|) on |page|. // // page - handle to the document page. // x - the x coordinate, in the page coordinate system. // y - the y coordinate, in the page coordinate system. // // Returns the Z-order of the link, or -1 if no link found at the given point. // Larger Z-order numbers are closer to the front. // // You can convert coordinates from screen coordinates to page coordinates using // FPDF_DeviceToPage(). FPDF_EXPORT int FPDF_CALLCONV FPDFLink_GetLinkZOrderAtPoint(FPDF_PAGE page, double x, double y); // Get destination info for |link|. // // document - handle to the document. // link - handle to the link. // // Returns a handle to the destination, or NULL if there is no destination // associated with the link. In this case, you should call FPDFLink_GetAction() // to retrieve the action associated with |link|. FPDF_EXPORT FPDF_DEST FPDF_CALLCONV FPDFLink_GetDest(FPDF_DOCUMENT document, FPDF_LINK link); // Get action info for |link|. // // link - handle to the link. // // Returns a handle to the action associated to |link|, or NULL if no action. // If this function returns a valid handle, it is valid as long as |link| is // valid. FPDF_EXPORT FPDF_ACTION FPDF_CALLCONV FPDFLink_GetAction(FPDF_LINK link); // Enumerates all the link annotations in |page|. // // page - handle to the page. // start_pos - the start position, should initially be 0 and is updated with // the next start position on return. // link_annot - the link handle for |startPos|. // // Returns TRUE on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFLink_Enumerate(FPDF_PAGE page, int* start_pos, FPDF_LINK* link_annot); // Experimental API. // Gets FPDF_ANNOTATION object for |link_annot|. // // page - handle to the page in which FPDF_LINK object is present. // link_annot - handle to link annotation. // // Returns FPDF_ANNOTATION from the FPDF_LINK and NULL on failure, // if the input link annot or page is NULL. FPDF_EXPORT FPDF_ANNOTATION FPDF_CALLCONV FPDFLink_GetAnnot(FPDF_PAGE page, FPDF_LINK link_annot); // Get the rectangle for |link_annot|. // // link_annot - handle to the link annotation. // rect - the annotation rectangle. // // Returns true on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFLink_GetAnnotRect(FPDF_LINK link_annot, FS_RECTF* rect); // Get the count of quadrilateral points to the |link_annot|. // // link_annot - handle to the link annotation. // // Returns the count of quadrilateral points. FPDF_EXPORT int FPDF_CALLCONV FPDFLink_CountQuadPoints(FPDF_LINK link_annot); // Get the quadrilateral points for the specified |quad_index| in |link_annot|. // // link_annot - handle to the link annotation. // quad_index - the specified quad point index. // quad_points - receives the quadrilateral points. // // Returns true on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFLink_GetQuadPoints(FPDF_LINK link_annot, int quad_index, FS_QUADPOINTSF* quad_points); // Experimental API // Gets an additional-action from |page|. // // page - handle to the page, as returned by FPDF_LoadPage(). // aa_type - the type of the page object's addtional-action, defined // in public/fpdf_formfill.h // // Returns the handle to the action data, or NULL if there is no // additional-action of type |aa_type|. // If this function returns a valid handle, it is valid as long as |page| is // valid. FPDF_EXPORT FPDF_ACTION FPDF_CALLCONV FPDF_GetPageAAction(FPDF_PAGE page, int aa_type); // Experimental API. // Get the file identifer defined in the trailer of |document|. // // document - handle to the document. // id_type - the file identifier type to retrieve. // buffer - a buffer for the file identifier. May be NULL. // buflen - the length of the buffer, in bytes. May be 0. // // Returns the number of bytes in the file identifier, including the NUL // terminator. // // The |buffer| is always a byte string. The |buffer| is followed by a NUL // terminator. If |buflen| is less than the returned length, or |buffer| is // NULL, |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetFileIdentifier(FPDF_DOCUMENT document, FPDF_FILEIDTYPE id_type, void* buffer, unsigned long buflen); // Get meta-data |tag| content from |document|. // // document - handle to the document. // tag - the tag to retrieve. The tag can be one of: // Title, Author, Subject, Keywords, Creator, Producer, // CreationDate, or ModDate. // For detailed explanations of these tags and their respective // values, please refer to PDF Reference 1.6, section 10.2.1, // 'Document Information Dictionary'. // buffer - a buffer for the tag. May be NULL. // buflen - the length of the buffer, in bytes. May be 0. // // Returns the number of bytes in the tag, including trailing zeros. // // The |buffer| is always encoded in UTF-16LE. The |buffer| is followed by two // bytes of zeros indicating the end of the string. If |buflen| is less than // the returned length, or |buffer| is NULL, |buffer| will not be modified. // // For linearized files, FPDFAvail_IsFormAvail must be called before this, and // it must have returned PDF_FORM_AVAIL or PDF_FORM_NOTEXIST. Before that, there // is no guarantee the metadata has been loaded. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetMetaText(FPDF_DOCUMENT document, FPDF_BYTESTRING tag, void* buffer, unsigned long buflen); // Get the page label for |page_index| from |document|. // // document - handle to the document. // page_index - the 0-based index of the page. // buffer - a buffer for the page label. May be NULL. // buflen - the length of the buffer, in bytes. May be 0. // // Returns the number of bytes in the page label, including trailing zeros. // // The |buffer| is always encoded in UTF-16LE. The |buffer| is followed by two // bytes of zeros indicating the end of the string. If |buflen| is less than // the returned length, or |buffer| is NULL, |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetPageLabel(FPDF_DOCUMENT document, int page_index, void* buffer, unsigned long buflen); #ifdef __cplusplus } // extern "C" #endif // __cplusplus #endif // PUBLIC_FPDF_DOC_H_ ================================================ FILE: external/pdfium/linux-x64/include/fpdf_edit.h ================================================ // Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #ifndef PUBLIC_FPDF_EDIT_H_ #define PUBLIC_FPDF_EDIT_H_ #include // NOLINTNEXTLINE(build/include_directory) #include "fpdfview.h" #define FPDF_ARGB(a, r, g, b) \ ((uint32_t)(((uint32_t)(b)&0xff) | (((uint32_t)(g)&0xff) << 8) | \ (((uint32_t)(r)&0xff) << 16) | (((uint32_t)(a)&0xff) << 24))) #define FPDF_GetBValue(argb) ((uint8_t)(argb)) #define FPDF_GetGValue(argb) ((uint8_t)(((uint16_t)(argb)) >> 8)) #define FPDF_GetRValue(argb) ((uint8_t)((argb) >> 16)) #define FPDF_GetAValue(argb) ((uint8_t)((argb) >> 24)) // Refer to PDF Reference version 1.7 table 4.12 for all color space families. #define FPDF_COLORSPACE_UNKNOWN 0 #define FPDF_COLORSPACE_DEVICEGRAY 1 #define FPDF_COLORSPACE_DEVICERGB 2 #define FPDF_COLORSPACE_DEVICECMYK 3 #define FPDF_COLORSPACE_CALGRAY 4 #define FPDF_COLORSPACE_CALRGB 5 #define FPDF_COLORSPACE_LAB 6 #define FPDF_COLORSPACE_ICCBASED 7 #define FPDF_COLORSPACE_SEPARATION 8 #define FPDF_COLORSPACE_DEVICEN 9 #define FPDF_COLORSPACE_INDEXED 10 #define FPDF_COLORSPACE_PATTERN 11 // The page object constants. #define FPDF_PAGEOBJ_UNKNOWN 0 #define FPDF_PAGEOBJ_TEXT 1 #define FPDF_PAGEOBJ_PATH 2 #define FPDF_PAGEOBJ_IMAGE 3 #define FPDF_PAGEOBJ_SHADING 4 #define FPDF_PAGEOBJ_FORM 5 // The path segment constants. #define FPDF_SEGMENT_UNKNOWN -1 #define FPDF_SEGMENT_LINETO 0 #define FPDF_SEGMENT_BEZIERTO 1 #define FPDF_SEGMENT_MOVETO 2 #define FPDF_FILLMODE_NONE 0 #define FPDF_FILLMODE_ALTERNATE 1 #define FPDF_FILLMODE_WINDING 2 #define FPDF_FONT_TYPE1 1 #define FPDF_FONT_TRUETYPE 2 #define FPDF_LINECAP_BUTT 0 #define FPDF_LINECAP_ROUND 1 #define FPDF_LINECAP_PROJECTING_SQUARE 2 #define FPDF_LINEJOIN_MITER 0 #define FPDF_LINEJOIN_ROUND 1 #define FPDF_LINEJOIN_BEVEL 2 // See FPDF_SetPrintMode() for descriptions. #define FPDF_PRINTMODE_EMF 0 #define FPDF_PRINTMODE_TEXTONLY 1 #define FPDF_PRINTMODE_POSTSCRIPT2 2 #define FPDF_PRINTMODE_POSTSCRIPT3 3 #define FPDF_PRINTMODE_POSTSCRIPT2_PASSTHROUGH 4 #define FPDF_PRINTMODE_POSTSCRIPT3_PASSTHROUGH 5 #define FPDF_PRINTMODE_EMF_IMAGE_MASKS 6 #define FPDF_PRINTMODE_POSTSCRIPT3_TYPE42 7 #define FPDF_PRINTMODE_POSTSCRIPT3_TYPE42_PASSTHROUGH 8 typedef struct FPDF_IMAGEOBJ_METADATA { // The image width in pixels. unsigned int width; // The image height in pixels. unsigned int height; // The image's horizontal pixel-per-inch. float horizontal_dpi; // The image's vertical pixel-per-inch. float vertical_dpi; // The number of bits used to represent each pixel. unsigned int bits_per_pixel; // The image's colorspace. See above for the list of FPDF_COLORSPACE_*. int colorspace; // The image's marked content ID. Useful for pairing with associated alt-text. // A value of -1 indicates no ID. int marked_content_id; } FPDF_IMAGEOBJ_METADATA; #ifdef __cplusplus extern "C" { #endif // __cplusplus // Create a new PDF document. // // Returns a handle to a new document, or NULL on failure. FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV FPDF_CreateNewDocument(); // Create a new PDF page. // // document - handle to document. // page_index - suggested 0-based index of the page to create. If it is larger // than document's current last index(L), the created page index // is the next available index -- L+1. // width - the page width in points. // height - the page height in points. // // Returns the handle to the new page or NULL on failure. // // The page should be closed with FPDF_ClosePage() when finished as // with any other page in the document. FPDF_EXPORT FPDF_PAGE FPDF_CALLCONV FPDFPage_New(FPDF_DOCUMENT document, int page_index, double width, double height); // Delete the page at |page_index|. // // document - handle to document. // page_index - the index of the page to delete. FPDF_EXPORT void FPDF_CALLCONV FPDFPage_Delete(FPDF_DOCUMENT document, int page_index); // Experimental API. // Move the given pages to a new index position. // // page_indices - the ordered list of pages to move. No duplicates allowed. // page_indices_len - the number of elements in |page_indices| // dest_page_index - the new index position to which the pages in // |page_indices| are moved. // // Returns TRUE on success. If it returns FALSE, the document may be left in an // indeterminate state. // // Example: The PDF document starts out with pages [A, B, C, D], with indices // [0, 1, 2, 3]. // // > Move(doc, [3, 2], 2, 1); // returns true // > // The document has pages [A, D, C, B]. // > // > Move(doc, [0, 4, 3], 3, 1); // returns false // > // Returned false because index 4 is out of range. // > // > Move(doc, [0, 3, 1], 3, 2); // returns false // > // Returned false because index 2 is out of range for 3 page indices. // > // > Move(doc, [2, 2], 2, 0); // returns false // > // Returned false because [2, 2] contains duplicates. // FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_MovePages(FPDF_DOCUMENT document, const int* page_indices, unsigned long page_indices_len, int dest_page_index); // Get the rotation of |page|. // // page - handle to a page // // Returns one of the following indicating the page rotation: // 0 - No rotation. // 1 - Rotated 90 degrees clockwise. // 2 - Rotated 180 degrees clockwise. // 3 - Rotated 270 degrees clockwise. FPDF_EXPORT int FPDF_CALLCONV FPDFPage_GetRotation(FPDF_PAGE page); // Set rotation for |page|. // // page - handle to a page. // rotate - the rotation value, one of: // 0 - No rotation. // 1 - Rotated 90 degrees clockwise. // 2 - Rotated 180 degrees clockwise. // 3 - Rotated 270 degrees clockwise. FPDF_EXPORT void FPDF_CALLCONV FPDFPage_SetRotation(FPDF_PAGE page, int rotate); // Insert |page_object| into |page|. // // page - handle to a page // page_object - handle to a page object. The |page_object| will be // automatically freed. FPDF_EXPORT void FPDF_CALLCONV FPDFPage_InsertObject(FPDF_PAGE page, FPDF_PAGEOBJECT page_object); // Insert |page_object| into |page| at the specified |index|. // // page - handle to a page // page_object - handle to a page object as previously obtained by // FPDFPageObj_CreateNew{Path|Rect}() or // FPDFPageObj_New{Text|Image}Obj(). Ownership of the object // is transferred back to PDFium. // index - the index position to insert the object at. If index equals // the current object count, the object will be appended to the // end. If index is greater than the object count, the function // will fail and return false. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_InsertObjectAtIndex(FPDF_PAGE page, FPDF_PAGEOBJECT page_object, size_t index); // Experimental API. // Remove |page_object| from |page|. // // page - handle to a page // page_object - handle to a page object to be removed. // // Returns TRUE on success. // // Ownership is transferred to the caller. Call FPDFPageObj_Destroy() to free // it. // Note that when removing a |page_object| of type FPDF_PAGEOBJ_TEXT, all // FPDF_TEXTPAGE handles for |page| are no longer valid. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_RemoveObject(FPDF_PAGE page, FPDF_PAGEOBJECT page_object); // Get number of page objects inside |page|. // // page - handle to a page. // // Returns the number of objects in |page|. FPDF_EXPORT int FPDF_CALLCONV FPDFPage_CountObjects(FPDF_PAGE page); // Get object in |page| at |index|. // // page - handle to a page. // index - the index of a page object. // // Returns the handle to the page object, or NULL on failed. FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV FPDFPage_GetObject(FPDF_PAGE page, int index); // Checks if |page| contains transparency. // // page - handle to a page. // // Returns TRUE if |page| contains transparency. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_HasTransparency(FPDF_PAGE page); // Generate the content of |page|. // // page - handle to a page. // // Returns TRUE on success. // // Before you save the page to a file, or reload the page, you must call // |FPDFPage_GenerateContent| or any changes to |page| will be lost. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_GenerateContent(FPDF_PAGE page); // Destroy |page_object| by releasing its resources. |page_object| must have // been created by FPDFPageObj_CreateNew{Path|Rect}() or // FPDFPageObj_New{Text|Image}Obj(). This function must be called on // newly-created objects if they are not added to a page through // FPDFPage_InsertObject() or to an annotation through FPDFAnnot_AppendObject(). // // page_object - handle to a page object. FPDF_EXPORT void FPDF_CALLCONV FPDFPageObj_Destroy(FPDF_PAGEOBJECT page_object); // Checks if |page_object| contains transparency. // // page_object - handle to a page object. // // Returns TRUE if |page_object| contains transparency. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_HasTransparency(FPDF_PAGEOBJECT page_object); // Get type of |page_object|. // // page_object - handle to a page object. // // Returns one of the FPDF_PAGEOBJ_* values on success, FPDF_PAGEOBJ_UNKNOWN on // error. FPDF_EXPORT int FPDF_CALLCONV FPDFPageObj_GetType(FPDF_PAGEOBJECT page_object); // Experimental API. // Gets active state for |page_object| within page. // // page_object - handle to a page object. // active - pointer to variable that will receive if the page object is // active. This is a required parameter. Not filled if FALSE // is returned. // // For page objects where |active| is filled with FALSE, the |page_object| is // treated as if it wasn't in the document even though it is still held // internally. // // Returns TRUE if the operation succeeded, FALSE if it failed. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_GetIsActive(FPDF_PAGEOBJECT page_object, FPDF_BOOL* active); // Experimental API. // Sets if |page_object| is active within page. // // page_object - handle to a page object. // active - a boolean specifying if the object is active. // // Returns TRUE on success. // // Page objects all start in the active state by default, and remain in that // state unless this function is called. // // When |active| is false, this makes the |page_object| be treated as if it // wasn't in the document even though it is still held internally. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_SetIsActive(FPDF_PAGEOBJECT page_object, FPDF_BOOL active); // Transform |page_object| by the given matrix. // // page_object - handle to a page object. // a - matrix value. // b - matrix value. // c - matrix value. // d - matrix value. // e - matrix value. // f - matrix value. // // The matrix is composed as: // |a c e| // |b d f| // and can be used to scale, rotate, shear and translate the |page_object|. FPDF_EXPORT void FPDF_CALLCONV FPDFPageObj_Transform(FPDF_PAGEOBJECT page_object, double a, double b, double c, double d, double e, double f); // Experimental API. // Transform |page_object| by the given matrix. // // page_object - handle to a page object. // matrix - the transform matrix. // // Returns TRUE on success. // // This can be used to scale, rotate, shear and translate the |page_object|. // It is an improved version of FPDFPageObj_Transform() that does not do // unnecessary double to float conversions, and only uses 1 parameter for the // matrix. It also returns whether the operation succeeded or not. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_TransformF(FPDF_PAGEOBJECT page_object, const FS_MATRIX* matrix); // Experimental API. // Get the transform matrix of a page object. // // page_object - handle to a page object. // matrix - pointer to struct to receive the matrix value. // // The matrix is composed as: // |a c e| // |b d f| // and used to scale, rotate, shear and translate the page object. // // For page objects outside form objects, the matrix values are relative to the // page that contains it. // For page objects inside form objects, the matrix values are relative to the // form that contains it. // // Returns TRUE on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_GetMatrix(FPDF_PAGEOBJECT page_object, FS_MATRIX* matrix); // Experimental API. // Set the transform matrix of a page object. // // page_object - handle to a page object. // matrix - pointer to struct with the matrix value. // // The matrix is composed as: // |a c e| // |b d f| // and can be used to scale, rotate, shear and translate the page object. // // Returns TRUE on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_SetMatrix(FPDF_PAGEOBJECT page_object, const FS_MATRIX* matrix); // Transform all annotations in |page|. // // page - handle to a page. // a - matrix value. // b - matrix value. // c - matrix value. // d - matrix value. // e - matrix value. // f - matrix value. // // The matrix is composed as: // |a c e| // |b d f| // and can be used to scale, rotate, shear and translate the |page| annotations. FPDF_EXPORT void FPDF_CALLCONV FPDFPage_TransformAnnots(FPDF_PAGE page, double a, double b, double c, double d, double e, double f); // Create a new image object. // // document - handle to a document. // // Returns a handle to a new image object. FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV FPDFPageObj_NewImageObj(FPDF_DOCUMENT document); // Experimental API. // Get the marked content ID for the object. // // page_object - handle to a page object. // // Returns the page object's marked content ID, or -1 on error. FPDF_EXPORT int FPDF_CALLCONV FPDFPageObj_GetMarkedContentID(FPDF_PAGEOBJECT page_object); // Experimental API. // Get number of content marks in |page_object|. // // page_object - handle to a page object. // // Returns the number of content marks in |page_object|, or -1 in case of // failure. FPDF_EXPORT int FPDF_CALLCONV FPDFPageObj_CountMarks(FPDF_PAGEOBJECT page_object); // Experimental API. // Get content mark in |page_object| at |index|. // // page_object - handle to a page object. // index - the index of a page object. // // Returns the handle to the content mark, or NULL on failure. The handle is // still owned by the library, and it should not be freed directly. It becomes // invalid if the page object is destroyed, either directly or indirectly by // unloading the page. FPDF_EXPORT FPDF_PAGEOBJECTMARK FPDF_CALLCONV FPDFPageObj_GetMark(FPDF_PAGEOBJECT page_object, unsigned long index); // Experimental API. // Add a new content mark to a |page_object|. // // page_object - handle to a page object. // name - the name (tag) of the mark. // // Returns the handle to the content mark, or NULL on failure. The handle is // still owned by the library, and it should not be freed directly. It becomes // invalid if the page object is destroyed, either directly or indirectly by // unloading the page. FPDF_EXPORT FPDF_PAGEOBJECTMARK FPDF_CALLCONV FPDFPageObj_AddMark(FPDF_PAGEOBJECT page_object, FPDF_BYTESTRING name); // Experimental API. // Removes a content |mark| from a |page_object|. // The mark handle will be invalid after the removal. // // page_object - handle to a page object. // mark - handle to a content mark in that object to remove. // // Returns TRUE if the operation succeeded, FALSE if it failed. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_RemoveMark(FPDF_PAGEOBJECT page_object, FPDF_PAGEOBJECTMARK mark); // Experimental API. // Get the name of a content mark. // // mark - handle to a content mark. // buffer - buffer for holding the returned name in UTF-16LE. This is only // modified if |buflen| is large enough to store the name. // Optional, pass null to just retrieve the size of the buffer // needed. // buflen - length of the buffer in bytes. // out_buflen - pointer to variable that will receive the minimum buffer size // in bytes to contain the name. This is a required parameter. // Not filled if FALSE is returned. // // Returns TRUE if the operation succeeded, FALSE if it failed. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObjMark_GetName(FPDF_PAGEOBJECTMARK mark, FPDF_WCHAR* buffer, unsigned long buflen, unsigned long* out_buflen); // Experimental API. // Get the number of key/value pair parameters in |mark|. // // mark - handle to a content mark. // // Returns the number of key/value pair parameters |mark|, or -1 in case of // failure. FPDF_EXPORT int FPDF_CALLCONV FPDFPageObjMark_CountParams(FPDF_PAGEOBJECTMARK mark); // Experimental API. // Get the key of a property in a content mark. // // mark - handle to a content mark. // index - index of the property. // buffer - buffer for holding the returned key in UTF-16LE. This is only // modified if |buflen| is large enough to store the key. // Optional, pass null to just retrieve the size of the buffer // needed. // buflen - length of the buffer in bytes. // out_buflen - pointer to variable that will receive the minimum buffer size // in bytes to contain the name. This is a required parameter. // Not filled if FALSE is returned. // // Returns TRUE if the operation was successful, FALSE otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObjMark_GetParamKey(FPDF_PAGEOBJECTMARK mark, unsigned long index, FPDF_WCHAR* buffer, unsigned long buflen, unsigned long* out_buflen); // Experimental API. // Get the type of the value of a property in a content mark by key. // // mark - handle to a content mark. // key - string key of the property. // // Returns the type of the value, or FPDF_OBJECT_UNKNOWN in case of failure. FPDF_EXPORT FPDF_OBJECT_TYPE FPDF_CALLCONV FPDFPageObjMark_GetParamValueType(FPDF_PAGEOBJECTMARK mark, FPDF_BYTESTRING key); // Experimental API. // Get the value of a number property in a content mark by key as int. // FPDFPageObjMark_GetParamValueType() should have returned FPDF_OBJECT_NUMBER // for this property. // // mark - handle to a content mark. // key - string key of the property. // out_value - pointer to variable that will receive the value. Not filled if // false is returned. // // Returns TRUE if the key maps to a number value, FALSE otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObjMark_GetParamIntValue(FPDF_PAGEOBJECTMARK mark, FPDF_BYTESTRING key, int* out_value); // Experimental API. // Get the value of a number property in a content mark by key as float. // FPDFPageObjMark_GetParamValueType() should have returned FPDF_OBJECT_NUMBER // for this property. // // mark - handle to a content mark. // key - string key of the property. // out_value - pointer to variable that will receive the value. Not filled if // false is returned. // // Returns TRUE if the key maps to a number value, FALSE otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObjMark_GetParamFloatValue(FPDF_PAGEOBJECTMARK mark, FPDF_BYTESTRING key, float* out_value); // Experimental API. // Get the value of a string property in a content mark by key. // // mark - handle to a content mark. // key - string key of the property. // buffer - buffer for holding the returned value in UTF-16LE. This is // only modified if |buflen| is large enough to store the value. // Optional, pass null to just retrieve the size of the buffer // needed. // buflen - length of the buffer in bytes. // out_buflen - pointer to variable that will receive the minimum buffer size // in bytes to contain the name. This is a required parameter. // Not filled if FALSE is returned. // // Returns TRUE if the key maps to a string/blob value, FALSE otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObjMark_GetParamStringValue(FPDF_PAGEOBJECTMARK mark, FPDF_BYTESTRING key, FPDF_WCHAR* buffer, unsigned long buflen, unsigned long* out_buflen); // Experimental API. // Get the value of a blob property in a content mark by key. // // mark - handle to a content mark. // key - string key of the property. // buffer - buffer for holding the returned value. This is only modified // if |buflen| is large enough to store the value. // Optional, pass null to just retrieve the size of the buffer // needed. // buflen - length of the buffer in bytes. // out_buflen - pointer to variable that will receive the minimum buffer size // in bytes to contain the name. This is a required parameter. // Not filled if FALSE is returned. // // Returns TRUE if the key maps to a string/blob value, FALSE otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObjMark_GetParamBlobValue(FPDF_PAGEOBJECTMARK mark, FPDF_BYTESTRING key, unsigned char* buffer, unsigned long buflen, unsigned long* out_buflen); // Experimental API. // Set the value of an int property in a content mark by key. If a parameter // with key |key| exists, its value is set to |value|. Otherwise, it is added as // a new parameter. // // document - handle to the document. // page_object - handle to the page object with the mark. // mark - handle to a content mark. // key - string key of the property. // value - int value to set. // // Returns TRUE if the operation succeeded, FALSE otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObjMark_SetIntParam(FPDF_DOCUMENT document, FPDF_PAGEOBJECT page_object, FPDF_PAGEOBJECTMARK mark, FPDF_BYTESTRING key, int value); // Experimental API. // Set the value of a float property in a content mark by key. If a parameter // with key |key| exists, its value is set to |value|. Otherwise, it is added as // a new parameter. // // document - handle to the document. // page_object - handle to the page object with the mark. // mark - handle to a content mark. // key - string key of the property. // value - float value to set. // // Returns TRUE if the operation succeeded, FALSE otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObjMark_SetFloatParam(FPDF_DOCUMENT document, FPDF_PAGEOBJECT page_object, FPDF_PAGEOBJECTMARK mark, FPDF_BYTESTRING key, float value); // Experimental API. // Set the value of a string property in a content mark by key. If a parameter // with key |key| exists, its value is set to |value|. Otherwise, it is added as // a new parameter. // // document - handle to the document. // page_object - handle to the page object with the mark. // mark - handle to a content mark. // key - string key of the property. // value - string value to set. // // Returns TRUE if the operation succeeded, FALSE otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObjMark_SetStringParam(FPDF_DOCUMENT document, FPDF_PAGEOBJECT page_object, FPDF_PAGEOBJECTMARK mark, FPDF_BYTESTRING key, FPDF_BYTESTRING value); // Experimental API. // Set the value of a blob property in a content mark by key. If a parameter // with key |key| exists, its value is set to |value|. Otherwise, it is added as // a new parameter. // // document - handle to the document. // page_object - handle to the page object with the mark. // mark - handle to a content mark. // key - string key of the property. // value - pointer to blob value to set. // value_len - size in bytes of |value|. // // Returns TRUE if the operation succeeded, FALSE otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObjMark_SetBlobParam(FPDF_DOCUMENT document, FPDF_PAGEOBJECT page_object, FPDF_PAGEOBJECTMARK mark, FPDF_BYTESTRING key, const unsigned char* value, unsigned long value_len); // Experimental API. // Removes a property from a content mark by key. // // page_object - handle to the page object with the mark. // mark - handle to a content mark. // key - string key of the property. // // Returns TRUE if the operation succeeded, FALSE otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObjMark_RemoveParam(FPDF_PAGEOBJECT page_object, FPDF_PAGEOBJECTMARK mark, FPDF_BYTESTRING key); // Load an image from a JPEG image file and then set it into |image_object|. // // pages - pointer to the start of all loaded pages, may be NULL. // count - number of |pages|, may be 0. // image_object - handle to an image object. // file_access - file access handler which specifies the JPEG image file. // // Returns TRUE on success. // // The image object might already have an associated image, which is shared and // cached by the loaded pages. In that case, we need to clear the cached image // for all the loaded pages. Pass |pages| and page count (|count|) to this API // to clear the image cache. If the image is not previously shared, or NULL is a // valid |pages| value. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFImageObj_LoadJpegFile(FPDF_PAGE* pages, int count, FPDF_PAGEOBJECT image_object, FPDF_FILEACCESS* file_access); // Load an image from a JPEG image file and then set it into |image_object|. // // pages - pointer to the start of all loaded pages, may be NULL. // count - number of |pages|, may be 0. // image_object - handle to an image object. // file_access - file access handler which specifies the JPEG image file. // // Returns TRUE on success. // // The image object might already have an associated image, which is shared and // cached by the loaded pages. In that case, we need to clear the cached image // for all the loaded pages. Pass |pages| and page count (|count|) to this API // to clear the image cache. If the image is not previously shared, or NULL is a // valid |pages| value. This function loads the JPEG image inline, so the image // content is copied to the file. This allows |file_access| and its associated // data to be deleted after this function returns. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFImageObj_LoadJpegFileInline(FPDF_PAGE* pages, int count, FPDF_PAGEOBJECT image_object, FPDF_FILEACCESS* file_access); // TODO(thestig): Start deprecating this once FPDFPageObj_SetMatrix() is stable. // // Set the transform matrix of |image_object|. // // image_object - handle to an image object. // a - matrix value. // b - matrix value. // c - matrix value. // d - matrix value. // e - matrix value. // f - matrix value. // // The matrix is composed as: // |a c e| // |b d f| // and can be used to scale, rotate, shear and translate the |image_object|. // // Returns TRUE on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFImageObj_SetMatrix(FPDF_PAGEOBJECT image_object, double a, double b, double c, double d, double e, double f); // Set |bitmap| to |image_object|. // // pages - pointer to the start of all loaded pages, may be NULL. // count - number of |pages|, may be 0. // image_object - handle to an image object. // bitmap - handle of the bitmap. // // Returns TRUE on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFImageObj_SetBitmap(FPDF_PAGE* pages, int count, FPDF_PAGEOBJECT image_object, FPDF_BITMAP bitmap); // Get a bitmap rasterization of |image_object|. FPDFImageObj_GetBitmap() only // operates on |image_object| and does not take the associated image mask into // account. It also ignores the matrix for |image_object|. // The returned bitmap will be owned by the caller, and FPDFBitmap_Destroy() // must be called on the returned bitmap when it is no longer needed. // // image_object - handle to an image object. // // Returns the bitmap. FPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV FPDFImageObj_GetBitmap(FPDF_PAGEOBJECT image_object); // Experimental API. // Get a bitmap rasterization of |image_object| that takes the image mask and // image matrix into account. To render correctly, the caller must provide the // |document| associated with |image_object|. If there is a |page| associated // with |image_object|, the caller should provide that as well. // The returned bitmap will be owned by the caller, and FPDFBitmap_Destroy() // must be called on the returned bitmap when it is no longer needed. // // document - handle to a document associated with |image_object|. // page - handle to an optional page associated with |image_object|. // image_object - handle to an image object. // // Returns the bitmap or NULL on failure. FPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV FPDFImageObj_GetRenderedBitmap(FPDF_DOCUMENT document, FPDF_PAGE page, FPDF_PAGEOBJECT image_object); // Get the decoded image data of |image_object|. The decoded data is the // uncompressed image data, i.e. the raw image data after having all filters // applied. |buffer| is only modified if |buflen| is longer than the length of // the decoded image data. // // image_object - handle to an image object. // buffer - buffer for holding the decoded image data. // buflen - length of the buffer in bytes. // // Returns the length of the decoded image data. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFImageObj_GetImageDataDecoded(FPDF_PAGEOBJECT image_object, void* buffer, unsigned long buflen); // Get the raw image data of |image_object|. The raw data is the image data as // stored in the PDF without applying any filters. |buffer| is only modified if // |buflen| is longer than the length of the raw image data. // // image_object - handle to an image object. // buffer - buffer for holding the raw image data. // buflen - length of the buffer in bytes. // // Returns the length of the raw image data. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFImageObj_GetImageDataRaw(FPDF_PAGEOBJECT image_object, void* buffer, unsigned long buflen); // Get the number of filters (i.e. decoders) of the image in |image_object|. // // image_object - handle to an image object. // // Returns the number of |image_object|'s filters. FPDF_EXPORT int FPDF_CALLCONV FPDFImageObj_GetImageFilterCount(FPDF_PAGEOBJECT image_object); // Get the filter at |index| of |image_object|'s list of filters. Note that the // filters need to be applied in order, i.e. the first filter should be applied // first, then the second, etc. |buffer| is only modified if |buflen| is longer // than the length of the filter string. // // image_object - handle to an image object. // index - the index of the filter requested. // buffer - buffer for holding filter string, encoded in UTF-8. // buflen - length of the buffer. // // Returns the length of the filter string. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFImageObj_GetImageFilter(FPDF_PAGEOBJECT image_object, int index, void* buffer, unsigned long buflen); // Get the image metadata of |image_object|, including dimension, DPI, bits per // pixel, and colorspace. If the |image_object| is not an image object or if it // does not have an image, then the return value will be false. Otherwise, // failure to retrieve any specific parameter would result in its value being 0. // // image_object - handle to an image object. // page - handle to the page that |image_object| is on. Required for // retrieving the image's bits per pixel and colorspace. // metadata - receives the image metadata; must not be NULL. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFImageObj_GetImageMetadata(FPDF_PAGEOBJECT image_object, FPDF_PAGE page, FPDF_IMAGEOBJ_METADATA* metadata); // Experimental API. // Get the image size in pixels. Faster method to get only image size. // // image_object - handle to an image object. // width - receives the image width in pixels; must not be NULL. // height - receives the image height in pixels; must not be NULL. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFImageObj_GetImagePixelSize(FPDF_PAGEOBJECT image_object, unsigned int* width, unsigned int* height); // Experimental API. // Get ICC profile decoded data of |image_object|. If the |image_object| is not // an image object or if it does not have an image, then the return value will // be false. It also returns false if the |image_object| has no ICC profile. // |buffer| is only modified if ICC profile exists and |buflen| is longer than // the length of the ICC profile decoded data. // // image_object - handle to an image object; must not be NULL. // page - handle to the page containing |image_object|; must not be // NULL. Required for retrieving the image's colorspace. // buffer - Buffer to receive ICC profile data; may be NULL if querying // required size via |out_buflen|. // buflen - Length of the buffer in bytes. Ignored if |buffer| is NULL. // out_buflen - Pointer to receive the ICC profile data size in bytes; must // not be NULL. Will be set if this API returns true. // // Returns true if |out_buflen| is not null and an ICC profile exists for the // given |image_object|. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFImageObj_GetIccProfileDataDecoded(FPDF_PAGEOBJECT image_object, FPDF_PAGE page, uint8_t* buffer, size_t buflen, size_t* out_buflen); // Create a new path object at an initial position. // // x - initial horizontal position. // y - initial vertical position. // // Returns a handle to a new path object. FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV FPDFPageObj_CreateNewPath(float x, float y); // Create a closed path consisting of a rectangle. // // x - horizontal position for the left boundary of the rectangle. // y - vertical position for the bottom boundary of the rectangle. // w - width of the rectangle. // h - height of the rectangle. // // Returns a handle to the new path object. FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV FPDFPageObj_CreateNewRect(float x, float y, float w, float h); // Get the bounding box of |page_object|. // // page_object - handle to a page object. // left - pointer where the left coordinate will be stored // bottom - pointer where the bottom coordinate will be stored // right - pointer where the right coordinate will be stored // top - pointer where the top coordinate will be stored // // On success, returns TRUE and fills in the 4 coordinates. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_GetBounds(FPDF_PAGEOBJECT page_object, float* left, float* bottom, float* right, float* top); // Experimental API. // Get the quad points that bounds |page_object|. // // page_object - handle to a page object. // quad_points - pointer where the quadrilateral points will be stored. // // On success, returns TRUE and fills in |quad_points|. // // Similar to FPDFPageObj_GetBounds(), this returns the bounds of a page // object. When the object is rotated by a non-multiple of 90 degrees, this API // returns a tighter bound that cannot be represented with just the 4 sides of // a rectangle. // // Currently only works the following |page_object| types: FPDF_PAGEOBJ_TEXT and // FPDF_PAGEOBJ_IMAGE. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_GetRotatedBounds(FPDF_PAGEOBJECT page_object, FS_QUADPOINTSF* quad_points); // Set the blend mode of |page_object|. // // page_object - handle to a page object. // blend_mode - string containing the blend mode. // // Blend mode can be one of following: Color, ColorBurn, ColorDodge, Darken, // Difference, Exclusion, HardLight, Hue, Lighten, Luminosity, Multiply, Normal, // Overlay, Saturation, Screen, SoftLight FPDF_EXPORT void FPDF_CALLCONV FPDFPageObj_SetBlendMode(FPDF_PAGEOBJECT page_object, FPDF_BYTESTRING blend_mode); // Set the stroke RGBA of a page object. Range of values: 0 - 255. // // page_object - the handle to the page object. // R - the red component for the object's stroke color. // G - the green component for the object's stroke color. // B - the blue component for the object's stroke color. // A - the stroke alpha for the object. // // Returns TRUE on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_SetStrokeColor(FPDF_PAGEOBJECT page_object, unsigned int R, unsigned int G, unsigned int B, unsigned int A); // Get the stroke RGBA of a page object. Range of values: 0 - 255. // // page_object - the handle to the page object. // R - the red component of the path stroke color. // G - the green component of the object's stroke color. // B - the blue component of the object's stroke color. // A - the stroke alpha of the object. // // Returns TRUE on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_GetStrokeColor(FPDF_PAGEOBJECT page_object, unsigned int* R, unsigned int* G, unsigned int* B, unsigned int* A); // Set the stroke width of a page object. // // path - the handle to the page object. // width - the width of the stroke. // // Returns TRUE on success FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_SetStrokeWidth(FPDF_PAGEOBJECT page_object, float width); // Get the stroke width of a page object. // // path - the handle to the page object. // width - the width of the stroke. // // Returns TRUE on success FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_GetStrokeWidth(FPDF_PAGEOBJECT page_object, float* width); // Get the line join of |page_object|. // // page_object - handle to a page object. // // Returns the line join, or -1 on failure. // Line join can be one of following: FPDF_LINEJOIN_MITER, FPDF_LINEJOIN_ROUND, // FPDF_LINEJOIN_BEVEL FPDF_EXPORT int FPDF_CALLCONV FPDFPageObj_GetLineJoin(FPDF_PAGEOBJECT page_object); // Set the line join of |page_object|. // // page_object - handle to a page object. // line_join - line join // // Line join can be one of following: FPDF_LINEJOIN_MITER, FPDF_LINEJOIN_ROUND, // FPDF_LINEJOIN_BEVEL FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_SetLineJoin(FPDF_PAGEOBJECT page_object, int line_join); // Get the line cap of |page_object|. // // page_object - handle to a page object. // // Returns the line cap, or -1 on failure. // Line cap can be one of following: FPDF_LINECAP_BUTT, FPDF_LINECAP_ROUND, // FPDF_LINECAP_PROJECTING_SQUARE FPDF_EXPORT int FPDF_CALLCONV FPDFPageObj_GetLineCap(FPDF_PAGEOBJECT page_object); // Set the line cap of |page_object|. // // page_object - handle to a page object. // line_cap - line cap // // Line cap can be one of following: FPDF_LINECAP_BUTT, FPDF_LINECAP_ROUND, // FPDF_LINECAP_PROJECTING_SQUARE FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_SetLineCap(FPDF_PAGEOBJECT page_object, int line_cap); // Set the fill RGBA of a page object. Range of values: 0 - 255. // // page_object - the handle to the page object. // R - the red component for the object's fill color. // G - the green component for the object's fill color. // B - the blue component for the object's fill color. // A - the fill alpha for the object. // // Returns TRUE on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_SetFillColor(FPDF_PAGEOBJECT page_object, unsigned int R, unsigned int G, unsigned int B, unsigned int A); // Get the fill RGBA of a page object. Range of values: 0 - 255. // // page_object - the handle to the page object. // R - the red component of the object's fill color. // G - the green component of the object's fill color. // B - the blue component of the object's fill color. // A - the fill alpha of the object. // // Returns TRUE on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_GetFillColor(FPDF_PAGEOBJECT page_object, unsigned int* R, unsigned int* G, unsigned int* B, unsigned int* A); // Experimental API. // Get the line dash |phase| of |page_object|. // // page_object - handle to a page object. // phase - pointer where the dashing phase will be stored. // // Returns TRUE on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_GetDashPhase(FPDF_PAGEOBJECT page_object, float* phase); // Experimental API. // Set the line dash phase of |page_object|. // // page_object - handle to a page object. // phase - line dash phase. // // Returns TRUE on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_SetDashPhase(FPDF_PAGEOBJECT page_object, float phase); // Experimental API. // Get the line dash array of |page_object|. // // page_object - handle to a page object. // // Returns the line dash array size or -1 on failure. FPDF_EXPORT int FPDF_CALLCONV FPDFPageObj_GetDashCount(FPDF_PAGEOBJECT page_object); // Experimental API. // Get the line dash array of |page_object|. // // page_object - handle to a page object. // dash_array - pointer where the dashing array will be stored. // dash_count - number of elements in |dash_array|. // // Returns TRUE on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_GetDashArray(FPDF_PAGEOBJECT page_object, float* dash_array, size_t dash_count); // Experimental API. // Set the line dash array of |page_object|. // // page_object - handle to a page object. // dash_array - the dash array. // dash_count - number of elements in |dash_array|. // phase - the line dash phase. // // Returns TRUE on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_SetDashArray(FPDF_PAGEOBJECT page_object, const float* dash_array, size_t dash_count, float phase); // Get number of segments inside |path|. // // path - handle to a path. // // A segment is a command, created by e.g. FPDFPath_MoveTo(), // FPDFPath_LineTo() or FPDFPath_BezierTo(). // // Returns the number of objects in |path| or -1 on failure. FPDF_EXPORT int FPDF_CALLCONV FPDFPath_CountSegments(FPDF_PAGEOBJECT path); // Get segment in |path| at |index|. // // path - handle to a path. // index - the index of a segment. // // Returns the handle to the segment, or NULL on faiure. FPDF_EXPORT FPDF_PATHSEGMENT FPDF_CALLCONV FPDFPath_GetPathSegment(FPDF_PAGEOBJECT path, int index); // Get coordinates of |segment|. // // segment - handle to a segment. // x - the horizontal position of the segment. // y - the vertical position of the segment. // // Returns TRUE on success, otherwise |x| and |y| is not set. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPathSegment_GetPoint(FPDF_PATHSEGMENT segment, float* x, float* y); // Get type of |segment|. // // segment - handle to a segment. // // Returns one of the FPDF_SEGMENT_* values on success, // FPDF_SEGMENT_UNKNOWN on error. FPDF_EXPORT int FPDF_CALLCONV FPDFPathSegment_GetType(FPDF_PATHSEGMENT segment); // Gets if the |segment| closes the current subpath of a given path. // // segment - handle to a segment. // // Returns close flag for non-NULL segment, FALSE otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPathSegment_GetClose(FPDF_PATHSEGMENT segment); // Move a path's current point. // // path - the handle to the path object. // x - the horizontal position of the new current point. // y - the vertical position of the new current point. // // Note that no line will be created between the previous current point and the // new one. // // Returns TRUE on success FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_MoveTo(FPDF_PAGEOBJECT path, float x, float y); // Add a line between the current point and a new point in the path. // // path - the handle to the path object. // x - the horizontal position of the new point. // y - the vertical position of the new point. // // The path's current point is changed to (x, y). // // Returns TRUE on success FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_LineTo(FPDF_PAGEOBJECT path, float x, float y); // Add a cubic Bezier curve to the given path, starting at the current point. // // path - the handle to the path object. // x1 - the horizontal position of the first Bezier control point. // y1 - the vertical position of the first Bezier control point. // x2 - the horizontal position of the second Bezier control point. // y2 - the vertical position of the second Bezier control point. // x3 - the horizontal position of the ending point of the Bezier curve. // y3 - the vertical position of the ending point of the Bezier curve. // // Returns TRUE on success FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_BezierTo(FPDF_PAGEOBJECT path, float x1, float y1, float x2, float y2, float x3, float y3); // Close the current subpath of a given path. // // path - the handle to the path object. // // This will add a line between the current point and the initial point of the // subpath, thus terminating the current subpath. // // Returns TRUE on success FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_Close(FPDF_PAGEOBJECT path); // Set the drawing mode of a path. // // path - the handle to the path object. // fillmode - the filling mode to be set: one of the FPDF_FILLMODE_* flags. // stroke - a boolean specifying if the path should be stroked or not. // // Returns TRUE on success FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_SetDrawMode(FPDF_PAGEOBJECT path, int fillmode, FPDF_BOOL stroke); // Get the drawing mode of a path. // // path - the handle to the path object. // fillmode - the filling mode of the path: one of the FPDF_FILLMODE_* flags. // stroke - a boolean specifying if the path is stroked or not. // // Returns TRUE on success FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_GetDrawMode(FPDF_PAGEOBJECT path, int* fillmode, FPDF_BOOL* stroke); // Create a new text object using one of the standard PDF fonts. // // document - handle to the document. // font - string containing the font name, without spaces. // font_size - the font size for the new text object. // // Returns a handle to a new text object, or NULL on failure FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV FPDFPageObj_NewTextObj(FPDF_DOCUMENT document, FPDF_BYTESTRING font, float font_size); // Set the text for a text object. If it had text, it will be replaced. // // text_object - handle to the text object. // text - the UTF-16LE encoded string containing the text to be added. // // Returns TRUE on success FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFText_SetText(FPDF_PAGEOBJECT text_object, FPDF_WIDESTRING text); // Experimental API. // Set the text using charcodes for a text object. If it had text, it will be // replaced. // // text_object - handle to the text object. // charcodes - pointer to an array of charcodes to be added. // count - number of elements in |charcodes|. // // Returns TRUE on success FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFText_SetCharcodes(FPDF_PAGEOBJECT text_object, const uint32_t* charcodes, size_t count); // Returns a font object loaded from a stream of data. The font is loaded // into the document. Various font data structures, such as the ToUnicode data, // are auto-generated based on the inputs. // // document - handle to the document. // data - the stream of font data, which will be copied by the font object. // size - the size of the font data, in bytes. // font_type - FPDF_FONT_TYPE1 or FPDF_FONT_TRUETYPE depending on the font type. // cid - a boolean specifying if the font is a CID font or not. // // The loaded font can be closed using FPDFFont_Close(). // // Returns NULL on failure FPDF_EXPORT FPDF_FONT FPDF_CALLCONV FPDFText_LoadFont(FPDF_DOCUMENT document, const uint8_t* data, uint32_t size, int font_type, FPDF_BOOL cid); // Experimental API. // Loads one of the standard 14 fonts per PDF spec 1.7 page 416. The preferred // way of using font style is using a dash to separate the name from the style, // for example 'Helvetica-BoldItalic'. // // document - handle to the document. // font - string containing the font name, without spaces. // // The loaded font can be closed using FPDFFont_Close(). // // Returns NULL on failure. FPDF_EXPORT FPDF_FONT FPDF_CALLCONV FPDFText_LoadStandardFont(FPDF_DOCUMENT document, FPDF_BYTESTRING font); // Experimental API. // Returns a font object loaded from a stream of data for a type 2 CID font. The // font is loaded into the document. Unlike FPDFText_LoadFont(), the ToUnicode // data and the CIDToGIDMap data are caller provided, instead of auto-generated. // // document - handle to the document. // font_data - the stream of font data, which will be copied by // the font object. // font_data_size - the size of the font data, in bytes. // to_unicode_cmap - the ToUnicode data. // cid_to_gid_map_data - the stream of CIDToGIDMap data. // cid_to_gid_map_data_size - the size of the CIDToGIDMap data, in bytes. // // The loaded font can be closed using FPDFFont_Close(). // // Returns NULL on failure. FPDF_EXPORT FPDF_FONT FPDF_CALLCONV FPDFText_LoadCidType2Font(FPDF_DOCUMENT document, const uint8_t* font_data, uint32_t font_data_size, FPDF_BYTESTRING to_unicode_cmap, const uint8_t* cid_to_gid_map_data, uint32_t cid_to_gid_map_data_size); // Get the font size of a text object. // // text - handle to a text. // size - pointer to the font size of the text object, measured in points // (about 1/72 inch) // // Returns TRUE on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFTextObj_GetFontSize(FPDF_PAGEOBJECT text, float* size); // Close a loaded PDF font. // // font - Handle to the loaded font. FPDF_EXPORT void FPDF_CALLCONV FPDFFont_Close(FPDF_FONT font); // Create a new text object using a loaded font. // // document - handle to the document. // font - handle to the font object. // font_size - the font size for the new text object. // // Returns a handle to a new text object, or NULL on failure FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV FPDFPageObj_CreateTextObj(FPDF_DOCUMENT document, FPDF_FONT font, float font_size); // Get the text rendering mode of a text object. // // text - the handle to the text object. // // Returns one of the known FPDF_TEXT_RENDERMODE enum values on success, // FPDF_TEXTRENDERMODE_UNKNOWN on error. FPDF_EXPORT FPDF_TEXT_RENDERMODE FPDF_CALLCONV FPDFTextObj_GetTextRenderMode(FPDF_PAGEOBJECT text); // Experimental API. // Set the text rendering mode of a text object. // // text - the handle to the text object. // render_mode - the FPDF_TEXT_RENDERMODE enum value to be set (cannot set to // FPDF_TEXTRENDERMODE_UNKNOWN). // // Returns TRUE on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFTextObj_SetTextRenderMode(FPDF_PAGEOBJECT text, FPDF_TEXT_RENDERMODE render_mode); // Get the text of a text object. // // text_object - the handle to the text object. // text_page - the handle to the text page. // buffer - the address of a buffer that receives the text. // length - the size, in bytes, of |buffer|. // // Returns the number of bytes in the text (including the trailing NUL // character) on success, 0 on error. // // Regardless of the platform, the |buffer| is always in UTF-16LE encoding. // If |length| is less than the returned length, or |buffer| is NULL, |buffer| // will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFTextObj_GetText(FPDF_PAGEOBJECT text_object, FPDF_TEXTPAGE text_page, FPDF_WCHAR* buffer, unsigned long length); // Experimental API. // Get a bitmap rasterization of |text_object|. To render correctly, the caller // must provide the |document| associated with |text_object|. If there is a // |page| associated with |text_object|, the caller should provide that as well. // The returned bitmap will be owned by the caller, and FPDFBitmap_Destroy() // must be called on the returned bitmap when it is no longer needed. // // document - handle to a document associated with |text_object|. // page - handle to an optional page associated with |text_object|. // text_object - handle to a text object. // scale - the scaling factor, which must be greater than 0. // // Returns the bitmap or NULL on failure. FPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV FPDFTextObj_GetRenderedBitmap(FPDF_DOCUMENT document, FPDF_PAGE page, FPDF_PAGEOBJECT text_object, float scale); // Experimental API. // Get the font of a text object. // // text - the handle to the text object. // // Returns a handle to the font object held by |text| which retains ownership. FPDF_EXPORT FPDF_FONT FPDF_CALLCONV FPDFTextObj_GetFont(FPDF_PAGEOBJECT text); // Experimental API. // Get the base name of a font. // // font - the handle to the font object. // buffer - the address of a buffer that receives the base font name. // length - the size, in bytes, of |buffer|. // // Returns the number of bytes in the base name (including the trailing NUL // character) on success, 0 on error. The base name is typically the font's // PostScript name. See descriptions of "BaseFont" in ISO 32000-1:2008 spec. // // Regardless of the platform, the |buffer| is always in UTF-8 encoding. // If |length| is less than the returned length, or |buffer| is NULL, |buffer| // will not be modified. FPDF_EXPORT size_t FPDF_CALLCONV FPDFFont_GetBaseFontName(FPDF_FONT font, char* buffer, size_t length); // Experimental API. // Get the family name of a font. // // font - the handle to the font object. // buffer - the address of a buffer that receives the font name. // length - the size, in bytes, of |buffer|. // // Returns the number of bytes in the family name (including the trailing NUL // character) on success, 0 on error. // // Regardless of the platform, the |buffer| is always in UTF-8 encoding. // If |length| is less than the returned length, or |buffer| is NULL, |buffer| // will not be modified. FPDF_EXPORT size_t FPDF_CALLCONV FPDFFont_GetFamilyName(FPDF_FONT font, char* buffer, size_t length); // Experimental API. // Get the decoded data from the |font| object. // // font - The handle to the font object. (Required) // buffer - The address of a buffer that receives the font data. // buflen - Length of the buffer. // out_buflen - Pointer to variable that will receive the minimum buffer size // to contain the font data. Not filled if the return value is // FALSE. (Required) // // Returns TRUE on success. In which case, |out_buflen| will be filled, and // |buffer| will be filled if it is large enough. Returns FALSE if any of the // required parameters are null. // // The decoded data is the uncompressed font data. i.e. the raw font data after // having all stream filters applied, when the data is embedded. // // If the font is not embedded, then this API will instead return the data for // the substitution font it is using. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFFont_GetFontData(FPDF_FONT font, uint8_t* buffer, size_t buflen, size_t* out_buflen); // Experimental API. // Get whether |font| is embedded or not. // // font - the handle to the font object. // // Returns 1 if the font is embedded, 0 if it not, and -1 on failure. FPDF_EXPORT int FPDF_CALLCONV FPDFFont_GetIsEmbedded(FPDF_FONT font); // Experimental API. // Get the descriptor flags of a font. // // font - the handle to the font object. // // Returns the bit flags specifying various characteristics of the font as // defined in ISO 32000-1:2008, table 123, -1 on failure. FPDF_EXPORT int FPDF_CALLCONV FPDFFont_GetFlags(FPDF_FONT font); // Experimental API. // Get the font weight of a font. // // font - the handle to the font object. // // Returns the font weight, -1 on failure. // Typical values are 400 (normal) and 700 (bold). FPDF_EXPORT int FPDF_CALLCONV FPDFFont_GetWeight(FPDF_FONT font); // Experimental API. // Get the italic angle of a font. // // font - the handle to the font object. // angle - pointer where the italic angle will be stored // // The italic angle of a |font| is defined as degrees counterclockwise // from vertical. For a font that slopes to the right, this will be negative. // // Returns TRUE on success; |angle| unmodified on failure. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFFont_GetItalicAngle(FPDF_FONT font, int* angle); // Experimental API. // Get ascent distance of a font. // // font - the handle to the font object. // font_size - the size of the |font|. // ascent - pointer where the font ascent will be stored // // Ascent is the maximum distance in points above the baseline reached by the // glyphs of the |font|. One point is 1/72 inch (around 0.3528 mm). // // Returns TRUE on success; |ascent| unmodified on failure. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFFont_GetAscent(FPDF_FONT font, float font_size, float* ascent); // Experimental API. // Get descent distance of a font. // // font - the handle to the font object. // font_size - the size of the |font|. // descent - pointer where the font descent will be stored // // Descent is the maximum distance in points below the baseline reached by the // glyphs of the |font|. One point is 1/72 inch (around 0.3528 mm). // // Returns TRUE on success; |descent| unmodified on failure. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFFont_GetDescent(FPDF_FONT font, float font_size, float* descent); // Experimental API. // Get the width of a glyph in a font. // // font - the handle to the font object. // glyph - the glyph. // font_size - the size of the font. // width - pointer where the glyph width will be stored // // Glyph width is the distance from the end of the prior glyph to the next // glyph. This will be the vertical distance for vertical writing. // // Returns TRUE on success; |width| unmodified on failure. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFFont_GetGlyphWidth(FPDF_FONT font, uint32_t glyph, float font_size, float* width); // Experimental API. // Get the glyphpath describing how to draw a font glyph. // // font - the handle to the font object. // glyph - the glyph being drawn. // font_size - the size of the font. // // Returns the handle to the segment, or NULL on faiure. FPDF_EXPORT FPDF_GLYPHPATH FPDF_CALLCONV FPDFFont_GetGlyphPath(FPDF_FONT font, uint32_t glyph, float font_size); // Experimental API. // Get number of segments inside glyphpath. // // glyphpath - handle to a glyph path. // // Returns the number of objects in |glyphpath| or -1 on failure. FPDF_EXPORT int FPDF_CALLCONV FPDFGlyphPath_CountGlyphSegments(FPDF_GLYPHPATH glyphpath); // Experimental API. // Get segment in glyphpath at index. // // glyphpath - handle to a glyph path. // index - the index of a segment. // // Returns the handle to the segment, or NULL on faiure. FPDF_EXPORT FPDF_PATHSEGMENT FPDF_CALLCONV FPDFGlyphPath_GetGlyphPathSegment(FPDF_GLYPHPATH glyphpath, int index); // Get number of page objects inside |form_object|. // // form_object - handle to a form object. // // Returns the number of objects in |form_object| on success, -1 on error. FPDF_EXPORT int FPDF_CALLCONV FPDFFormObj_CountObjects(FPDF_PAGEOBJECT form_object); // Get page object in |form_object| at |index|. // // form_object - handle to a form object. // index - the 0-based index of a page object. // // Returns the handle to the page object, or NULL on error. FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV FPDFFormObj_GetObject(FPDF_PAGEOBJECT form_object, unsigned long index); // Experimental API. // // Remove |page_object| from |form_object|. // // form_object - handle to a form object. // page_object - handle to a page object to be removed from the form. // // Returns TRUE on success. // // Ownership of the removed |page_object| is transferred to the caller. // Call FPDFPageObj_Destroy() on the removed page_object to free it. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFFormObj_RemoveObject(FPDF_PAGEOBJECT form_object, FPDF_PAGEOBJECT page_object); #ifdef __cplusplus } // extern "C" #endif // __cplusplus #endif // PUBLIC_FPDF_EDIT_H_ ================================================ FILE: external/pdfium/linux-x64/include/fpdf_ext.h ================================================ // Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #ifndef PUBLIC_FPDF_EXT_H_ #define PUBLIC_FPDF_EXT_H_ #include // NOLINTNEXTLINE(build/include) #include "fpdfview.h" #ifdef __cplusplus extern "C" { #endif // __cplusplus // Unsupported XFA form. #define FPDF_UNSP_DOC_XFAFORM 1 // Unsupported portable collection. #define FPDF_UNSP_DOC_PORTABLECOLLECTION 2 // Unsupported attachment. #define FPDF_UNSP_DOC_ATTACHMENT 3 // Unsupported security. #define FPDF_UNSP_DOC_SECURITY 4 // Unsupported shared review. #define FPDF_UNSP_DOC_SHAREDREVIEW 5 // Unsupported shared form, acrobat. #define FPDF_UNSP_DOC_SHAREDFORM_ACROBAT 6 // Unsupported shared form, filesystem. #define FPDF_UNSP_DOC_SHAREDFORM_FILESYSTEM 7 // Unsupported shared form, email. #define FPDF_UNSP_DOC_SHAREDFORM_EMAIL 8 // Unsupported 3D annotation. #define FPDF_UNSP_ANNOT_3DANNOT 11 // Unsupported movie annotation. #define FPDF_UNSP_ANNOT_MOVIE 12 // Unsupported sound annotation. #define FPDF_UNSP_ANNOT_SOUND 13 // Unsupported screen media annotation. #define FPDF_UNSP_ANNOT_SCREEN_MEDIA 14 // Unsupported screen rich media annotation. #define FPDF_UNSP_ANNOT_SCREEN_RICHMEDIA 15 // Unsupported attachment annotation. #define FPDF_UNSP_ANNOT_ATTACHMENT 16 // Unsupported signature annotation. #define FPDF_UNSP_ANNOT_SIG 17 // Interface for unsupported feature notifications. typedef struct _UNSUPPORT_INFO { // Version number of the interface. Must be 1. int version; // Unsupported object notification function. // Interface Version: 1 // Implementation Required: Yes // // pThis - pointer to the interface structure. // nType - the type of unsupported object. One of the |FPDF_UNSP_*| entries. void (*FSDK_UnSupport_Handler)(struct _UNSUPPORT_INFO* pThis, int nType); } UNSUPPORT_INFO; // Setup an unsupported object handler. // // unsp_info - Pointer to an UNSUPPORT_INFO structure. // // Returns TRUE on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FSDK_SetUnSpObjProcessHandler(UNSUPPORT_INFO* unsp_info); // Set replacement function for calls to time(). // // This API is intended to be used only for testing, thus may cause PDFium to // behave poorly in production environments. // // func - Function pointer to alternate implementation of time(), or // NULL to restore to actual time() call itself. FPDF_EXPORT void FPDF_CALLCONV FSDK_SetTimeFunction(time_t (*func)()); // Set replacement function for calls to localtime(). // // This API is intended to be used only for testing, thus may cause PDFium to // behave poorly in production environments. // // func - Function pointer to alternate implementation of localtime(), or // NULL to restore to actual localtime() call itself. FPDF_EXPORT void FPDF_CALLCONV FSDK_SetLocaltimeFunction(struct tm* (*func)(const time_t*)); // Unknown page mode. #define PAGEMODE_UNKNOWN -1 // Document outline, and thumbnails hidden. #define PAGEMODE_USENONE 0 // Document outline visible. #define PAGEMODE_USEOUTLINES 1 // Thumbnail images visible. #define PAGEMODE_USETHUMBS 2 // Full-screen mode, no menu bar, window controls, or other decorations visible. #define PAGEMODE_FULLSCREEN 3 // Optional content group panel visible. #define PAGEMODE_USEOC 4 // Attachments panel visible. #define PAGEMODE_USEATTACHMENTS 5 // Get the document's PageMode. // // doc - Handle to document. // // Returns one of the |PAGEMODE_*| flags defined above. // // The page mode defines how the document should be initially displayed. FPDF_EXPORT int FPDF_CALLCONV FPDFDoc_GetPageMode(FPDF_DOCUMENT document); #ifdef __cplusplus } // extern "C" #endif // __cplusplus #endif // PUBLIC_FPDF_EXT_H_ ================================================ FILE: external/pdfium/linux-x64/include/fpdf_flatten.h ================================================ // Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #ifndef PUBLIC_FPDF_FLATTEN_H_ #define PUBLIC_FPDF_FLATTEN_H_ // NOLINTNEXTLINE(build/include) #include "fpdfview.h" // Flatten operation failed. #define FLATTEN_FAIL 0 // Flatten operation succeed. #define FLATTEN_SUCCESS 1 // Nothing to be flattened. #define FLATTEN_NOTHINGTODO 2 // Flatten for normal display. #define FLAT_NORMALDISPLAY 0 // Flatten for print. #define FLAT_PRINT 1 #ifdef __cplusplus extern "C" { #endif // __cplusplus // Flatten annotations and form fields into the page contents. // // page - handle to the page. // nFlag - One of the |FLAT_*| values denoting the page usage. // // Returns one of the |FLATTEN_*| values. // // Currently, all failures return |FLATTEN_FAIL| with no indication of the // cause. FPDF_EXPORT int FPDF_CALLCONV FPDFPage_Flatten(FPDF_PAGE page, int nFlag); #ifdef __cplusplus } // extern "C" #endif // __cplusplus #endif // PUBLIC_FPDF_FLATTEN_H_ ================================================ FILE: external/pdfium/linux-x64/include/fpdf_formfill.h ================================================ // Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #ifndef PUBLIC_FPDF_FORMFILL_H_ #define PUBLIC_FPDF_FORMFILL_H_ // clang-format off // NOLINTNEXTLINE(build/include_directory) #include "fpdfview.h" // These values are return values for a public API, so should not be changed // other than the count when adding new values. #define FORMTYPE_NONE 0 // Document contains no forms #define FORMTYPE_ACRO_FORM 1 // Forms are specified using AcroForm spec #define FORMTYPE_XFA_FULL 2 // Forms are specified using entire XFA spec #define FORMTYPE_XFA_FOREGROUND 3 // Forms are specified using the XFAF subset // of XFA spec #define FORMTYPE_COUNT 4 // The number of form types #define JSPLATFORM_ALERT_BUTTON_OK 0 // OK button #define JSPLATFORM_ALERT_BUTTON_OKCANCEL 1 // OK & Cancel buttons #define JSPLATFORM_ALERT_BUTTON_YESNO 2 // Yes & No buttons #define JSPLATFORM_ALERT_BUTTON_YESNOCANCEL 3 // Yes, No & Cancel buttons #define JSPLATFORM_ALERT_BUTTON_DEFAULT JSPLATFORM_ALERT_BUTTON_OK #define JSPLATFORM_ALERT_ICON_ERROR 0 // Error #define JSPLATFORM_ALERT_ICON_WARNING 1 // Warning #define JSPLATFORM_ALERT_ICON_QUESTION 2 // Question #define JSPLATFORM_ALERT_ICON_STATUS 3 // Status #define JSPLATFORM_ALERT_ICON_ASTERISK 4 // Asterisk #define JSPLATFORM_ALERT_ICON_DEFAULT JSPLATFORM_ALERT_ICON_ERROR #define JSPLATFORM_ALERT_RETURN_OK 1 // OK #define JSPLATFORM_ALERT_RETURN_CANCEL 2 // Cancel #define JSPLATFORM_ALERT_RETURN_NO 3 // No #define JSPLATFORM_ALERT_RETURN_YES 4 // Yes #define JSPLATFORM_BEEP_ERROR 0 // Error #define JSPLATFORM_BEEP_WARNING 1 // Warning #define JSPLATFORM_BEEP_QUESTION 2 // Question #define JSPLATFORM_BEEP_STATUS 3 // Status #define JSPLATFORM_BEEP_DEFAULT 4 // Default // Exported Functions #ifdef __cplusplus extern "C" { #endif typedef struct _IPDF_JsPlatform { // Version number of the interface. Currently must be 2. int version; // Version 1. // Method: app_alert // Pop up a dialog to show warning or hint. // Interface Version: // 1 // Implementation Required: // yes // Parameters: // pThis - Pointer to the interface structure itself. // Msg - A string containing the message to be displayed. // Title - The title of the dialog. // Type - The type of button group, one of the // JSPLATFORM_ALERT_BUTTON_* values above. // nIcon - The type of the icon, one of the // JSPLATFORM_ALERT_ICON_* above. // Return Value: // Option selected by user in dialogue, one of the // JSPLATFORM_ALERT_RETURN_* values above. int (*app_alert)(struct _IPDF_JsPlatform* pThis, FPDF_WIDESTRING Msg, FPDF_WIDESTRING Title, int Type, int Icon); // Method: app_beep // Causes the system to play a sound. // Interface Version: // 1 // Implementation Required: // yes // Parameters: // pThis - Pointer to the interface structure itself // nType - The sound type, see JSPLATFORM_BEEP_TYPE_* // above. // Return Value: // None void (*app_beep)(struct _IPDF_JsPlatform* pThis, int nType); // Method: app_response // Displays a dialog box containing a question and an entry field for // the user to reply to the question. // Interface Version: // 1 // Implementation Required: // yes // Parameters: // pThis - Pointer to the interface structure itself // Question - The question to be posed to the user. // Title - The title of the dialog box. // Default - A default value for the answer to the question. If // not specified, no default value is presented. // cLabel - A short string to appear in front of and on the // same line as the edit text field. // bPassword - If true, indicates that the user's response should // be shown as asterisks (*) or bullets (?) to mask // the response, which might be sensitive information. // response - A string buffer allocated by PDFium, to receive the // user's response. // length - The length of the buffer in bytes. Currently, it is // always 2048. // Return Value: // Number of bytes the complete user input would actually require, not // including trailing zeros, regardless of the value of the length // parameter or the presence of the response buffer. // Comments: // No matter on what platform, the response buffer should be always // written using UTF-16LE encoding. If a response buffer is // present and the size of the user input exceeds the capacity of the // buffer as specified by the length parameter, only the // first "length" bytes of the user input are to be written to the // buffer. int (*app_response)(struct _IPDF_JsPlatform* pThis, FPDF_WIDESTRING Question, FPDF_WIDESTRING Title, FPDF_WIDESTRING Default, FPDF_WIDESTRING cLabel, FPDF_BOOL bPassword, void* response, int length); // Method: Doc_getFilePath // Get the file path of the current document. // Interface Version: // 1 // Implementation Required: // yes // Parameters: // pThis - Pointer to the interface structure itself // filePath - The string buffer to receive the file path. Can // be NULL. // length - The length of the buffer, number of bytes. Can // be 0. // Return Value: // Number of bytes the filePath consumes, including trailing zeros. // Comments: // The filePath should always be provided in the local encoding. // The return value always indicated number of bytes required for // the buffer, even when there is no buffer specified, or the buffer // size is less than required. In this case, the buffer will not // be modified. int (*Doc_getFilePath)(struct _IPDF_JsPlatform* pThis, void* filePath, int length); // Method: Doc_mail // Mails the data buffer as an attachment to all recipients, with or // without user interaction. // Interface Version: // 1 // Implementation Required: // yes // Parameters: // pThis - Pointer to the interface structure itself // mailData - Pointer to the data buffer to be sent. Can be NULL. // length - The size,in bytes, of the buffer pointed by // mailData parameter. Can be 0. // bUI - If true, the rest of the parameters are used in a // compose-new-message window that is displayed to the // user. If false, the cTo parameter is required and // all others are optional. // To - A semicolon-delimited list of recipients for the // message. // Subject - The subject of the message. The length limit is // 64 KB. // CC - A semicolon-delimited list of CC recipients for // the message. // BCC - A semicolon-delimited list of BCC recipients for // the message. // Msg - The content of the message. The length limit is // 64 KB. // Return Value: // None. // Comments: // If the parameter mailData is NULL or length is 0, the current // document will be mailed as an attachment to all recipients. void (*Doc_mail)(struct _IPDF_JsPlatform* pThis, void* mailData, int length, FPDF_BOOL bUI, FPDF_WIDESTRING To, FPDF_WIDESTRING Subject, FPDF_WIDESTRING CC, FPDF_WIDESTRING BCC, FPDF_WIDESTRING Msg); // Method: Doc_print // Prints all or a specific number of pages of the document. // Interface Version: // 1 // Implementation Required: // yes // Parameters: // pThis - Pointer to the interface structure itself. // bUI - If true, will cause a UI to be presented to the // user to obtain printing information and confirm // the action. // nStart - A 0-based index that defines the start of an // inclusive range of pages. // nEnd - A 0-based index that defines the end of an // inclusive page range. // bSilent - If true, suppresses the cancel dialog box while // the document is printing. The default is false. // bShrinkToFit - If true, the page is shrunk (if necessary) to // fit within the imageable area of the printed page. // bPrintAsImage - If true, print pages as an image. // bReverse - If true, print from nEnd to nStart. // bAnnotations - If true (the default), annotations are // printed. // Return Value: // None. void (*Doc_print)(struct _IPDF_JsPlatform* pThis, FPDF_BOOL bUI, int nStart, int nEnd, FPDF_BOOL bSilent, FPDF_BOOL bShrinkToFit, FPDF_BOOL bPrintAsImage, FPDF_BOOL bReverse, FPDF_BOOL bAnnotations); // Method: Doc_submitForm // Send the form data to a specified URL. // Interface Version: // 1 // Implementation Required: // yes // Parameters: // pThis - Pointer to the interface structure itself // formData - Pointer to the data buffer to be sent. // length - The size,in bytes, of the buffer pointed by // formData parameter. // URL - The URL to send to. // Return Value: // None. void (*Doc_submitForm)(struct _IPDF_JsPlatform* pThis, void* formData, int length, FPDF_WIDESTRING URL); // Method: Doc_gotoPage // Jump to a specified page. // Interface Version: // 1 // Implementation Required: // yes // Parameters: // pThis - Pointer to the interface structure itself // nPageNum - The specified page number, zero for the first page. // Return Value: // None. void (*Doc_gotoPage)(struct _IPDF_JsPlatform* pThis, int nPageNum); // Method: Field_browse // Show a file selection dialog, and return the selected file path. // Interface Version: // 1 // Implementation Required: // yes // Parameters: // pThis - Pointer to the interface structure itself. // filePath - Pointer to the data buffer to receive the file // path. Can be NULL. // length - The length of the buffer, in bytes. Can be 0. // Return Value: // Number of bytes the filePath consumes, including trailing zeros. // Comments: // The filePath should always be provided in local encoding. int (*Field_browse)(struct _IPDF_JsPlatform* pThis, void* filePath, int length); // Pointer for embedder-specific data. Unused by PDFium, and despite // its name, can be any data the embedder desires, though traditionally // a FPDF_FORMFILLINFO interface. void* m_pFormfillinfo; // Version 2. void* m_isolate; // Unused in v3, retain for compatibility. unsigned int m_v8EmbedderSlot; // Unused in v3, retain for compatibility. // Version 3. // Version 3 moves m_Isolate and m_v8EmbedderSlot to FPDF_LIBRARY_CONFIG. } IPDF_JSPLATFORM; // Flags for Cursor type #define FXCT_ARROW 0 #define FXCT_NESW 1 #define FXCT_NWSE 2 #define FXCT_VBEAM 3 #define FXCT_HBEAM 4 #define FXCT_HAND 5 // Function signature for the callback function passed to the FFI_SetTimer // method. // Parameters: // idEvent - Identifier of the timer. // Return value: // None. typedef void (*TimerCallback)(int idEvent); // Declares of a struct type to the local system time. typedef struct _FPDF_SYSTEMTIME { unsigned short wYear; // years since 1900 unsigned short wMonth; // months since January - [0,11] unsigned short wDayOfWeek; // days since Sunday - [0,6] unsigned short wDay; // day of the month - [1,31] unsigned short wHour; // hours since midnight - [0,23] unsigned short wMinute; // minutes after the hour - [0,59] unsigned short wSecond; // seconds after the minute - [0,59] unsigned short wMilliseconds; // milliseconds after the second - [0,999] } FPDF_SYSTEMTIME; #ifdef PDF_ENABLE_XFA // Pageview event flags #define FXFA_PAGEVIEWEVENT_POSTADDED 1 // After a new pageview is added. #define FXFA_PAGEVIEWEVENT_POSTREMOVED 3 // After a pageview is removed. // Definitions for Right Context Menu Features Of XFA Fields #define FXFA_MENU_COPY 1 #define FXFA_MENU_CUT 2 #define FXFA_MENU_SELECTALL 4 #define FXFA_MENU_UNDO 8 #define FXFA_MENU_REDO 16 #define FXFA_MENU_PASTE 32 // Definitions for File Type. #define FXFA_SAVEAS_XML 1 #define FXFA_SAVEAS_XDP 2 #endif // PDF_ENABLE_XFA typedef struct _FPDF_FORMFILLINFO { // Version number of the interface. // Version 1 contains stable interfaces. Version 2 has additional // experimental interfaces. // When PDFium is built without the XFA module, version can be 1 or 2. // With version 1, only stable interfaces are called. With version 2, // additional experimental interfaces are also called. // When PDFium is built with the XFA module, version must be 2. // All the XFA related interfaces are experimental. If PDFium is built with // the XFA module and version 1 then none of the XFA related interfaces // would be called. When PDFium is built with XFA module then the version // must be 2. int version; // Version 1. // Method: Release // Give the implementation a chance to release any resources after the // interface is no longer used. // Interface Version: // 1 // Implementation Required: // No // Comments: // Called by PDFium during the final cleanup process. // Parameters: // pThis - Pointer to the interface structure itself // Return Value: // None void (*Release)(struct _FPDF_FORMFILLINFO* pThis); // Method: FFI_Invalidate // Invalidate the client area within the specified rectangle. // Interface Version: // 1 // Implementation Required: // yes // Parameters: // pThis - Pointer to the interface structure itself. // page - Handle to the page. Returned by FPDF_LoadPage(). // left - Left position of the client area in PDF page // coordinates. // top - Top position of the client area in PDF page // coordinates. // right - Right position of the client area in PDF page // coordinates. // bottom - Bottom position of the client area in PDF page // coordinates. // Return Value: // None. // Comments: // All positions are measured in PDF "user space". // Implementation should call FPDF_RenderPageBitmap() for repainting // the specified page area. void (*FFI_Invalidate)(struct _FPDF_FORMFILLINFO* pThis, FPDF_PAGE page, double left, double top, double right, double bottom); // Method: FFI_OutputSelectedRect // When the user selects text in form fields with the mouse, this // callback function will be invoked with the selected areas. // Interface Version: // 1 // Implementation Required: // No // Parameters: // pThis - Pointer to the interface structure itself. // page - Handle to the page. Returned by FPDF_LoadPage()/ // left - Left position of the client area in PDF page // coordinates. // top - Top position of the client area in PDF page // coordinates. // right - Right position of the client area in PDF page // coordinates. // bottom - Bottom position of the client area in PDF page // coordinates. // Return Value: // None. // Comments: // This callback function is useful for implementing special text // selection effects. An implementation should first record the // returned rectangles, then draw them one by one during the next // painting period. Lastly, it should remove all the recorded // rectangles when finished painting. void (*FFI_OutputSelectedRect)(struct _FPDF_FORMFILLINFO* pThis, FPDF_PAGE page, double left, double top, double right, double bottom); // Method: FFI_SetCursor // Set the Cursor shape. // Interface Version: // 1 // Implementation Required: // yes // Parameters: // pThis - Pointer to the interface structure itself. // nCursorType - Cursor type, see Flags for Cursor type for details. // Return value: // None. void (*FFI_SetCursor)(struct _FPDF_FORMFILLINFO* pThis, int nCursorType); // Method: FFI_SetTimer // This method installs a system timer. An interval value is specified, // and every time that interval elapses, the system must call into the // callback function with the timer ID as returned by this function. // Interface Version: // 1 // Implementation Required: // yes // Parameters: // pThis - Pointer to the interface structure itself. // uElapse - Specifies the time-out value, in milliseconds. // lpTimerFunc - A pointer to the callback function-TimerCallback. // Return value: // The timer identifier of the new timer if the function is successful. // An application passes this value to the FFI_KillTimer method to kill // the timer. Nonzero if it is successful; otherwise, it is zero. int (*FFI_SetTimer)(struct _FPDF_FORMFILLINFO* pThis, int uElapse, TimerCallback lpTimerFunc); // Method: FFI_KillTimer // This method uninstalls a system timer, as set by an earlier call to // FFI_SetTimer. // Interface Version: // 1 // Implementation Required: // yes // Parameters: // pThis - Pointer to the interface structure itself. // nTimerID - The timer ID returned by FFI_SetTimer function. // Return value: // None. void (*FFI_KillTimer)(struct _FPDF_FORMFILLINFO* pThis, int nTimerID); // Method: FFI_GetLocalTime // This method receives the current local time on the system. // Interface Version: // 1 // Implementation Required: // yes // Parameters: // pThis - Pointer to the interface structure itself. // Return value: // The local time. See FPDF_SYSTEMTIME above for details. // Note: Unused. FPDF_SYSTEMTIME (*FFI_GetLocalTime)(struct _FPDF_FORMFILLINFO* pThis); // Method: FFI_OnChange // This method will be invoked to notify the implementation when the // value of any FormField on the document had been changed. // Interface Version: // 1 // Implementation Required: // no // Parameters: // pThis - Pointer to the interface structure itself. // Return value: // None. void (*FFI_OnChange)(struct _FPDF_FORMFILLINFO* pThis); // Method: FFI_GetPage // This method receives the page handle associated with a specified // page index. // Interface Version: // 1 // Implementation Required: // yes // Parameters: // pThis - Pointer to the interface structure itself. // document - Handle to document. Returned by FPDF_LoadDocument(). // nPageIndex - Index number of the page. 0 for the first page. // Return value: // Handle to the page, as previously returned to the implementation by // FPDF_LoadPage(). // Comments: // The implementation is expected to keep track of the page handles it // receives from PDFium, and their mappings to page numbers. In some // cases, the document-level JavaScript action may refer to a page // which hadn't been loaded yet. To successfully run the Javascript // action, the implementation needs to load the page. FPDF_PAGE (*FFI_GetPage)(struct _FPDF_FORMFILLINFO* pThis, FPDF_DOCUMENT document, int nPageIndex); // Method: FFI_GetCurrentPage // This method receives the handle to the current page. // Interface Version: // 1 // Implementation Required: // Yes when V8 support is present, otherwise unused. // Parameters: // pThis - Pointer to the interface structure itself. // document - Handle to document. Returned by FPDF_LoadDocument(). // Return value: // Handle to the page. Returned by FPDF_LoadPage(). // Comments: // PDFium doesn't keep keep track of the "current page" (e.g. the one // that is most visible on screen), so it must ask the embedder for // this information. FPDF_PAGE (*FFI_GetCurrentPage)(struct _FPDF_FORMFILLINFO* pThis, FPDF_DOCUMENT document); // Method: FFI_GetRotation // This method receives currently rotation of the page view. // Interface Version: // 1 // Implementation Required: // yes // Parameters: // pThis - Pointer to the interface structure itself. // page - Handle to page, as returned by FPDF_LoadPage(). // Return value: // A number to indicate the page rotation in 90 degree increments // in a clockwise direction: // 0 - 0 degrees // 1 - 90 degrees // 2 - 180 degrees // 3 - 270 degrees // Note: Unused. int (*FFI_GetRotation)(struct _FPDF_FORMFILLINFO* pThis, FPDF_PAGE page); // Method: FFI_ExecuteNamedAction // This method will execute a named action. // Interface Version: // 1 // Implementation Required: // yes // Parameters: // pThis - Pointer to the interface structure itself. // namedAction - A byte string which indicates the named action, // terminated by 0. // Return value: // None. // Comments: // See ISO 32000-1:2008, section 12.6.4.11 for descriptions of the // standard named actions, but note that a document may supply any // name of its choosing. void (*FFI_ExecuteNamedAction)(struct _FPDF_FORMFILLINFO* pThis, FPDF_BYTESTRING namedAction); // Method: FFI_SetTextFieldFocus // Called when a text field is getting or losing focus. // Interface Version: // 1 // Implementation Required: // no // Parameters: // pThis - Pointer to the interface structure itself. // value - The string value of the form field, in UTF-16LE // format. // valueLen - The length of the string value. This is the // number of characters, not bytes. // is_focus - True if the form field is getting focus, false // if the form field is losing focus. // Return value: // None. // Comments: // Only supports text fields and combobox fields. void (*FFI_SetTextFieldFocus)(struct _FPDF_FORMFILLINFO* pThis, FPDF_WIDESTRING value, FPDF_DWORD valueLen, FPDF_BOOL is_focus); // Method: FFI_DoURIAction // Ask the implementation to navigate to a uniform resource identifier. // Interface Version: // 1 // Implementation Required: // No // Parameters: // pThis - Pointer to the interface structure itself. // bsURI - A byte string which indicates the uniform // resource identifier, terminated by 0. // Return value: // None. // Comments: // If the embedder is version 2 or higher and have implementation for // FFI_DoURIActionWithKeyboardModifier, then // FFI_DoURIActionWithKeyboardModifier takes precedence over // FFI_DoURIAction. // See the URI actions description of <> // for more details. void (*FFI_DoURIAction)(struct _FPDF_FORMFILLINFO* pThis, FPDF_BYTESTRING bsURI); // Method: FFI_DoGoToAction // This action changes the view to a specified destination. // Interface Version: // 1 // Implementation Required: // No // Parameters: // pThis - Pointer to the interface structure itself. // nPageIndex - The index of the PDF page. // zoomMode - The zoom mode for viewing page. See below. // fPosArray - The float array which carries the position info. // sizeofArray - The size of float array. // PDFZoom values: // - XYZ = 1 // - FITPAGE = 2 // - FITHORZ = 3 // - FITVERT = 4 // - FITRECT = 5 // - FITBBOX = 6 // - FITBHORZ = 7 // - FITBVERT = 8 // Return value: // None. // Comments: // See the Destinations description of <> // in 8.2.1 for more details. void (*FFI_DoGoToAction)(struct _FPDF_FORMFILLINFO* pThis, int nPageIndex, int zoomMode, float* fPosArray, int sizeofArray); // Pointer to IPDF_JSPLATFORM interface. // Unused if PDFium is built without V8 support. Otherwise, if NULL, then // JavaScript will be prevented from executing while rendering the document. IPDF_JSPLATFORM* m_pJsPlatform; // Version 2 - Experimental. // Whether the XFA module is disabled when built with the XFA module. // Interface Version: // Ignored if |version| < 2. FPDF_BOOL xfa_disabled; // Method: FFI_DisplayCaret // This method will show the caret at specified position. // Interface Version: // Ignored if |version| < 2. // Implementation Required: // Required for XFA, otherwise set to NULL. // Parameters: // pThis - Pointer to the interface structure itself. // page - Handle to page. Returned by FPDF_LoadPage(). // left - Left position of the client area in PDF page // coordinates. // top - Top position of the client area in PDF page // coordinates. // right - Right position of the client area in PDF page // coordinates. // bottom - Bottom position of the client area in PDF page // coordinates. // Return value: // None. void (*FFI_DisplayCaret)(struct _FPDF_FORMFILLINFO* pThis, FPDF_PAGE page, FPDF_BOOL bVisible, double left, double top, double right, double bottom); // Method: FFI_GetCurrentPageIndex // This method will get the current page index. // Interface Version: // Ignored if |version| < 2. // Implementation Required: // Required for XFA, otherwise set to NULL. // Parameters: // pThis - Pointer to the interface structure itself. // document - Handle to document from FPDF_LoadDocument(). // Return value: // The index of current page. int (*FFI_GetCurrentPageIndex)(struct _FPDF_FORMFILLINFO* pThis, FPDF_DOCUMENT document); // Method: FFI_SetCurrentPage // This method will set the current page. // Interface Version: // Ignored if |version| < 2. // Implementation Required: // Required for XFA, otherwise set to NULL. // Parameters: // pThis - Pointer to the interface structure itself. // document - Handle to document from FPDF_LoadDocument(). // iCurPage - The index of the PDF page. // Return value: // None. void (*FFI_SetCurrentPage)(struct _FPDF_FORMFILLINFO* pThis, FPDF_DOCUMENT document, int iCurPage); // Method: FFI_GotoURL // This method will navigate to the specified URL. // Interface Version: // Ignored if |version| < 2. // Implementation Required: // Required for XFA, otherwise set to NULL. // Parameters: // pThis - Pointer to the interface structure itself. // document - Handle to document from FPDF_LoadDocument(). // wsURL - The string value of the URL, in UTF-16LE format. // Return value: // None. void (*FFI_GotoURL)(struct _FPDF_FORMFILLINFO* pThis, FPDF_DOCUMENT document, FPDF_WIDESTRING wsURL); // Method: FFI_GetPageViewRect // This method will get the current page view rectangle. // Interface Version: // Ignored if |version| < 2. // Implementation Required: // Required for XFA, otherwise set to NULL. // Parameters: // pThis - Pointer to the interface structure itself. // page - Handle to page. Returned by FPDF_LoadPage(). // left - The pointer to receive left position of the page // view area in PDF page coordinates. // top - The pointer to receive top position of the page // view area in PDF page coordinates. // right - The pointer to receive right position of the // page view area in PDF page coordinates. // bottom - The pointer to receive bottom position of the // page view area in PDF page coordinates. // Return value: // None. void (*FFI_GetPageViewRect)(struct _FPDF_FORMFILLINFO* pThis, FPDF_PAGE page, double* left, double* top, double* right, double* bottom); // Method: FFI_PageEvent // This method fires when pages have been added to or deleted from // the XFA document. // Interface Version: // Ignored if |version| < 2. // Implementation Required: // Required for XFA, otherwise set to NULL. // Parameters: // pThis - Pointer to the interface structure itself. // page_count - The number of pages to be added or deleted. // event_type - See FXFA_PAGEVIEWEVENT_* above. // Return value: // None. // Comments: // The pages to be added or deleted always start from the last page // of document. This means that if parameter page_count is 2 and // event type is FXFA_PAGEVIEWEVENT_POSTADDED, 2 new pages have been // appended to the tail of document; If page_count is 2 and // event type is FXFA_PAGEVIEWEVENT_POSTREMOVED, the last 2 pages // have been deleted. void (*FFI_PageEvent)(struct _FPDF_FORMFILLINFO* pThis, int page_count, FPDF_DWORD event_type); // Method: FFI_PopupMenu // This method will track the right context menu for XFA fields. // Interface Version: // Ignored if |version| < 2. // Implementation Required: // Required for XFA, otherwise set to NULL. // Parameters: // pThis - Pointer to the interface structure itself. // page - Handle to page. Returned by FPDF_LoadPage(). // hWidget - Always null, exists for compatibility. // menuFlag - The menu flags. Please refer to macro definition // of FXFA_MENU_XXX and this can be one or a // combination of these macros. // x - X position of the client area in PDF page // coordinates. // y - Y position of the client area in PDF page // coordinates. // Return value: // TRUE indicates success; otherwise false. FPDF_BOOL (*FFI_PopupMenu)(struct _FPDF_FORMFILLINFO* pThis, FPDF_PAGE page, FPDF_WIDGET hWidget, int menuFlag, float x, float y); // Method: FFI_OpenFile // This method will open the specified file with the specified mode. // Interface Version: // Ignored if |version| < 2. // Implementation Required: // Required for XFA, otherwise set to NULL. // Parameters: // pThis - Pointer to the interface structure itself. // fileFlag - The file flag. Please refer to macro definition // of FXFA_SAVEAS_XXX and use one of these macros. // wsURL - The string value of the file URL, in UTF-16LE // format. // mode - The mode for open file, e.g. "rb" or "wb". // Return value: // The handle to FPDF_FILEHANDLER. FPDF_FILEHANDLER* (*FFI_OpenFile)(struct _FPDF_FORMFILLINFO* pThis, int fileFlag, FPDF_WIDESTRING wsURL, const char* mode); // Method: FFI_EmailTo // This method will email the specified file stream to the specified // contact. // Interface Version: // Ignored if |version| < 2. // Implementation Required: // Required for XFA, otherwise set to NULL. // Parameters: // pThis - Pointer to the interface structure itself. // pFileHandler - Handle to the FPDF_FILEHANDLER. // pTo - A semicolon-delimited list of recipients for the // message,in UTF-16LE format. // pSubject - The subject of the message,in UTF-16LE format. // pCC - A semicolon-delimited list of CC recipients for // the message,in UTF-16LE format. // pBcc - A semicolon-delimited list of BCC recipients for // the message,in UTF-16LE format. // pMsg - Pointer to the data buffer to be sent.Can be // NULL,in UTF-16LE format. // Return value: // None. void (*FFI_EmailTo)(struct _FPDF_FORMFILLINFO* pThis, FPDF_FILEHANDLER* fileHandler, FPDF_WIDESTRING pTo, FPDF_WIDESTRING pSubject, FPDF_WIDESTRING pCC, FPDF_WIDESTRING pBcc, FPDF_WIDESTRING pMsg); // Method: FFI_UploadTo // This method will upload the specified file stream to the // specified URL. // Interface Version: // Ignored if |version| < 2. // Implementation Required: // Required for XFA, otherwise set to NULL. // Parameters: // pThis - Pointer to the interface structure itself. // pFileHandler - Handle to the FPDF_FILEHANDLER. // fileFlag - The file flag. Please refer to macro definition // of FXFA_SAVEAS_XXX and use one of these macros. // uploadTo - Pointer to the URL path, in UTF-16LE format. // Return value: // None. void (*FFI_UploadTo)(struct _FPDF_FORMFILLINFO* pThis, FPDF_FILEHANDLER* fileHandler, int fileFlag, FPDF_WIDESTRING uploadTo); // Method: FFI_GetPlatform // This method will get the current platform. // Interface Version: // Ignored if |version| < 2. // Implementation Required: // Required for XFA, otherwise set to NULL. // Parameters: // pThis - Pointer to the interface structure itself. // platform - Pointer to the data buffer to receive the // platform,in UTF-16LE format. Can be NULL. // length - The length of the buffer in bytes. Can be // 0 to query the required size. // Return value: // The length of the buffer, number of bytes. int (*FFI_GetPlatform)(struct _FPDF_FORMFILLINFO* pThis, void* platform, int length); // Method: FFI_GetLanguage // This method will get the current language. // Interface Version: // Ignored if |version| < 2. // Implementation Required: // Required for XFA, otherwise set to NULL. // Parameters: // pThis - Pointer to the interface structure itself. // language - Pointer to the data buffer to receive the // current language. Can be NULL. // length - The length of the buffer in bytes. Can be // 0 to query the required size. // Return value: // The length of the buffer, number of bytes. int (*FFI_GetLanguage)(struct _FPDF_FORMFILLINFO* pThis, void* language, int length); // Method: FFI_DownloadFromURL // This method will download the specified file from the URL. // Interface Version: // Ignored if |version| < 2. // Implementation Required: // Required for XFA, otherwise set to NULL. // Parameters: // pThis - Pointer to the interface structure itself. // URL - The string value of the file URL, in UTF-16LE // format. // Return value: // The handle to FPDF_FILEHANDLER. FPDF_FILEHANDLER* (*FFI_DownloadFromURL)(struct _FPDF_FORMFILLINFO* pThis, FPDF_WIDESTRING URL); // Method: FFI_PostRequestURL // This method will post the request to the server URL. // Interface Version: // Ignored if |version| < 2. // Implementation Required: // Required for XFA, otherwise set to NULL. // Parameters: // pThis - Pointer to the interface structure itself. // wsURL - The string value of the server URL, in UTF-16LE // format. // wsData - The post data,in UTF-16LE format. // wsContentType - The content type of the request data, in // UTF-16LE format. // wsEncode - The encode type, in UTF-16LE format. // wsHeader - The request header,in UTF-16LE format. // response - Pointer to the FPDF_BSTR to receive the response // data from the server, in UTF-16LE format. // Return value: // TRUE indicates success, otherwise FALSE. FPDF_BOOL (*FFI_PostRequestURL)(struct _FPDF_FORMFILLINFO* pThis, FPDF_WIDESTRING wsURL, FPDF_WIDESTRING wsData, FPDF_WIDESTRING wsContentType, FPDF_WIDESTRING wsEncode, FPDF_WIDESTRING wsHeader, FPDF_BSTR* response); // Method: FFI_PutRequestURL // This method will put the request to the server URL. // Interface Version: // Ignored if |version| < 2. // Implementation Required: // Required for XFA, otherwise set to NULL. // Parameters: // pThis - Pointer to the interface structure itself. // wsURL - The string value of the server URL, in UTF-16LE // format. // wsData - The put data, in UTF-16LE format. // wsEncode - The encode type, in UTR-16LE format. // Return value: // TRUE indicates success, otherwise FALSE. FPDF_BOOL (*FFI_PutRequestURL)(struct _FPDF_FORMFILLINFO* pThis, FPDF_WIDESTRING wsURL, FPDF_WIDESTRING wsData, FPDF_WIDESTRING wsEncode); // Method: FFI_OnFocusChange // Called when the focused annotation is updated. // Interface Version: // Ignored if |version| < 2. // Implementation Required: // No // Parameters: // param - Pointer to the interface structure itself. // annot - The focused annotation. // page_index - Index number of the page which contains the // focused annotation. 0 for the first page. // Return value: // None. // Comments: // This callback function is useful for implementing any view based // action such as scrolling the annotation rect into view. The // embedder should not copy and store the annot as its scope is // limited to this call only. void (*FFI_OnFocusChange)(struct _FPDF_FORMFILLINFO* param, FPDF_ANNOTATION annot, int page_index); // Method: FFI_DoURIActionWithKeyboardModifier // Ask the implementation to navigate to a uniform resource identifier // with the specified modifiers. // Interface Version: // Ignored if |version| < 2. // Implementation Required: // No // Parameters: // param - Pointer to the interface structure itself. // uri - A byte string which indicates the uniform // resource identifier, terminated by 0. // modifiers - Keyboard modifier that indicates which of // the virtual keys are down, if any. // Return value: // None. // Comments: // If the embedder who is version 2 and does not implement this API, // then a call will be redirected to FFI_DoURIAction. // See the URI actions description of <> // for more details. void(*FFI_DoURIActionWithKeyboardModifier)(struct _FPDF_FORMFILLINFO* param, FPDF_BYTESTRING uri, int modifiers); } FPDF_FORMFILLINFO; // Function: FPDFDOC_InitFormFillEnvironment // Initialize form fill environment. // Parameters: // document - Handle to document from FPDF_LoadDocument(). // formInfo - Pointer to a FPDF_FORMFILLINFO structure. // Return Value: // Handle to the form fill module, or NULL on failure. // Comments: // This function should be called before any form fill operation. // The FPDF_FORMFILLINFO passed in via |formInfo| must remain valid until // the returned FPDF_FORMHANDLE is closed. FPDF_EXPORT FPDF_FORMHANDLE FPDF_CALLCONV FPDFDOC_InitFormFillEnvironment(FPDF_DOCUMENT document, FPDF_FORMFILLINFO* formInfo); // Function: FPDFDOC_ExitFormFillEnvironment // Take ownership of |hHandle| and exit form fill environment. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // Return Value: // None. // Comments: // This function is a no-op when |hHandle| is null. FPDF_EXPORT void FPDF_CALLCONV FPDFDOC_ExitFormFillEnvironment(FPDF_FORMHANDLE hHandle); // Function: FORM_OnAfterLoadPage // This method is required for implementing all the form related // functions. Should be invoked after user successfully loaded a // PDF page, and FPDFDOC_InitFormFillEnvironment() has been invoked. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // Return Value: // None. FPDF_EXPORT void FPDF_CALLCONV FORM_OnAfterLoadPage(FPDF_PAGE page, FPDF_FORMHANDLE hHandle); // Function: FORM_OnBeforeClosePage // This method is required for implementing all the form related // functions. Should be invoked before user closes the PDF page. // Parameters: // page - Handle to the page, as returned by FPDF_LoadPage(). // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // Return Value: // None. FPDF_EXPORT void FPDF_CALLCONV FORM_OnBeforeClosePage(FPDF_PAGE page, FPDF_FORMHANDLE hHandle); // Function: FORM_DoDocumentJSAction // This method is required for performing document-level JavaScript // actions. It should be invoked after the PDF document has been loaded. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // Return Value: // None. // Comments: // If there is document-level JavaScript action embedded in the // document, this method will execute the JavaScript action. Otherwise, // the method will do nothing. FPDF_EXPORT void FPDF_CALLCONV FORM_DoDocumentJSAction(FPDF_FORMHANDLE hHandle); // Function: FORM_DoDocumentOpenAction // This method is required for performing open-action when the document // is opened. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // Return Value: // None. // Comments: // This method will do nothing if there are no open-actions embedded // in the document. FPDF_EXPORT void FPDF_CALLCONV FORM_DoDocumentOpenAction(FPDF_FORMHANDLE hHandle); // Additional actions type of document: // WC, before closing document, JavaScript action. // WS, before saving document, JavaScript action. // DS, after saving document, JavaScript action. // WP, before printing document, JavaScript action. // DP, after printing document, JavaScript action. #define FPDFDOC_AACTION_WC 0x10 #define FPDFDOC_AACTION_WS 0x11 #define FPDFDOC_AACTION_DS 0x12 #define FPDFDOC_AACTION_WP 0x13 #define FPDFDOC_AACTION_DP 0x14 // Function: FORM_DoDocumentAAction // This method is required for performing the document's // additional-action. // Parameters: // hHandle - Handle to the form fill module. Returned by // FPDFDOC_InitFormFillEnvironment. // aaType - The type of the additional-actions which defined // above. // Return Value: // None. // Comments: // This method will do nothing if there is no document // additional-action corresponding to the specified |aaType|. FPDF_EXPORT void FPDF_CALLCONV FORM_DoDocumentAAction(FPDF_FORMHANDLE hHandle, int aaType); // Additional-action types of page object: // OPEN (/O) -- An action to be performed when the page is opened // CLOSE (/C) -- An action to be performed when the page is closed #define FPDFPAGE_AACTION_OPEN 0 #define FPDFPAGE_AACTION_CLOSE 1 // Function: FORM_DoPageAAction // This method is required for performing the page object's // additional-action when opened or closed. // Parameters: // page - Handle to the page, as returned by FPDF_LoadPage(). // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // aaType - The type of the page object's additional-actions // which defined above. // Return Value: // None. // Comments: // This method will do nothing if no additional-action corresponding // to the specified |aaType| exists. FPDF_EXPORT void FPDF_CALLCONV FORM_DoPageAAction(FPDF_PAGE page, FPDF_FORMHANDLE hHandle, int aaType); // Function: FORM_OnMouseMove // Call this member function when the mouse cursor moves. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page, as returned by FPDF_LoadPage(). // modifier - Indicates whether various virtual keys are down. // page_x - Specifies the x-coordinate of the cursor in PDF user // space. // page_y - Specifies the y-coordinate of the cursor in PDF user // space. // Return Value: // True indicates success; otherwise false. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnMouseMove(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, int modifier, double page_x, double page_y); // Experimental API // Function: FORM_OnMouseWheel // Call this member function when the user scrolls the mouse wheel. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page, as returned by FPDF_LoadPage(). // modifier - Indicates whether various virtual keys are down. // page_coord - Specifies the coordinates of the cursor in PDF user // space. // delta_x - Specifies the amount of wheel movement on the x-axis, // in units of platform-agnostic wheel deltas. Negative // values mean left. // delta_y - Specifies the amount of wheel movement on the y-axis, // in units of platform-agnostic wheel deltas. Negative // values mean down. // Return Value: // True indicates success; otherwise false. // Comments: // For |delta_x| and |delta_y|, the caller must normalize // platform-specific wheel deltas. e.g. On Windows, a delta value of 240 // for a WM_MOUSEWHEEL event normalizes to 2, since Windows defines // WHEEL_DELTA as 120. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnMouseWheel( FPDF_FORMHANDLE hHandle, FPDF_PAGE page, int modifier, const FS_POINTF* page_coord, int delta_x, int delta_y); // Function: FORM_OnFocus // This function focuses the form annotation at a given point. If the // annotation at the point already has focus, nothing happens. If there // is no annotation at the point, removes form focus. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page, as returned by FPDF_LoadPage(). // modifier - Indicates whether various virtual keys are down. // page_x - Specifies the x-coordinate of the cursor in PDF user // space. // page_y - Specifies the y-coordinate of the cursor in PDF user // space. // Return Value: // True if there is an annotation at the given point and it has focus. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnFocus(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, int modifier, double page_x, double page_y); // Function: FORM_OnLButtonDown // Call this member function when the user presses the left // mouse button. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page, as returned by FPDF_LoadPage(). // modifier - Indicates whether various virtual keys are down. // page_x - Specifies the x-coordinate of the cursor in PDF user // space. // page_y - Specifies the y-coordinate of the cursor in PDF user // space. // Return Value: // True indicates success; otherwise false. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnLButtonDown(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, int modifier, double page_x, double page_y); // Function: FORM_OnRButtonDown // Same as above, execpt for the right mouse button. // Comments: // At the present time, has no effect except in XFA builds, but is // included for the sake of symmetry. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnRButtonDown(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, int modifier, double page_x, double page_y); // Function: FORM_OnLButtonUp // Call this member function when the user releases the left // mouse button. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page, as returned by FPDF_LoadPage(). // modifier - Indicates whether various virtual keys are down. // page_x - Specifies the x-coordinate of the cursor in device. // page_y - Specifies the y-coordinate of the cursor in device. // Return Value: // True indicates success; otherwise false. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnLButtonUp(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, int modifier, double page_x, double page_y); // Function: FORM_OnRButtonUp // Same as above, execpt for the right mouse button. // Comments: // At the present time, has no effect except in XFA builds, but is // included for the sake of symmetry. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnRButtonUp(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, int modifier, double page_x, double page_y); // Function: FORM_OnLButtonDoubleClick // Call this member function when the user double clicks the // left mouse button. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page, as returned by FPDF_LoadPage(). // modifier - Indicates whether various virtual keys are down. // page_x - Specifies the x-coordinate of the cursor in PDF user // space. // page_y - Specifies the y-coordinate of the cursor in PDF user // space. // Return Value: // True indicates success; otherwise false. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnLButtonDoubleClick(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, int modifier, double page_x, double page_y); // Function: FORM_OnKeyDown // Call this member function when a nonsystem key is pressed. // Parameters: // hHandle - Handle to the form fill module, aseturned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page, as returned by FPDF_LoadPage(). // nKeyCode - The virtual-key code of the given key (see // fpdf_fwlevent.h for virtual key codes). // modifier - Mask of key flags (see fpdf_fwlevent.h for key // flag values). // Return Value: // True indicates success; otherwise false. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnKeyDown(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, int nKeyCode, int modifier); // Function: FORM_OnKeyUp // Call this member function when a nonsystem key is released. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page, as returned by FPDF_LoadPage(). // nKeyCode - The virtual-key code of the given key (see // fpdf_fwlevent.h for virtual key codes). // modifier - Mask of key flags (see fpdf_fwlevent.h for key // flag values). // Return Value: // True indicates success; otherwise false. // Comments: // Currently unimplemented and always returns false. PDFium reserves this // API and may implement it in the future on an as-needed basis. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnKeyUp(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, int nKeyCode, int modifier); // Function: FORM_OnChar // Call this member function when a keystroke translates to a // nonsystem character. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page, as returned by FPDF_LoadPage(). // nChar - The character code value itself. // modifier - Mask of key flags (see fpdf_fwlevent.h for key // flag values). // Return Value: // True indicates success; otherwise false. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnChar(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, int nChar, int modifier); // Experimental API // Function: FORM_GetFocusedText // Call this function to obtain the text within the current focused // field, if any. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page, as returned by FPDF_LoadPage(). // buffer - Buffer for holding the form text, encoded in // UTF-16LE. If NULL, |buffer| is not modified. // buflen - Length of |buffer| in bytes. If |buflen| is less // than the length of the form text string, |buffer| is // not modified. // Return Value: // Length in bytes for the text in the focused field. FPDF_EXPORT unsigned long FPDF_CALLCONV FORM_GetFocusedText(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, void* buffer, unsigned long buflen); // Function: FORM_GetSelectedText // Call this function to obtain selected text within a form text // field or form combobox text field. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page, as returned by FPDF_LoadPage(). // buffer - Buffer for holding the selected text, encoded in // UTF-16LE. If NULL, |buffer| is not modified. // buflen - Length of |buffer| in bytes. If |buflen| is less // than the length of the selected text string, // |buffer| is not modified. // Return Value: // Length in bytes of selected text in form text field or form combobox // text field. FPDF_EXPORT unsigned long FPDF_CALLCONV FORM_GetSelectedText(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, void* buffer, unsigned long buflen); // Experimental API // Function: FORM_ReplaceAndKeepSelection // Call this function to replace the selected text in a form // text field or user-editable form combobox text field with another // text string (which can be empty or non-empty). If there is no // selected text, this function will append the replacement text after // the current caret position. After the insertion, the inserted text // will be selected. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page, as Returned by FPDF_LoadPage(). // wsText - The text to be inserted, in UTF-16LE format. // Return Value: // None. FPDF_EXPORT void FPDF_CALLCONV FORM_ReplaceAndKeepSelection(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, FPDF_WIDESTRING wsText); // Function: FORM_ReplaceSelection // Call this function to replace the selected text in a form // text field or user-editable form combobox text field with another // text string (which can be empty or non-empty). If there is no // selected text, this function will append the replacement text after // the current caret position. After the insertion, the selection range // will be set to empty. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page, as Returned by FPDF_LoadPage(). // wsText - The text to be inserted, in UTF-16LE format. // Return Value: // None. FPDF_EXPORT void FPDF_CALLCONV FORM_ReplaceSelection(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, FPDF_WIDESTRING wsText); // Experimental API // Function: FORM_SelectAllText // Call this function to select all the text within the currently focused // form text field or form combobox text field. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page, as returned by FPDF_LoadPage(). // Return Value: // Whether the operation succeeded or not. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_SelectAllText(FPDF_FORMHANDLE hHandle, FPDF_PAGE page); // Function: FORM_CanUndo // Find out if it is possible for the current focused widget in a given // form to perform an undo operation. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page, as returned by FPDF_LoadPage(). // Return Value: // True if it is possible to undo. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_CanUndo(FPDF_FORMHANDLE hHandle, FPDF_PAGE page); // Function: FORM_CanRedo // Find out if it is possible for the current focused widget in a given // form to perform a redo operation. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page, as returned by FPDF_LoadPage(). // Return Value: // True if it is possible to redo. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_CanRedo(FPDF_FORMHANDLE hHandle, FPDF_PAGE page); // Function: FORM_Undo // Make the current focused widget perform an undo operation. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page, as returned by FPDF_LoadPage(). // Return Value: // True if the undo operation succeeded. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_Undo(FPDF_FORMHANDLE hHandle, FPDF_PAGE page); // Function: FORM_Redo // Make the current focused widget perform a redo operation. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page, as returned by FPDF_LoadPage(). // Return Value: // True if the redo operation succeeded. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_Redo(FPDF_FORMHANDLE hHandle, FPDF_PAGE page); // Function: FORM_ForceToKillFocus. // Call this member function to force to kill the focus of the form // field which has focus. If it would kill the focus of a form field, // save the value of form field if was changed by theuser. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // Return Value: // True indicates success; otherwise false. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_ForceToKillFocus(FPDF_FORMHANDLE hHandle); // Experimental API. // Function: FORM_GetFocusedAnnot. // Call this member function to get the currently focused annotation. // Parameters: // handle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // page_index - Buffer to hold the index number of the page which // contains the focused annotation. 0 for the first page. // Can't be NULL. // annot - Buffer to hold the focused annotation. Can't be NULL. // Return Value: // On success, return true and write to the out parameters. Otherwise // return false and leave the out parameters unmodified. // Comments: // Not currently supported for XFA forms - will report no focused // annotation. // Must call FPDFPage_CloseAnnot() when the annotation returned in |annot| // by this function is no longer needed. // This will return true and set |page_index| to -1 and |annot| to NULL, // if there is no focused annotation. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_GetFocusedAnnot(FPDF_FORMHANDLE handle, int* page_index, FPDF_ANNOTATION* annot); // Experimental API. // Function: FORM_SetFocusedAnnot. // Call this member function to set the currently focused annotation. // Parameters: // handle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // annot - Handle to an annotation. // Return Value: // True indicates success; otherwise false. // Comments: // |annot| can't be NULL. To kill focus, use FORM_ForceToKillFocus() // instead. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_SetFocusedAnnot(FPDF_FORMHANDLE handle, FPDF_ANNOTATION annot); // Form Field Types // The names of the defines are stable, but the specific values associated with // them are not, so do not hardcode their values. #define FPDF_FORMFIELD_UNKNOWN 0 // Unknown. #define FPDF_FORMFIELD_PUSHBUTTON 1 // push button type. #define FPDF_FORMFIELD_CHECKBOX 2 // check box type. #define FPDF_FORMFIELD_RADIOBUTTON 3 // radio button type. #define FPDF_FORMFIELD_COMBOBOX 4 // combo box type. #define FPDF_FORMFIELD_LISTBOX 5 // list box type. #define FPDF_FORMFIELD_TEXTFIELD 6 // text field type. #define FPDF_FORMFIELD_SIGNATURE 7 // text field type. #ifdef PDF_ENABLE_XFA #define FPDF_FORMFIELD_XFA 8 // Generic XFA type. #define FPDF_FORMFIELD_XFA_CHECKBOX 9 // XFA check box type. #define FPDF_FORMFIELD_XFA_COMBOBOX 10 // XFA combo box type. #define FPDF_FORMFIELD_XFA_IMAGEFIELD 11 // XFA image field type. #define FPDF_FORMFIELD_XFA_LISTBOX 12 // XFA list box type. #define FPDF_FORMFIELD_XFA_PUSHBUTTON 13 // XFA push button type. #define FPDF_FORMFIELD_XFA_SIGNATURE 14 // XFA signture field type. #define FPDF_FORMFIELD_XFA_TEXTFIELD 15 // XFA text field type. #endif // PDF_ENABLE_XFA #ifdef PDF_ENABLE_XFA #define FPDF_FORMFIELD_COUNT 16 #else // PDF_ENABLE_XFA #define FPDF_FORMFIELD_COUNT 8 #endif // PDF_ENABLE_XFA #ifdef PDF_ENABLE_XFA #define IS_XFA_FORMFIELD(type) \ (((type) == FPDF_FORMFIELD_XFA) || \ ((type) == FPDF_FORMFIELD_XFA_CHECKBOX) || \ ((type) == FPDF_FORMFIELD_XFA_COMBOBOX) || \ ((type) == FPDF_FORMFIELD_XFA_IMAGEFIELD) || \ ((type) == FPDF_FORMFIELD_XFA_LISTBOX) || \ ((type) == FPDF_FORMFIELD_XFA_PUSHBUTTON) || \ ((type) == FPDF_FORMFIELD_XFA_SIGNATURE) || \ ((type) == FPDF_FORMFIELD_XFA_TEXTFIELD)) #endif // PDF_ENABLE_XFA // Function: FPDFPage_HasFormFieldAtPoint // Get the form field type by point. // Parameters: // hHandle - Handle to the form fill module. Returned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page. Returned by FPDF_LoadPage(). // page_x - X position in PDF "user space". // page_y - Y position in PDF "user space". // Return Value: // Return the type of the form field; -1 indicates no field. // See field types above. FPDF_EXPORT int FPDF_CALLCONV FPDFPage_HasFormFieldAtPoint(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, double page_x, double page_y); // Function: FPDFPage_FormFieldZOrderAtPoint // Get the form field z-order by point. // Parameters: // hHandle - Handle to the form fill module. Returned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page. Returned by FPDF_LoadPage(). // page_x - X position in PDF "user space". // page_y - Y position in PDF "user space". // Return Value: // Return the z-order of the form field; -1 indicates no field. // Higher numbers are closer to the front. FPDF_EXPORT int FPDF_CALLCONV FPDFPage_FormFieldZOrderAtPoint(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, double page_x, double page_y); // Function: FPDF_SetFormFieldHighlightColor // Set the highlight color of the specified (or all) form fields // in the document. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // doc - Handle to the document, as returned by // FPDF_LoadDocument(). // fieldType - A 32-bit integer indicating the type of a form // field (defined above). // color - The highlight color of the form field. Constructed by // 0xxxrrggbb. // Return Value: // None. // Comments: // When the parameter fieldType is set to FPDF_FORMFIELD_UNKNOWN, the // highlight color will be applied to all the form fields in the // document. // Please refresh the client window to show the highlight immediately // if necessary. FPDF_EXPORT void FPDF_CALLCONV FPDF_SetFormFieldHighlightColor(FPDF_FORMHANDLE hHandle, int fieldType, unsigned long color); // Function: FPDF_SetFormFieldHighlightAlpha // Set the transparency of the form field highlight color in the // document. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // doc - Handle to the document, as returaned by // FPDF_LoadDocument(). // alpha - The transparency of the form field highlight color, // between 0-255. // Return Value: // None. FPDF_EXPORT void FPDF_CALLCONV FPDF_SetFormFieldHighlightAlpha(FPDF_FORMHANDLE hHandle, unsigned char alpha); // Function: FPDF_RemoveFormFieldHighlight // Remove the form field highlight color in the document. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // Return Value: // None. // Comments: // Please refresh the client window to remove the highlight immediately // if necessary. FPDF_EXPORT void FPDF_CALLCONV FPDF_RemoveFormFieldHighlight(FPDF_FORMHANDLE hHandle); // Function: FPDF_FFLDraw // Render FormFields and popup window on a page to a device independent // bitmap. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // bitmap - Handle to the device independent bitmap (as the // output buffer). Bitmap handles can be created by // FPDFBitmap_Create(). // page - Handle to the page, as returned by FPDF_LoadPage(). // start_x - Left pixel position of the display area in the // device coordinates. // start_y - Top pixel position of the display area in the device // coordinates. // size_x - Horizontal size (in pixels) for displaying the page. // size_y - Vertical size (in pixels) for displaying the page. // rotate - Page orientation: 0 (normal), 1 (rotated 90 degrees // clockwise), 2 (rotated 180 degrees), 3 (rotated 90 // degrees counter-clockwise). // flags - 0 for normal display, or combination of flags // defined above. // Return Value: // None. // Comments: // This function is designed to render annotations that are // user-interactive, which are widget annotations (for FormFields) and // popup annotations. // With the FPDF_ANNOT flag, this function will render a popup annotation // when users mouse-hover on a non-widget annotation. Regardless of // FPDF_ANNOT flag, this function will always render widget annotations // for FormFields. // In order to implement the FormFill functions, implementation should // call this function after rendering functions, such as // FPDF_RenderPageBitmap() or FPDF_RenderPageBitmap_Start(), have // finished rendering the page contents. FPDF_EXPORT void FPDF_CALLCONV FPDF_FFLDraw(FPDF_FORMHANDLE hHandle, FPDF_BITMAP bitmap, FPDF_PAGE page, int start_x, int start_y, int size_x, int size_y, int rotate, int flags); #if defined(PDF_USE_SKIA) FPDF_EXPORT void FPDF_CALLCONV FPDF_FFLDrawSkia(FPDF_FORMHANDLE hHandle, FPDF_SKIA_CANVAS canvas, FPDF_PAGE page, int start_x, int start_y, int size_x, int size_y, int rotate, int flags); #endif // Experimental API // Function: FPDF_GetFormType // Returns the type of form contained in the PDF document. // Parameters: // document - Handle to document. // Return Value: // Integer value representing one of the FORMTYPE_ values. // Comments: // If |document| is NULL, then the return value is FORMTYPE_NONE. FPDF_EXPORT int FPDF_CALLCONV FPDF_GetFormType(FPDF_DOCUMENT document); // Experimental API // Function: FORM_SetIndexSelected // Selects/deselects the value at the given |index| of the focused // annotation. // Parameters: // hHandle - Handle to the form fill module. Returned by // FPDFDOC_InitFormFillEnvironment. // page - Handle to the page. Returned by FPDF_LoadPage // index - 0-based index of value to be set as // selected/unselected // selected - true to select, false to deselect // Return Value: // TRUE if the operation succeeded. // FALSE if the operation failed or widget is not a supported type. // Comments: // Intended for use with listbox/combobox widget types. Comboboxes // have at most a single value selected at a time which cannot be // deselected. Deselect on a combobox is a no-op that returns false. // Default implementation is a no-op that will return false for // other types. // Not currently supported for XFA forms - will return false. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_SetIndexSelected(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, int index, FPDF_BOOL selected); // Experimental API // Function: FORM_IsIndexSelected // Returns whether or not the value at |index| of the focused // annotation is currently selected. // Parameters: // hHandle - Handle to the form fill module. Returned by // FPDFDOC_InitFormFillEnvironment. // page - Handle to the page. Returned by FPDF_LoadPage // index - 0-based Index of value to check // Return Value: // TRUE if value at |index| is currently selected. // FALSE if value at |index| is not selected or widget is not a // supported type. // Comments: // Intended for use with listbox/combobox widget types. Default // implementation is a no-op that will return false for other types. // Not currently supported for XFA forms - will return false. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_IsIndexSelected(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, int index); // Function: FPDF_LoadXFA // If the document consists of XFA fields, call this method to // attempt to load XFA fields. // Parameters: // document - Handle to document from FPDF_LoadDocument(). // Return Value: // TRUE upon success, otherwise FALSE. If XFA support is not built // into PDFium, performs no action and always returns FALSE. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_LoadXFA(FPDF_DOCUMENT document); #ifdef __cplusplus } #endif #endif // PUBLIC_FPDF_FORMFILL_H_ ================================================ FILE: external/pdfium/linux-x64/include/fpdf_fwlevent.h ================================================ // Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #ifndef PUBLIC_FPDF_FWLEVENT_H_ #define PUBLIC_FPDF_FWLEVENT_H_ // NOLINTNEXTLINE(build/include) #include "fpdfview.h" #ifdef __cplusplus extern "C" { #endif // __cplusplus // Key flags. typedef enum { FWL_EVENTFLAG_ShiftKey = 1 << 0, FWL_EVENTFLAG_ControlKey = 1 << 1, FWL_EVENTFLAG_AltKey = 1 << 2, FWL_EVENTFLAG_MetaKey = 1 << 3, FWL_EVENTFLAG_KeyPad = 1 << 4, FWL_EVENTFLAG_AutoRepeat = 1 << 5, FWL_EVENTFLAG_LeftButtonDown = 1 << 6, FWL_EVENTFLAG_MiddleButtonDown = 1 << 7, FWL_EVENTFLAG_RightButtonDown = 1 << 8, } FWL_EVENTFLAG; // Virtual keycodes. typedef enum { FWL_VKEY_Back = 0x08, FWL_VKEY_Tab = 0x09, FWL_VKEY_NewLine = 0x0A, FWL_VKEY_Clear = 0x0C, FWL_VKEY_Return = 0x0D, FWL_VKEY_Shift = 0x10, FWL_VKEY_Control = 0x11, FWL_VKEY_Menu = 0x12, FWL_VKEY_Pause = 0x13, FWL_VKEY_Capital = 0x14, FWL_VKEY_Kana = 0x15, FWL_VKEY_Hangul = 0x15, FWL_VKEY_Junja = 0x17, FWL_VKEY_Final = 0x18, FWL_VKEY_Hanja = 0x19, FWL_VKEY_Kanji = 0x19, FWL_VKEY_Escape = 0x1B, FWL_VKEY_Convert = 0x1C, FWL_VKEY_NonConvert = 0x1D, FWL_VKEY_Accept = 0x1E, FWL_VKEY_ModeChange = 0x1F, FWL_VKEY_Space = 0x20, FWL_VKEY_Prior = 0x21, FWL_VKEY_Next = 0x22, FWL_VKEY_End = 0x23, FWL_VKEY_Home = 0x24, FWL_VKEY_Left = 0x25, FWL_VKEY_Up = 0x26, FWL_VKEY_Right = 0x27, FWL_VKEY_Down = 0x28, FWL_VKEY_Select = 0x29, FWL_VKEY_Print = 0x2A, FWL_VKEY_Execute = 0x2B, FWL_VKEY_Snapshot = 0x2C, FWL_VKEY_Insert = 0x2D, FWL_VKEY_Delete = 0x2E, FWL_VKEY_Help = 0x2F, FWL_VKEY_0 = 0x30, FWL_VKEY_1 = 0x31, FWL_VKEY_2 = 0x32, FWL_VKEY_3 = 0x33, FWL_VKEY_4 = 0x34, FWL_VKEY_5 = 0x35, FWL_VKEY_6 = 0x36, FWL_VKEY_7 = 0x37, FWL_VKEY_8 = 0x38, FWL_VKEY_9 = 0x39, FWL_VKEY_A = 0x41, FWL_VKEY_B = 0x42, FWL_VKEY_C = 0x43, FWL_VKEY_D = 0x44, FWL_VKEY_E = 0x45, FWL_VKEY_F = 0x46, FWL_VKEY_G = 0x47, FWL_VKEY_H = 0x48, FWL_VKEY_I = 0x49, FWL_VKEY_J = 0x4A, FWL_VKEY_K = 0x4B, FWL_VKEY_L = 0x4C, FWL_VKEY_M = 0x4D, FWL_VKEY_N = 0x4E, FWL_VKEY_O = 0x4F, FWL_VKEY_P = 0x50, FWL_VKEY_Q = 0x51, FWL_VKEY_R = 0x52, FWL_VKEY_S = 0x53, FWL_VKEY_T = 0x54, FWL_VKEY_U = 0x55, FWL_VKEY_V = 0x56, FWL_VKEY_W = 0x57, FWL_VKEY_X = 0x58, FWL_VKEY_Y = 0x59, FWL_VKEY_Z = 0x5A, FWL_VKEY_LWin = 0x5B, FWL_VKEY_Command = 0x5B, FWL_VKEY_RWin = 0x5C, FWL_VKEY_Apps = 0x5D, FWL_VKEY_Sleep = 0x5F, FWL_VKEY_NumPad0 = 0x60, FWL_VKEY_NumPad1 = 0x61, FWL_VKEY_NumPad2 = 0x62, FWL_VKEY_NumPad3 = 0x63, FWL_VKEY_NumPad4 = 0x64, FWL_VKEY_NumPad5 = 0x65, FWL_VKEY_NumPad6 = 0x66, FWL_VKEY_NumPad7 = 0x67, FWL_VKEY_NumPad8 = 0x68, FWL_VKEY_NumPad9 = 0x69, FWL_VKEY_Multiply = 0x6A, FWL_VKEY_Add = 0x6B, FWL_VKEY_Separator = 0x6C, FWL_VKEY_Subtract = 0x6D, FWL_VKEY_Decimal = 0x6E, FWL_VKEY_Divide = 0x6F, FWL_VKEY_F1 = 0x70, FWL_VKEY_F2 = 0x71, FWL_VKEY_F3 = 0x72, FWL_VKEY_F4 = 0x73, FWL_VKEY_F5 = 0x74, FWL_VKEY_F6 = 0x75, FWL_VKEY_F7 = 0x76, FWL_VKEY_F8 = 0x77, FWL_VKEY_F9 = 0x78, FWL_VKEY_F10 = 0x79, FWL_VKEY_F11 = 0x7A, FWL_VKEY_F12 = 0x7B, FWL_VKEY_F13 = 0x7C, FWL_VKEY_F14 = 0x7D, FWL_VKEY_F15 = 0x7E, FWL_VKEY_F16 = 0x7F, FWL_VKEY_F17 = 0x80, FWL_VKEY_F18 = 0x81, FWL_VKEY_F19 = 0x82, FWL_VKEY_F20 = 0x83, FWL_VKEY_F21 = 0x84, FWL_VKEY_F22 = 0x85, FWL_VKEY_F23 = 0x86, FWL_VKEY_F24 = 0x87, FWL_VKEY_NunLock = 0x90, FWL_VKEY_Scroll = 0x91, FWL_VKEY_LShift = 0xA0, FWL_VKEY_RShift = 0xA1, FWL_VKEY_LControl = 0xA2, FWL_VKEY_RControl = 0xA3, FWL_VKEY_LMenu = 0xA4, FWL_VKEY_RMenu = 0xA5, FWL_VKEY_BROWSER_Back = 0xA6, FWL_VKEY_BROWSER_Forward = 0xA7, FWL_VKEY_BROWSER_Refresh = 0xA8, FWL_VKEY_BROWSER_Stop = 0xA9, FWL_VKEY_BROWSER_Search = 0xAA, FWL_VKEY_BROWSER_Favorites = 0xAB, FWL_VKEY_BROWSER_Home = 0xAC, FWL_VKEY_VOLUME_Mute = 0xAD, FWL_VKEY_VOLUME_Down = 0xAE, FWL_VKEY_VOLUME_Up = 0xAF, FWL_VKEY_MEDIA_NEXT_Track = 0xB0, FWL_VKEY_MEDIA_PREV_Track = 0xB1, FWL_VKEY_MEDIA_Stop = 0xB2, FWL_VKEY_MEDIA_PLAY_Pause = 0xB3, FWL_VKEY_MEDIA_LAUNCH_Mail = 0xB4, FWL_VKEY_MEDIA_LAUNCH_MEDIA_Select = 0xB5, FWL_VKEY_MEDIA_LAUNCH_APP1 = 0xB6, FWL_VKEY_MEDIA_LAUNCH_APP2 = 0xB7, FWL_VKEY_OEM_1 = 0xBA, FWL_VKEY_OEM_Plus = 0xBB, FWL_VKEY_OEM_Comma = 0xBC, FWL_VKEY_OEM_Minus = 0xBD, FWL_VKEY_OEM_Period = 0xBE, FWL_VKEY_OEM_2 = 0xBF, FWL_VKEY_OEM_3 = 0xC0, FWL_VKEY_OEM_4 = 0xDB, FWL_VKEY_OEM_5 = 0xDC, FWL_VKEY_OEM_6 = 0xDD, FWL_VKEY_OEM_7 = 0xDE, FWL_VKEY_OEM_8 = 0xDF, FWL_VKEY_OEM_102 = 0xE2, FWL_VKEY_ProcessKey = 0xE5, FWL_VKEY_Packet = 0xE7, FWL_VKEY_Attn = 0xF6, FWL_VKEY_Crsel = 0xF7, FWL_VKEY_Exsel = 0xF8, FWL_VKEY_Ereof = 0xF9, FWL_VKEY_Play = 0xFA, FWL_VKEY_Zoom = 0xFB, FWL_VKEY_NoName = 0xFC, FWL_VKEY_PA1 = 0xFD, FWL_VKEY_OEM_Clear = 0xFE, FWL_VKEY_Unknown = 0, } FWL_VKEYCODE; #ifdef __cplusplus } // extern "C" #endif // __cplusplus #endif // PUBLIC_FPDF_FWLEVENT_H_ ================================================ FILE: external/pdfium/linux-x64/include/fpdf_javascript.h ================================================ // Copyright 2019 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef PUBLIC_FPDF_JAVASCRIPT_H_ #define PUBLIC_FPDF_JAVASCRIPT_H_ // NOLINTNEXTLINE(build/include) #include "fpdfview.h" #ifdef __cplusplus extern "C" { #endif // __cplusplus // Experimental API. // Get the number of JavaScript actions in |document|. // // document - handle to a document. // // Returns the number of JavaScript actions in |document| or -1 on error. FPDF_EXPORT int FPDF_CALLCONV FPDFDoc_GetJavaScriptActionCount(FPDF_DOCUMENT document); // Experimental API. // Get the JavaScript action at |index| in |document|. // // document - handle to a document. // index - the index of the requested JavaScript action. // // Returns the handle to the JavaScript action, or NULL on failure. // Caller owns the returned handle and must close it with // FPDFDoc_CloseJavaScriptAction(). FPDF_EXPORT FPDF_JAVASCRIPT_ACTION FPDF_CALLCONV FPDFDoc_GetJavaScriptAction(FPDF_DOCUMENT document, int index); // Experimental API. // Close a loaded FPDF_JAVASCRIPT_ACTION object. // javascript - Handle to a JavaScript action. FPDF_EXPORT void FPDF_CALLCONV FPDFDoc_CloseJavaScriptAction(FPDF_JAVASCRIPT_ACTION javascript); // Experimental API. // Get the name from the |javascript| handle. |buffer| is only modified if // |buflen| is longer than the length of the name. On errors, |buffer| is // unmodified and the returned length is 0. // // javascript - handle to an JavaScript action. // buffer - buffer for holding the name, encoded in UTF-16LE. // buflen - length of the buffer in bytes. // // Returns the length of the JavaScript action name in bytes. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFJavaScriptAction_GetName(FPDF_JAVASCRIPT_ACTION javascript, FPDF_WCHAR* buffer, unsigned long buflen); // Experimental API. // Get the script from the |javascript| handle. |buffer| is only modified if // |buflen| is longer than the length of the script. On errors, |buffer| is // unmodified and the returned length is 0. // // javascript - handle to an JavaScript action. // buffer - buffer for holding the name, encoded in UTF-16LE. // buflen - length of the buffer in bytes. // // Returns the length of the JavaScript action name in bytes. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFJavaScriptAction_GetScript(FPDF_JAVASCRIPT_ACTION javascript, FPDF_WCHAR* buffer, unsigned long buflen); #ifdef __cplusplus } // extern "C" #endif // __cplusplus #endif // PUBLIC_FPDF_JAVASCRIPT_H_ ================================================ FILE: external/pdfium/linux-x64/include/fpdf_ppo.h ================================================ // Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #ifndef PUBLIC_FPDF_PPO_H_ #define PUBLIC_FPDF_PPO_H_ // NOLINTNEXTLINE(build/include) #include "fpdfview.h" #ifdef __cplusplus extern "C" { #endif // Experimental API. // Import pages to a FPDF_DOCUMENT. // // dest_doc - The destination document for the pages. // src_doc - The document to be imported. // page_indices - An array of page indices to be imported. The first page is // zero. If |page_indices| is NULL, all pages from |src_doc| // are imported. // length - The length of the |page_indices| array. // index - The page index at which to insert the first imported page // into |dest_doc|. The first page is zero. // // Returns TRUE on success. Returns FALSE if any pages in |page_indices| is // invalid. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_ImportPagesByIndex(FPDF_DOCUMENT dest_doc, FPDF_DOCUMENT src_doc, const int* page_indices, unsigned long length, int index); // Import pages to a FPDF_DOCUMENT. // // dest_doc - The destination document for the pages. // src_doc - The document to be imported. // pagerange - A page range string, Such as "1,3,5-7". The first page is one. // If |pagerange| is NULL, all pages from |src_doc| are imported. // index - The page index at which to insert the first imported page into // |dest_doc|. The first page is zero. // // Returns TRUE on success. Returns FALSE if any pages in |pagerange| is // invalid or if |pagerange| cannot be read. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_ImportPages(FPDF_DOCUMENT dest_doc, FPDF_DOCUMENT src_doc, FPDF_BYTESTRING pagerange, int index); // Experimental API. // Create a new document from |src_doc|. The pages of |src_doc| will be // combined to provide |num_pages_on_x_axis x num_pages_on_y_axis| pages per // |output_doc| page. // // src_doc - The document to be imported. // output_width - The output page width in PDF "user space" units. // output_height - The output page height in PDF "user space" units. // num_pages_on_x_axis - The number of pages on X Axis. // num_pages_on_y_axis - The number of pages on Y Axis. // // Return value: // A handle to the created document, or NULL on failure. // // Comments: // number of pages per page = num_pages_on_x_axis * num_pages_on_y_axis // FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV FPDF_ImportNPagesToOne(FPDF_DOCUMENT src_doc, float output_width, float output_height, size_t num_pages_on_x_axis, size_t num_pages_on_y_axis); // Experimental API. // Create a template to generate form xobjects from |src_doc|'s page at // |src_page_index|, for use in |dest_doc|. // // Returns a handle on success, or NULL on failure. Caller owns the newly // created object. FPDF_EXPORT FPDF_XOBJECT FPDF_CALLCONV FPDF_NewXObjectFromPage(FPDF_DOCUMENT dest_doc, FPDF_DOCUMENT src_doc, int src_page_index); // Experimental API. // Close an FPDF_XOBJECT handle created by FPDF_NewXObjectFromPage(). // FPDF_PAGEOBJECTs created from the FPDF_XOBJECT handle are not affected. FPDF_EXPORT void FPDF_CALLCONV FPDF_CloseXObject(FPDF_XOBJECT xobject); // Experimental API. // Create a new form object from an FPDF_XOBJECT object. // // Returns a new form object on success, or NULL on failure. Caller owns the // newly created object. FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV FPDF_NewFormObjectFromXObject(FPDF_XOBJECT xobject); // Copy the viewer preferences from |src_doc| into |dest_doc|. // // dest_doc - Document to write the viewer preferences into. // src_doc - Document to read the viewer preferences from. // // Returns TRUE on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_CopyViewerPreferences(FPDF_DOCUMENT dest_doc, FPDF_DOCUMENT src_doc); #ifdef __cplusplus } // extern "C" #endif // __cplusplus #endif // PUBLIC_FPDF_PPO_H_ ================================================ FILE: external/pdfium/linux-x64/include/fpdf_progressive.h ================================================ // Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #ifndef PUBLIC_FPDF_PROGRESSIVE_H_ #define PUBLIC_FPDF_PROGRESSIVE_H_ // clang-format off // NOLINTNEXTLINE(build/include) #include "fpdfview.h" // Flags for progressive process status. #define FPDF_RENDER_READY 0 #define FPDF_RENDER_TOBECONTINUED 1 #define FPDF_RENDER_DONE 2 #define FPDF_RENDER_FAILED 3 #ifdef __cplusplus extern "C" { #endif // IFPDF_RENDERINFO interface. typedef struct _IFSDK_PAUSE { // Version number of the interface. Currently must be 1. int version; // Method: NeedToPauseNow // Check if we need to pause a progressive process now. // Interface Version: // 1 // Implementation Required: // yes // Parameters: // pThis - Pointer to the interface structure itself // Return Value: // Non-zero for pause now, 0 for continue. FPDF_BOOL (*NeedToPauseNow)(struct _IFSDK_PAUSE* pThis); // A user defined data pointer, used by user's application. Can be NULL. void* user; } IFSDK_PAUSE; // Experimental API. // Function: FPDF_RenderPageBitmapWithColorScheme_Start // Start to render page contents to a device independent bitmap // progressively with a specified color scheme for the content. // Parameters: // bitmap - Handle to the device independent bitmap (as the // output buffer). Bitmap handle can be created by // FPDFBitmap_Create function. // page - Handle to the page as returned by FPDF_LoadPage // function. // start_x - Left pixel position of the display area in the // bitmap coordinate. // start_y - Top pixel position of the display area in the // bitmap coordinate. // size_x - Horizontal size (in pixels) for displaying the // page. // size_y - Vertical size (in pixels) for displaying the page. // rotate - Page orientation: 0 (normal), 1 (rotated 90 // degrees clockwise), 2 (rotated 180 degrees), // 3 (rotated 90 degrees counter-clockwise). // flags - 0 for normal display, or combination of flags // defined in fpdfview.h. With FPDF_ANNOT flag, it // renders all annotations that does not require // user-interaction, which are all annotations except // widget and popup annotations. // color_scheme - Color scheme to be used in rendering the |page|. // If null, this function will work similar to // FPDF_RenderPageBitmap_Start(). // pause - The IFSDK_PAUSE interface. A callback mechanism // allowing the page rendering process. // Return value: // Rendering Status. See flags for progressive process status for the // details. FPDF_EXPORT int FPDF_CALLCONV FPDF_RenderPageBitmapWithColorScheme_Start(FPDF_BITMAP bitmap, FPDF_PAGE page, int start_x, int start_y, int size_x, int size_y, int rotate, int flags, const FPDF_COLORSCHEME* color_scheme, IFSDK_PAUSE* pause); // Function: FPDF_RenderPageBitmap_Start // Start to render page contents to a device independent bitmap // progressively. // Parameters: // bitmap - Handle to the device independent bitmap (as the // output buffer). Bitmap handle can be created by // FPDFBitmap_Create(). // page - Handle to the page, as returned by FPDF_LoadPage(). // start_x - Left pixel position of the display area in the // bitmap coordinates. // start_y - Top pixel position of the display area in the bitmap // coordinates. // size_x - Horizontal size (in pixels) for displaying the page. // size_y - Vertical size (in pixels) for displaying the page. // rotate - Page orientation: 0 (normal), 1 (rotated 90 degrees // clockwise), 2 (rotated 180 degrees), 3 (rotated 90 // degrees counter-clockwise). // flags - 0 for normal display, or combination of flags // defined in fpdfview.h. With FPDF_ANNOT flag, it // renders all annotations that does not require // user-interaction, which are all annotations except // widget and popup annotations. // pause - The IFSDK_PAUSE interface.A callback mechanism // allowing the page rendering process // Return value: // Rendering Status. See flags for progressive process status for the // details. FPDF_EXPORT int FPDF_CALLCONV FPDF_RenderPageBitmap_Start(FPDF_BITMAP bitmap, FPDF_PAGE page, int start_x, int start_y, int size_x, int size_y, int rotate, int flags, IFSDK_PAUSE* pause); // Function: FPDF_RenderPage_Continue // Continue rendering a PDF page. // Parameters: // page - Handle to the page, as returned by FPDF_LoadPage(). // pause - The IFSDK_PAUSE interface (a callback mechanism // allowing the page rendering process to be paused // before it's finished). This can be NULL if you // don't want to pause. // Return value: // The rendering status. See flags for progressive process status for // the details. FPDF_EXPORT int FPDF_CALLCONV FPDF_RenderPage_Continue(FPDF_PAGE page, IFSDK_PAUSE* pause); // Function: FPDF_RenderPage_Close // Release the resource allocate during page rendering. Need to be // called after finishing rendering or // cancel the rendering. // Parameters: // page - Handle to the page, as returned by FPDF_LoadPage(). // Return value: // None. FPDF_EXPORT void FPDF_CALLCONV FPDF_RenderPage_Close(FPDF_PAGE page); #ifdef __cplusplus } #endif #endif // PUBLIC_FPDF_PROGRESSIVE_H_ ================================================ FILE: external/pdfium/linux-x64/include/fpdf_save.h ================================================ // Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #ifndef PUBLIC_FPDF_SAVE_H_ #define PUBLIC_FPDF_SAVE_H_ // clang-format off // NOLINTNEXTLINE(build/include) #include "fpdfview.h" #ifdef __cplusplus extern "C" { #endif // Structure for custom file write typedef struct FPDF_FILEWRITE_ { // // Version number of the interface. Currently must be 1. // int version; // Method: WriteBlock // Output a block of data in your custom way. // Interface Version: // 1 // Implementation Required: // Yes // Comments: // Called by function FPDF_SaveDocument // Parameters: // self - Pointer to the structure itself // data - Pointer to a buffer to output // size - The size of the buffer. // Return value: // Should be non-zero if successful, zero for error. int (*WriteBlock)(struct FPDF_FILEWRITE_* self, const void* data, unsigned long size); } FPDF_FILEWRITE; // Flags for FPDF_SaveAsCopy(). // FPDF_INCREMENTAL and FPDF_NO_INCREMENTAL cannot be used together. #define FPDF_INCREMENTAL (1 << 0) #define FPDF_NO_INCREMENTAL (1 << 1) // Deprecated. Use FPDF_REMOVE_SECURITY instead. // TODO(crbug.com/42270430): Remove FPDF_REMOVE_SECURITY_DEPRECATED. #define FPDF_REMOVE_SECURITY_DEPRECATED 3 #define FPDF_REMOVE_SECURITY (1 << 2) // Experimental. Subsets any embedded font files for new text objects added to // the document. #define FPDF_SUBSET_NEW_FONTS (1 << 3) // Function: FPDF_SaveAsCopy // Saves the copy of specified document in custom way. // Parameters: // document - Handle to document, as returned by // FPDF_LoadDocument() or FPDF_CreateNewDocument(). // file_write - A pointer to a custom file write structure. // flags - Flags above that affect how the PDF gets saved. // Pass in 0 when there are no flags. // Return value: // TRUE for succeed, FALSE for failed. // FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_SaveAsCopy(FPDF_DOCUMENT document, FPDF_FILEWRITE* file_write, FPDF_DWORD flags); // Function: FPDF_SaveWithVersion // Same as FPDF_SaveAsCopy(), except the file version of the // saved document can be specified by the caller. // Parameters: // document - Handle to document. // file_write - A pointer to a custom file write structure. // flags - The creating flags. // file_version - The PDF file version. File version: 14 for 1.4, // 15 for 1.5, ... // Return value: // TRUE if succeed, FALSE if failed. // FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_SaveWithVersion(FPDF_DOCUMENT document, FPDF_FILEWRITE* file_write, FPDF_DWORD flags, int file_version); #ifdef __cplusplus } #endif #endif // PUBLIC_FPDF_SAVE_H_ ================================================ FILE: external/pdfium/linux-x64/include/fpdf_searchex.h ================================================ // Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #ifndef PUBLIC_FPDF_SEARCHEX_H_ #define PUBLIC_FPDF_SEARCHEX_H_ // NOLINTNEXTLINE(build/include) #include "fpdfview.h" #ifdef __cplusplus extern "C" { #endif // __cplusplus // Get the character index in |text_page| internal character list. // // text_page - a text page information structure. // nTextIndex - index of the text returned from FPDFText_GetText(). // // Returns the index of the character in internal character list. -1 for error. FPDF_EXPORT int FPDF_CALLCONV FPDFText_GetCharIndexFromTextIndex(FPDF_TEXTPAGE text_page, int nTextIndex); // Get the text index in |text_page| internal character list. // // text_page - a text page information structure. // nCharIndex - index of the character in internal character list. // // Returns the index of the text returned from FPDFText_GetText(). -1 for error. FPDF_EXPORT int FPDF_CALLCONV FPDFText_GetTextIndexFromCharIndex(FPDF_TEXTPAGE text_page, int nCharIndex); #ifdef __cplusplus } // extern "C" #endif // __cplusplus #endif // PUBLIC_FPDF_SEARCHEX_H_ ================================================ FILE: external/pdfium/linux-x64/include/fpdf_signature.h ================================================ // Copyright 2020 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef PUBLIC_FPDF_SIGNATURE_H_ #define PUBLIC_FPDF_SIGNATURE_H_ // NOLINTNEXTLINE(build/include) #include "fpdfview.h" #ifdef __cplusplus extern "C" { #endif // __cplusplus // Experimental API. // Function: FPDF_GetSignatureCount // Get total number of signatures in the document. // Parameters: // document - Handle to document. Returned by FPDF_LoadDocument(). // Return value: // Total number of signatures in the document on success, -1 on error. FPDF_EXPORT int FPDF_CALLCONV FPDF_GetSignatureCount(FPDF_DOCUMENT document); // Experimental API. // Function: FPDF_GetSignatureObject // Get the Nth signature of the document. // Parameters: // document - Handle to document. Returned by FPDF_LoadDocument(). // index - Index into the array of signatures of the document. // Return value: // Returns the handle to the signature, or NULL on failure. The caller // does not take ownership of the returned FPDF_SIGNATURE. Instead, it // remains valid until FPDF_CloseDocument() is called for the document. FPDF_EXPORT FPDF_SIGNATURE FPDF_CALLCONV FPDF_GetSignatureObject(FPDF_DOCUMENT document, int index); // Experimental API. // Function: FPDFSignatureObj_GetContents // Get the contents of a signature object. // Parameters: // signature - Handle to the signature object. Returned by // FPDF_GetSignatureObject(). // buffer - The address of a buffer that receives the contents. // length - The size, in bytes, of |buffer|. // Return value: // Returns the number of bytes in the contents on success, 0 on error. // // For public-key signatures, |buffer| is either a DER-encoded PKCS#1 binary or // a DER-encoded PKCS#7 binary. If |length| is less than the returned length, or // |buffer| is NULL, |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFSignatureObj_GetContents(FPDF_SIGNATURE signature, void* buffer, unsigned long length); // Experimental API. // Function: FPDFSignatureObj_GetByteRange // Get the byte range of a signature object. // Parameters: // signature - Handle to the signature object. Returned by // FPDF_GetSignatureObject(). // buffer - The address of a buffer that receives the // byte range. // length - The size, in ints, of |buffer|. // Return value: // Returns the number of ints in the byte range on // success, 0 on error. // // |buffer| is an array of pairs of integers (starting byte offset, // length in bytes) that describes the exact byte range for the digest // calculation. If |length| is less than the returned length, or // |buffer| is NULL, |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFSignatureObj_GetByteRange(FPDF_SIGNATURE signature, int* buffer, unsigned long length); // Experimental API. // Function: FPDFSignatureObj_GetSubFilter // Get the encoding of the value of a signature object. // Parameters: // signature - Handle to the signature object. Returned by // FPDF_GetSignatureObject(). // buffer - The address of a buffer that receives the encoding. // length - The size, in bytes, of |buffer|. // Return value: // Returns the number of bytes in the encoding name (including the // trailing NUL character) on success, 0 on error. // // The |buffer| is always encoded in 7-bit ASCII. If |length| is less than the // returned length, or |buffer| is NULL, |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFSignatureObj_GetSubFilter(FPDF_SIGNATURE signature, char* buffer, unsigned long length); // Experimental API. // Function: FPDFSignatureObj_GetReason // Get the reason (comment) of the signature object. // Parameters: // signature - Handle to the signature object. Returned by // FPDF_GetSignatureObject(). // buffer - The address of a buffer that receives the reason. // length - The size, in bytes, of |buffer|. // Return value: // Returns the number of bytes in the reason on success, 0 on error. // // Regardless of the platform, the |buffer| is always in UTF-16LE encoding. The // string is terminated by a UTF16 NUL character. If |length| is less than the // returned length, or |buffer| is NULL, |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFSignatureObj_GetReason(FPDF_SIGNATURE signature, void* buffer, unsigned long length); // Experimental API. // Function: FPDFSignatureObj_GetTime // Get the time of signing of a signature object. // Parameters: // signature - Handle to the signature object. Returned by // FPDF_GetSignatureObject(). // buffer - The address of a buffer that receives the time. // length - The size, in bytes, of |buffer|. // Return value: // Returns the number of bytes in the encoding name (including the // trailing NUL character) on success, 0 on error. // // The |buffer| is always encoded in 7-bit ASCII. If |length| is less than the // returned length, or |buffer| is NULL, |buffer| will not be modified. // // The format of time is expected to be D:YYYYMMDDHHMMSS+XX'YY', i.e. it's // percision is seconds, with timezone information. This value should be used // only when the time of signing is not available in the (PKCS#7 binary) // signature. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFSignatureObj_GetTime(FPDF_SIGNATURE signature, char* buffer, unsigned long length); // Experimental API. // Function: FPDFSignatureObj_GetDocMDPPermission // Get the DocMDP permission of a signature object. // Parameters: // signature - Handle to the signature object. Returned by // FPDF_GetSignatureObject(). // Return value: // Returns the permission (1, 2 or 3) on success, 0 on error. FPDF_EXPORT unsigned int FPDF_CALLCONV FPDFSignatureObj_GetDocMDPPermission(FPDF_SIGNATURE signature); #ifdef __cplusplus } // extern "C" #endif // __cplusplus #endif // PUBLIC_FPDF_SIGNATURE_H_ ================================================ FILE: external/pdfium/linux-x64/include/fpdf_structtree.h ================================================ // Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #ifndef PUBLIC_FPDF_STRUCTTREE_H_ #define PUBLIC_FPDF_STRUCTTREE_H_ // clang-format off // NOLINTNEXTLINE(build/include) #include "fpdfview.h" #ifdef __cplusplus extern "C" { #endif // Function: FPDF_StructTree_GetForPage // Get the structure tree for a page. // Parameters: // page - Handle to the page, as returned by FPDF_LoadPage(). // Return value: // A handle to the structure tree or NULL on error. The caller owns the // returned handle and must use FPDF_StructTree_Close() to release it. // The handle should be released before |page| gets released. FPDF_EXPORT FPDF_STRUCTTREE FPDF_CALLCONV FPDF_StructTree_GetForPage(FPDF_PAGE page); // Function: FPDF_StructTree_Close // Release a resource allocated by FPDF_StructTree_GetForPage(). // Parameters: // struct_tree - Handle to the structure tree, as returned by // FPDF_StructTree_LoadPage(). // Return value: // None. FPDF_EXPORT void FPDF_CALLCONV FPDF_StructTree_Close(FPDF_STRUCTTREE struct_tree); // Function: FPDF_StructTree_CountChildren // Count the number of children for the structure tree. // Parameters: // struct_tree - Handle to the structure tree, as returned by // FPDF_StructTree_LoadPage(). // Return value: // The number of children, or -1 on error. FPDF_EXPORT int FPDF_CALLCONV FPDF_StructTree_CountChildren(FPDF_STRUCTTREE struct_tree); // Function: FPDF_StructTree_GetChildAtIndex // Get a child in the structure tree. // Parameters: // struct_tree - Handle to the structure tree, as returned by // FPDF_StructTree_LoadPage(). // index - The index for the child, 0-based. // Return value: // The child at the n-th index or NULL on error. The caller does not // own the handle. The handle remains valid as long as |struct_tree| // remains valid. // Comments: // The |index| must be less than the FPDF_StructTree_CountChildren() // return value. FPDF_EXPORT FPDF_STRUCTELEMENT FPDF_CALLCONV FPDF_StructTree_GetChildAtIndex(FPDF_STRUCTTREE struct_tree, int index); // Function: FPDF_StructElement_GetAltText // Get the alt text for a given element. // Parameters: // struct_element - Handle to the struct element. // buffer - A buffer for output the alt text. May be NULL. // buflen - The length of the buffer, in bytes. May be 0. // Return value: // The number of bytes in the alt text, including the terminating NUL // character. The number of bytes is returned regardless of the // |buffer| and |buflen| parameters. // Comments: // Regardless of the platform, the |buffer| is always in UTF-16LE // encoding. The string is terminated by a UTF16 NUL character. If // |buflen| is less than the required length, or |buffer| is NULL, // |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_StructElement_GetAltText(FPDF_STRUCTELEMENT struct_element, void* buffer, unsigned long buflen); // Experimental API. // Function: FPDF_StructElement_GetActualText // Get the actual text for a given element. // Parameters: // struct_element - Handle to the struct element. // buffer - A buffer for output the actual text. May be NULL. // buflen - The length of the buffer, in bytes. May be 0. // Return value: // The number of bytes in the actual text, including the terminating // NUL character. The number of bytes is returned regardless of the // |buffer| and |buflen| parameters. // Comments: // Regardless of the platform, the |buffer| is always in UTF-16LE // encoding. The string is terminated by a UTF16 NUL character. If // |buflen| is less than the required length, or |buffer| is NULL, // |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_StructElement_GetActualText(FPDF_STRUCTELEMENT struct_element, void* buffer, unsigned long buflen); // Experimental API. // Function: FPDF_StructElement_GetExpansion // Get the expansion of an abbreviation or acronym for a given element. // Parameters: // struct_element - Handle to the struct element. // buffer - A buffer for output the expansion text. May be // NULL. // buflen - The length of the buffer, in bytes. May be 0. // Return value: // The number of bytes in the expansion text, including the terminating // NUL character. The number of bytes is returned regardless of the // |buffer| and |buflen| parameters. // Comments: // Regardless of the platform, the |buffer| is always in UTF-16LE // encoding. The string is terminated by a UTF16 NUL character. If // |buflen| is less than the required length, or |buffer| is NULL, // |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_StructElement_GetExpansion(FPDF_STRUCTELEMENT struct_element, void* buffer, unsigned long buflen); // Function: FPDF_StructElement_GetID // Get the ID for a given element. // Parameters: // struct_element - Handle to the struct element. // buffer - A buffer for output the ID string. May be NULL. // buflen - The length of the buffer, in bytes. May be 0. // Return value: // The number of bytes in the ID string, including the terminating NUL // character. The number of bytes is returned regardless of the // |buffer| and |buflen| parameters. // Comments: // Regardless of the platform, the |buffer| is always in UTF-16LE // encoding. The string is terminated by a UTF16 NUL character. If // |buflen| is less than the required length, or |buffer| is NULL, // |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_StructElement_GetID(FPDF_STRUCTELEMENT struct_element, void* buffer, unsigned long buflen); // Experimental API. // Function: FPDF_StructElement_GetLang // Get the case-insensitive IETF BCP 47 language code for an element. // Parameters: // struct_element - Handle to the struct element. // buffer - A buffer for output the lang string. May be NULL. // buflen - The length of the buffer, in bytes. May be 0. // Return value: // The number of bytes in the ID string, including the terminating NUL // character. The number of bytes is returned regardless of the // |buffer| and |buflen| parameters. // Comments: // Regardless of the platform, the |buffer| is always in UTF-16LE // encoding. The string is terminated by a UTF16 NUL character. If // |buflen| is less than the required length, or |buffer| is NULL, // |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_StructElement_GetLang(FPDF_STRUCTELEMENT struct_element, void* buffer, unsigned long buflen); // Experimental API. // Function: FPDF_StructElement_GetStringAttribute // Get a struct element attribute of type "name" or "string". // Parameters: // struct_element - Handle to the struct element. // attr_name - The name of the attribute to retrieve. // buffer - A buffer for output. May be NULL. // buflen - The length of the buffer, in bytes. May be 0. // Return value: // The number of bytes in the attribute value, including the // terminating NUL character. The number of bytes is returned // regardless of the |buffer| and |buflen| parameters. // Comments: // Regardless of the platform, the |buffer| is always in UTF-16LE // encoding. The string is terminated by a UTF16 NUL character. If // |buflen| is less than the required length, or |buffer| is NULL, // |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_StructElement_GetStringAttribute(FPDF_STRUCTELEMENT struct_element, FPDF_BYTESTRING attr_name, void* buffer, unsigned long buflen); // Function: FPDF_StructElement_GetMarkedContentID // Get the marked content ID for a given element. // Parameters: // struct_element - Handle to the struct element. // Return value: // The marked content ID of the element. If no ID exists, returns // -1. // Comments: // FPDF_StructElement_GetMarkedContentIdAtIndex() may be able to // extract more marked content IDs out of |struct_element|. This API // may be deprecated in the future. FPDF_EXPORT int FPDF_CALLCONV FPDF_StructElement_GetMarkedContentID(FPDF_STRUCTELEMENT struct_element); // Function: FPDF_StructElement_GetType // Get the type (/S) for a given element. // Parameters: // struct_element - Handle to the struct element. // buffer - A buffer for output. May be NULL. // buflen - The length of the buffer, in bytes. May be 0. // Return value: // The number of bytes in the type, including the terminating NUL // character. The number of bytes is returned regardless of the // |buffer| and |buflen| parameters. // Comments: // Regardless of the platform, the |buffer| is always in UTF-16LE // encoding. The string is terminated by a UTF16 NUL character. If // |buflen| is less than the required length, or |buffer| is NULL, // |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_StructElement_GetType(FPDF_STRUCTELEMENT struct_element, void* buffer, unsigned long buflen); // Experimental API. // Function: FPDF_StructElement_GetObjType // Get the object type (/Type) for a given element. // Parameters: // struct_element - Handle to the struct element. // buffer - A buffer for output. May be NULL. // buflen - The length of the buffer, in bytes. May be 0. // Return value: // The number of bytes in the object type, including the terminating // NUL character. The number of bytes is returned regardless of the // |buffer| and |buflen| parameters. // Comments: // Regardless of the platform, the |buffer| is always in UTF-16LE // encoding. The string is terminated by a UTF16 NUL character. If // |buflen| is less than the required length, or |buffer| is NULL, // |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_StructElement_GetObjType(FPDF_STRUCTELEMENT struct_element, void* buffer, unsigned long buflen); // Function: FPDF_StructElement_GetTitle // Get the title (/T) for a given element. // Parameters: // struct_element - Handle to the struct element. // buffer - A buffer for output. May be NULL. // buflen - The length of the buffer, in bytes. May be 0. // Return value: // The number of bytes in the title, including the terminating NUL // character. The number of bytes is returned regardless of the // |buffer| and |buflen| parameters. // Comments: // Regardless of the platform, the |buffer| is always in UTF-16LE // encoding. The string is terminated by a UTF16 NUL character. If // |buflen| is less than the required length, or |buffer| is NULL, // |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_StructElement_GetTitle(FPDF_STRUCTELEMENT struct_element, void* buffer, unsigned long buflen); // Function: FPDF_StructElement_CountChildren // Count the number of children for the structure element. // Parameters: // struct_element - Handle to the struct element. // Return value: // The number of children, or -1 on error. FPDF_EXPORT int FPDF_CALLCONV FPDF_StructElement_CountChildren(FPDF_STRUCTELEMENT struct_element); // Function: FPDF_StructElement_GetChildAtIndex // Get a child in the structure element. // Parameters: // struct_element - Handle to the struct element. // index - The index for the child, 0-based. // Return value: // The child at the n-th index or NULL on error. // Comments: // If the child exists but is not an element, then this function will // return NULL. This will also return NULL for out of bounds indices. // The |index| must be less than the FPDF_StructElement_CountChildren() // return value. FPDF_EXPORT FPDF_STRUCTELEMENT FPDF_CALLCONV FPDF_StructElement_GetChildAtIndex(FPDF_STRUCTELEMENT struct_element, int index); // Experimental API. // Function: FPDF_StructElement_GetChildMarkedContentID // Get the child's content id // Parameters: // struct_element - Handle to the struct element. // index - The index for the child, 0-based. // Return value: // The marked content ID of the child. If no ID exists, returns -1. // Comments: // If the child exists but is not a stream or object, then this // function will return -1. This will also return -1 for out of bounds // indices. Compared to FPDF_StructElement_GetMarkedContentIdAtIndex, // it is scoped to the current page. // The |index| must be less than the FPDF_StructElement_CountChildren() // return value. FPDF_EXPORT int FPDF_CALLCONV FPDF_StructElement_GetChildMarkedContentID(FPDF_STRUCTELEMENT struct_element, int index); // Experimental API. // Function: FPDF_StructElement_GetParent // Get the parent of the structure element. // Parameters: // struct_element - Handle to the struct element. // Return value: // The parent structure element or NULL on error. // Comments: // If structure element is StructTreeRoot, then this function will // return NULL. FPDF_EXPORT FPDF_STRUCTELEMENT FPDF_CALLCONV FPDF_StructElement_GetParent(FPDF_STRUCTELEMENT struct_element); // Function: FPDF_StructElement_GetAttributeCount // Count the number of attributes for the structure element. // Parameters: // struct_element - Handle to the struct element. // Return value: // The number of attributes, or -1 on error. FPDF_EXPORT int FPDF_CALLCONV FPDF_StructElement_GetAttributeCount(FPDF_STRUCTELEMENT struct_element); // Experimental API. // Function: FPDF_StructElement_GetAttributeAtIndex // Get an attribute object in the structure element. // Parameters: // struct_element - Handle to the struct element. // index - The index for the attribute object, 0-based. // Return value: // The attribute object at the n-th index or NULL on error. // Comments: // If the attribute object exists but is not a dict, then this // function will return NULL. This will also return NULL for out of // bounds indices. The caller does not own the handle. The handle // remains valid as long as |struct_element| remains valid. // The |index| must be less than the // FPDF_StructElement_GetAttributeCount() return value. FPDF_EXPORT FPDF_STRUCTELEMENT_ATTR FPDF_CALLCONV FPDF_StructElement_GetAttributeAtIndex(FPDF_STRUCTELEMENT struct_element, int index); // Experimental API. // Function: FPDF_StructElement_Attr_GetCount // Count the number of attributes in a structure element attribute map. // Parameters: // struct_attribute - Handle to the struct element attribute. // Return value: // The number of attributes, or -1 on error. FPDF_EXPORT int FPDF_CALLCONV FPDF_StructElement_Attr_GetCount(FPDF_STRUCTELEMENT_ATTR struct_attribute); // Experimental API. // Function: FPDF_StructElement_Attr_GetName // Get the name of an attribute in a structure element attribute map. // Parameters: // struct_attribute - Handle to the struct element attribute. // index - The index of attribute in the map. // buffer - A buffer for output. May be NULL. This is only // modified if |buflen| is longer than the length // of the key. Optional, pass null to just // retrieve the size of the buffer needed. // buflen - The length of the buffer. // out_buflen - A pointer to variable that will receive the // minimum buffer size to contain the key. Not // filled if FALSE is returned. // Return value: // TRUE if the operation was successful, FALSE otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_StructElement_Attr_GetName(FPDF_STRUCTELEMENT_ATTR struct_attribute, int index, void* buffer, unsigned long buflen, unsigned long* out_buflen); // Experimental API. // Function: FPDF_StructElement_Attr_GetValue // Get a handle to a value for an attribute in a structure element // attribute map. // Parameters: // struct_attribute - Handle to the struct element attribute. // name - The attribute name. // Return value: // Returns a handle to the value associated with the input, if any. // Returns NULL on failure. The caller does not own the handle. // The handle remains valid as long as |struct_attribute| remains // valid. FPDF_EXPORT FPDF_STRUCTELEMENT_ATTR_VALUE FPDF_CALLCONV FPDF_StructElement_Attr_GetValue(FPDF_STRUCTELEMENT_ATTR struct_attribute, FPDF_BYTESTRING name); // Experimental API. // Function: FPDF_StructElement_Attr_GetType // Get the type of an attribute in a structure element attribute map. // Parameters: // value - Handle to the value. // Return value: // Returns the type of the value, or FPDF_OBJECT_UNKNOWN in case of // failure. Note that this will never return FPDF_OBJECT_REFERENCE, as // references are always dereferenced. FPDF_EXPORT FPDF_OBJECT_TYPE FPDF_CALLCONV FPDF_StructElement_Attr_GetType(FPDF_STRUCTELEMENT_ATTR_VALUE value); // Experimental API. // Function: FPDF_StructElement_Attr_GetBooleanValue // Get the value of a boolean attribute in an attribute map as // FPDF_BOOL. FPDF_StructElement_Attr_GetType() should have returned // FPDF_OBJECT_BOOLEAN for this property. // Parameters: // value - Handle to the value. // out_value - A pointer to variable that will receive the value. Not // filled if false is returned. // Return value: // Returns TRUE if the attribute maps to a boolean value, FALSE // otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_StructElement_Attr_GetBooleanValue(FPDF_STRUCTELEMENT_ATTR_VALUE value, FPDF_BOOL* out_value); // Experimental API. // Function: FPDF_StructElement_Attr_GetNumberValue // Get the value of a number attribute in an attribute map as float. // FPDF_StructElement_Attr_GetType() should have returned // FPDF_OBJECT_NUMBER for this property. // Parameters: // value - Handle to the value. // out_value - A pointer to variable that will receive the value. Not // filled if false is returned. // Return value: // Returns TRUE if the attribute maps to a number value, FALSE // otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_StructElement_Attr_GetNumberValue(FPDF_STRUCTELEMENT_ATTR_VALUE value, float* out_value); // Experimental API. // Function: FPDF_StructElement_Attr_GetStringValue // Get the value of a string attribute in an attribute map as string. // FPDF_StructElement_Attr_GetType() should have returned // FPDF_OBJECT_STRING or FPDF_OBJECT_NAME for this property. // Parameters: // value - Handle to the value. // buffer - A buffer for holding the returned key in UTF-16LE. // This is only modified if |buflen| is longer than the // length of the key. Optional, pass null to just // retrieve the size of the buffer needed. // buflen - The length of the buffer. // out_buflen - A pointer to variable that will receive the minimum // buffer size to contain the key. Not filled if FALSE is // returned. // Return value: // Returns TRUE if the attribute maps to a string value, FALSE // otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_StructElement_Attr_GetStringValue(FPDF_STRUCTELEMENT_ATTR_VALUE value, void* buffer, unsigned long buflen, unsigned long* out_buflen); // Experimental API. // Function: FPDF_StructElement_Attr_GetBlobValue // Get the value of a blob attribute in an attribute map as string. // Parameters: // value - Handle to the value. // buffer - A buffer for holding the returned value. This is only // modified if |buflen| is at least as long as the length // of the value. Optional, pass null to just retrieve the // size of the buffer needed. // buflen - The length of the buffer. // out_buflen - A pointer to variable that will receive the minimum // buffer size to contain the key. Not filled if FALSE is // returned. // Return value: // Returns TRUE if the attribute maps to a string value, FALSE // otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_StructElement_Attr_GetBlobValue(FPDF_STRUCTELEMENT_ATTR_VALUE value, void* buffer, unsigned long buflen, unsigned long* out_buflen); // Experimental API. // Function: FPDF_StructElement_Attr_CountChildren // Count the number of children values in an attribute. // Parameters: // value - Handle to the value. // Return value: // The number of children, or -1 on error. FPDF_EXPORT int FPDF_CALLCONV FPDF_StructElement_Attr_CountChildren(FPDF_STRUCTELEMENT_ATTR_VALUE value); // Experimental API. // Function: FPDF_StructElement_Attr_GetChildAtIndex // Get a child from an attribute. // Parameters: // value - Handle to the value. // index - The index for the child, 0-based. // Return value: // The child at the n-th index or NULL on error. // Comments: // The |index| must be less than the // FPDF_StructElement_Attr_CountChildren() return value. FPDF_EXPORT FPDF_STRUCTELEMENT_ATTR_VALUE FPDF_CALLCONV FPDF_StructElement_Attr_GetChildAtIndex(FPDF_STRUCTELEMENT_ATTR_VALUE value, int index); // Experimental API. // Function: FPDF_StructElement_GetMarkedContentIdCount // Get the count of marked content ids for a given element. // Parameters: // struct_element - Handle to the struct element. // Return value: // The count of marked content ids or -1 if none exists. FPDF_EXPORT int FPDF_CALLCONV FPDF_StructElement_GetMarkedContentIdCount(FPDF_STRUCTELEMENT struct_element); // Experimental API. // Function: FPDF_StructElement_GetMarkedContentIdAtIndex // Get the marked content id at a given index for a given element. // Parameters: // struct_element - Handle to the struct element. // index - The index of the marked content id, 0-based. // Return value: // The marked content ID of the element. If no ID exists, returns // -1. // Comments: // The |index| must be less than the // FPDF_StructElement_GetMarkedContentIdCount() return value. // This will likely supersede FPDF_StructElement_GetMarkedContentID(). FPDF_EXPORT int FPDF_CALLCONV FPDF_StructElement_GetMarkedContentIdAtIndex(FPDF_STRUCTELEMENT struct_element, int index); #ifdef __cplusplus } // extern "C" #endif #endif // PUBLIC_FPDF_STRUCTTREE_H_ ================================================ FILE: external/pdfium/linux-x64/include/fpdf_sysfontinfo.h ================================================ // Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #ifndef PUBLIC_FPDF_SYSFONTINFO_H_ #define PUBLIC_FPDF_SYSFONTINFO_H_ #include // clang-format off // NOLINTNEXTLINE(build/include) #include "fpdfview.h" // Character sets for the font #define FXFONT_ANSI_CHARSET 0 #define FXFONT_DEFAULT_CHARSET 1 #define FXFONT_SYMBOL_CHARSET 2 #define FXFONT_SHIFTJIS_CHARSET 128 #define FXFONT_HANGEUL_CHARSET 129 #define FXFONT_GB2312_CHARSET 134 #define FXFONT_CHINESEBIG5_CHARSET 136 #define FXFONT_GREEK_CHARSET 161 #define FXFONT_VIETNAMESE_CHARSET 163 #define FXFONT_HEBREW_CHARSET 177 #define FXFONT_ARABIC_CHARSET 178 #define FXFONT_CYRILLIC_CHARSET 204 #define FXFONT_THAI_CHARSET 222 #define FXFONT_EASTERNEUROPEAN_CHARSET 238 // Font pitch and family flags #define FXFONT_FF_FIXEDPITCH (1 << 0) #define FXFONT_FF_ROMAN (1 << 4) #define FXFONT_FF_SCRIPT (4 << 4) // Typical weight values #define FXFONT_FW_NORMAL 400 #define FXFONT_FW_BOLD 700 // Exported Functions #ifdef __cplusplus extern "C" { #endif // Interface: FPDF_SYSFONTINFO // Interface for getting system font information and font mapping typedef struct _FPDF_SYSFONTINFO { // Version number of the interface. Currently must be 1 or 2. // Version 1: Traditional behavior - calls EnumFonts during initialization. // Version 2: Per-request behavior - skips EnumFonts, relies on MapFont. // Experimental: Subject to change based on feedback. int version; // Method: Release // Give implementation a chance to release any data after the // interface is no longer used. // Interface Version: // 1 and 2 // Implementation Required: // No // Parameters: // pThis - Pointer to the interface structure itself // Return Value: // None // Comments: // Called by PDFium during the final cleanup process. void (*Release)(struct _FPDF_SYSFONTINFO* pThis); // Method: EnumFonts // Enumerate all fonts installed on the system // Interface Version: // 1 // Implementation Required: // No // Parameters: // pThis - Pointer to the interface structure itself // pMapper - An opaque pointer to internal font mapper, used // when calling FPDF_AddInstalledFont(). // Return Value: // None // Comments: // Implementations should call FPDF_AddInstalledFont() function for // each font found. Only TrueType/OpenType and Type1 fonts are // accepted by PDFium. // NOTE: This method will not be called when version is set to 2. // Version 2 relies entirely on MapFont() for per-request matching. void (*EnumFonts)(struct _FPDF_SYSFONTINFO* pThis, void* pMapper); // Method: MapFont // Use the system font mapper to get a font handle from requested // parameters. // Interface Version: // 1 and 2 // Implementation Required: // Required if GetFont method is not implemented. // Parameters: // pThis - Pointer to the interface structure itself // weight - Weight of the requested font. 400 is normal and // 700 is bold. // bItalic - Italic option of the requested font, TRUE or // FALSE. // charset - Character set identifier for the requested font. // See above defined constants. // pitch_family - A combination of flags. See above defined // constants. // face - Typeface name. Currently use system local encoding // only. // bExact - Obsolete: this parameter is now ignored. // Return Value: // An opaque pointer for font handle, or NULL if system mapping is // not supported. // Comments: // If the system supports native font mapper (like Windows), // implementation can implement this method to get a font handle. // Otherwise, PDFium will do the mapping and then call GetFont // method. Only TrueType/OpenType and Type1 fonts are accepted // by PDFium. void* (*MapFont)(struct _FPDF_SYSFONTINFO* pThis, int weight, FPDF_BOOL bItalic, int charset, int pitch_family, const char* face, FPDF_BOOL* bExact); // Method: GetFont // Get a handle to a particular font by its internal ID // Interface Version: // 1 and 2 // Implementation Required: // Required if MapFont method is not implemented. // Return Value: // An opaque pointer for font handle. // Parameters: // pThis - Pointer to the interface structure itself // face - Typeface name in system local encoding. // Comments: // If the system mapping not supported, PDFium will do the font // mapping and use this method to get a font handle. void* (*GetFont)(struct _FPDF_SYSFONTINFO* pThis, const char* face); // Method: GetFontData // Get font data from a font // Interface Version: // 1 and 2 // Implementation Required: // Yes // Parameters: // pThis - Pointer to the interface structure itself // hFont - Font handle returned by MapFont or GetFont method // table - TrueType/OpenType table identifier (refer to // TrueType specification), or 0 for the whole file. // buffer - The buffer receiving the font data. Can be NULL if // not provided. // buf_size - Buffer size, can be zero if not provided. // Return Value: // Number of bytes needed, if buffer not provided or not large // enough, or number of bytes written into buffer otherwise. // Comments: // Can read either the full font file, or a particular // TrueType/OpenType table. unsigned long (*GetFontData)(struct _FPDF_SYSFONTINFO* pThis, void* hFont, unsigned int table, unsigned char* buffer, unsigned long buf_size); // Method: GetFaceName // Get face name from a font handle // Interface Version: // 1 and 2 // Implementation Required: // No // Parameters: // pThis - Pointer to the interface structure itself // hFont - Font handle returned by MapFont or GetFont method // buffer - The buffer receiving the face name. Can be NULL if // not provided // buf_size - Buffer size, can be zero if not provided // Return Value: // Number of bytes needed, if buffer not provided or not large // enough, or number of bytes written into buffer otherwise. unsigned long (*GetFaceName)(struct _FPDF_SYSFONTINFO* pThis, void* hFont, char* buffer, unsigned long buf_size); // Method: GetFontCharset // Get character set information for a font handle // Interface Version: // 1 and 2 // Implementation Required: // No // Parameters: // pThis - Pointer to the interface structure itself // hFont - Font handle returned by MapFont or GetFont method // Return Value: // Character set identifier. See defined constants above. int (*GetFontCharset)(struct _FPDF_SYSFONTINFO* pThis, void* hFont); // Method: DeleteFont // Delete a font handle // Interface Version: // 1 and 2 // Implementation Required: // Yes // Parameters: // pThis - Pointer to the interface structure itself // hFont - Font handle returned by MapFont or GetFont method // Return Value: // None void (*DeleteFont)(struct _FPDF_SYSFONTINFO* pThis, void* hFont); } FPDF_SYSFONTINFO; // Struct: FPDF_CharsetFontMap // Provides the name of a font to use for a given charset value. typedef struct FPDF_CharsetFontMap_ { int charset; // Character Set Enum value, see FXFONT_*_CHARSET above. const char* fontname; // Name of default font to use with that charset. } FPDF_CharsetFontMap; // Function: FPDF_GetDefaultTTFMap // Returns a pointer to the default character set to TT Font name map. The // map is an array of FPDF_CharsetFontMap structs, with its end indicated // by a { -1, NULL } entry. // Parameters: // None. // Return Value: // Pointer to the Charset Font Map. // Note: // Once FPDF_GetDefaultTTFMapCount() and FPDF_GetDefaultTTFMapEntry() are no // longer experimental, this API will be marked as deprecated. // See https://crbug.com/348468114 FPDF_EXPORT const FPDF_CharsetFontMap* FPDF_CALLCONV FPDF_GetDefaultTTFMap(); // Experimental API. // // Function: FPDF_GetDefaultTTFMapCount // Returns the number of entries in the default character set to TT Font name // map. // Parameters: // None. // Return Value: // The number of entries in the map. FPDF_EXPORT size_t FPDF_CALLCONV FPDF_GetDefaultTTFMapCount(); // Experimental API. // // Function: FPDF_GetDefaultTTFMapEntry // Returns an entry in the default character set to TT Font name map. // Parameters: // index - The index to the entry in the map to retrieve. // Return Value: // A pointer to the entry, if it is in the map, or NULL if the index is out // of bounds. FPDF_EXPORT const FPDF_CharsetFontMap* FPDF_CALLCONV FPDF_GetDefaultTTFMapEntry(size_t index); // Function: FPDF_AddInstalledFont // Add a system font to the list in PDFium. // Comments: // This function is only called during the system font list building // process. // Parameters: // mapper - Opaque pointer to Foxit font mapper // face - The font face name // charset - Font character set. See above defined constants. // Return Value: // None. FPDF_EXPORT void FPDF_CALLCONV FPDF_AddInstalledFont(void* mapper, const char* face, int charset); // Function: FPDF_SetSystemFontInfo // Set the system font info interface into PDFium // Parameters: // font_info - Pointer to a FPDF_SYSFONTINFO structure // Return Value: // None // Comments: // Platform support implementation should implement required methods of // FFDF_SYSFONTINFO interface, then call this function during PDFium // initialization process. // // Call this with NULL to tell PDFium to stop using a previously set // |FPDF_SYSFONTINFO|. FPDF_EXPORT void FPDF_CALLCONV FPDF_SetSystemFontInfo(FPDF_SYSFONTINFO* font_info); // Function: FPDF_GetDefaultSystemFontInfo // Get default system font info interface for current platform // Parameters: // None // Return Value: // Pointer to a FPDF_SYSFONTINFO structure describing the default // interface, or NULL if the platform doesn't have a default interface. // Application should call FPDF_FreeDefaultSystemFontInfo to free the // returned pointer. // Comments: // For some platforms, PDFium implements a default version of system // font info interface. The default implementation can be passed to // FPDF_SetSystemFontInfo(). FPDF_EXPORT FPDF_SYSFONTINFO* FPDF_CALLCONV FPDF_GetDefaultSystemFontInfo(); // Function: FPDF_FreeDefaultSystemFontInfo // Free a default system font info interface // Parameters: // font_info - Pointer to a FPDF_SYSFONTINFO structure // Return Value: // None // Comments: // This function should be called on the output from // FPDF_GetDefaultSystemFontInfo() once it is no longer needed. FPDF_EXPORT void FPDF_CALLCONV FPDF_FreeDefaultSystemFontInfo(FPDF_SYSFONTINFO* font_info); #ifdef __cplusplus } #endif #endif // PUBLIC_FPDF_SYSFONTINFO_H_ ================================================ FILE: external/pdfium/linux-x64/include/fpdf_text.h ================================================ // Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #ifndef PUBLIC_FPDF_TEXT_H_ #define PUBLIC_FPDF_TEXT_H_ // clang-format off // NOLINTNEXTLINE(build/include) #include "fpdfview.h" // Exported Functions #ifdef __cplusplus extern "C" { #endif // Function: FPDFText_LoadPage // Prepare information about all characters in a page. // Parameters: // page - Handle to the page. Returned by FPDF_LoadPage function // (in FPDFVIEW module). // Return value: // A handle to the text page information structure. // NULL if something goes wrong. // Comments: // Application must call FPDFText_ClosePage to release the text page // information. // FPDF_EXPORT FPDF_TEXTPAGE FPDF_CALLCONV FPDFText_LoadPage(FPDF_PAGE page); // Function: FPDFText_ClosePage // Release all resources allocated for a text page information // structure. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // Return Value: // None. // FPDF_EXPORT void FPDF_CALLCONV FPDFText_ClosePage(FPDF_TEXTPAGE text_page); // Function: FPDFText_CountChars // Get number of characters in a page. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // Return value: // Number of characters in the page. Return -1 for error. // Generated characters, like additional space characters, new line // characters, are also counted. // Comments: // Characters in a page form a "stream", inside the stream, each // character has an index. // We will use the index parameters in many of FPDFTEXT functions. The // first character in the page // has an index value of zero. // FPDF_EXPORT int FPDF_CALLCONV FPDFText_CountChars(FPDF_TEXTPAGE text_page); // Function: FPDFText_GetUnicode // Get Unicode of a character in a page. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // index - Zero-based index of the character. // Return value: // The Unicode of the particular character. // If a character is not encoded in Unicode and Foxit engine can't // convert to Unicode, // the return value will be zero. // FPDF_EXPORT unsigned int FPDF_CALLCONV FPDFText_GetUnicode(FPDF_TEXTPAGE text_page, int index); // Experimental API. // Function: FPDFText_GetTextObject // Get the FPDF_PAGEOBJECT associated with a given character. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // index - Zero-based index of the character. // Return value: // The associated text object for the character at |index|, or NULL on // error. The returned text object, if non-null, is of type // |FPDF_PAGEOBJ_TEXT|. The caller does not own the returned object. // FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV FPDFText_GetTextObject(FPDF_TEXTPAGE text_page, int index); // Experimental API. // Function: FPDFText_IsGenerated // Get if a character in a page is generated by PDFium. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // index - Zero-based index of the character. // Return value: // 1 if the character is generated by PDFium. // 0 if the character is not generated by PDFium. // -1 if there was an error. // FPDF_EXPORT int FPDF_CALLCONV FPDFText_IsGenerated(FPDF_TEXTPAGE text_page, int index); // Experimental API. // Function: FPDFText_IsHyphen // Get if a character in a page is a hyphen. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // index - Zero-based index of the character. // Return value: // 1 if the character is a hyphen. // 0 if the character is not a hyphen. // -1 if there was an error. // FPDF_EXPORT int FPDF_CALLCONV FPDFText_IsHyphen(FPDF_TEXTPAGE text_page, int index); // Experimental API. // Function: FPDFText_HasUnicodeMapError // Get if a character in a page has an invalid unicode mapping. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // index - Zero-based index of the character. // Return value: // 1 if the character has an invalid unicode mapping. // 0 if the character has no known unicode mapping issues. // -1 if there was an error. // FPDF_EXPORT int FPDF_CALLCONV FPDFText_HasUnicodeMapError(FPDF_TEXTPAGE text_page, int index); // Function: FPDFText_GetFontSize // Get the font size of a particular character. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // index - Zero-based index of the character. // Return value: // The font size of the particular character, measured in points (about // 1/72 inch). This is the typographic size of the font (so called // "em size"). // FPDF_EXPORT double FPDF_CALLCONV FPDFText_GetFontSize(FPDF_TEXTPAGE text_page, int index); // Experimental API. // Function: FPDFText_GetFontInfo // Get the font name and flags of a particular character. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // index - Zero-based index of the character. // buffer - A buffer receiving the font name. // buflen - The length of |buffer| in bytes. // flags - Optional pointer to an int receiving the font flags. // These flags should be interpreted per PDF spec 1.7 // Section 5.7.1 Font Descriptor Flags. // Return value: // On success, return the length of the font name, including the // trailing NUL character, in bytes. If this length is less than or // equal to |length|, |buffer| is set to the font name, |flags| is // set to the font flags. |buffer| is in UTF-8 encoding. Return 0 on // failure. // FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFText_GetFontInfo(FPDF_TEXTPAGE text_page, int index, void* buffer, unsigned long buflen, int* flags); // Experimental API. // Function: FPDFText_GetFontWeight // Get the font weight of a particular character. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // index - Zero-based index of the character. // Return value: // On success, return the font weight of the particular character. If // |text_page| is invalid, if |index| is out of bounds, or if the // character's text object is undefined, return -1. // FPDF_EXPORT int FPDF_CALLCONV FPDFText_GetFontWeight(FPDF_TEXTPAGE text_page, int index); // Experimental API. // Function: FPDFText_GetFillColor // Get the fill color of a particular character. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // index - Zero-based index of the character. // R - Pointer to an unsigned int number receiving the // red value of the fill color. // G - Pointer to an unsigned int number receiving the // green value of the fill color. // B - Pointer to an unsigned int number receiving the // blue value of the fill color. // A - Pointer to an unsigned int number receiving the // alpha value of the fill color. // Return value: // Whether the call succeeded. If false, |R|, |G|, |B| and |A| are // unchanged. // FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFText_GetFillColor(FPDF_TEXTPAGE text_page, int index, unsigned int* R, unsigned int* G, unsigned int* B, unsigned int* A); // Experimental API. // Function: FPDFText_GetStrokeColor // Get the stroke color of a particular character. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // index - Zero-based index of the character. // R - Pointer to an unsigned int number receiving the // red value of the stroke color. // G - Pointer to an unsigned int number receiving the // green value of the stroke color. // B - Pointer to an unsigned int number receiving the // blue value of the stroke color. // A - Pointer to an unsigned int number receiving the // alpha value of the stroke color. // Return value: // Whether the call succeeded. If false, |R|, |G|, |B| and |A| are // unchanged. // FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFText_GetStrokeColor(FPDF_TEXTPAGE text_page, int index, unsigned int* R, unsigned int* G, unsigned int* B, unsigned int* A); // Experimental API. // Function: FPDFText_GetCharAngle // Get character rotation angle. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // index - Zero-based index of the character. // Return Value: // On success, return the angle value in radian. Value will always be // greater or equal to 0. If |text_page| is invalid, or if |index| is // out of bounds, then return -1. // FPDF_EXPORT float FPDF_CALLCONV FPDFText_GetCharAngle(FPDF_TEXTPAGE text_page, int index); // Function: FPDFText_GetCharBox // Get bounding box of a particular character. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // index - Zero-based index of the character. // left - Pointer to a double number receiving left position // of the character box. // right - Pointer to a double number receiving right position // of the character box. // bottom - Pointer to a double number receiving bottom position // of the character box. // top - Pointer to a double number receiving top position of // the character box. // Return Value: // On success, return TRUE and fill in |left|, |right|, |bottom|, and // |top|. If |text_page| is invalid, or if |index| is out of bounds, // then return FALSE, and the out parameters remain unmodified. // Comments: // All positions are measured in PDF "user space". // FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFText_GetCharBox(FPDF_TEXTPAGE text_page, int index, double* left, double* right, double* bottom, double* top); // Experimental API. // Function: FPDFText_GetLooseCharBox // Get a "loose" bounding box of a particular character, i.e., covering // the entire glyph bounds, without taking the actual glyph shape into // account. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // index - Zero-based index of the character. // rect - Pointer to a FS_RECTF receiving the character box. // Return Value: // On success, return TRUE and fill in |rect|. If |text_page| is // invalid, or if |index| is out of bounds, then return FALSE, and the // |rect| out parameter remains unmodified. // Comments: // All positions are measured in PDF "user space". // FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFText_GetLooseCharBox(FPDF_TEXTPAGE text_page, int index, FS_RECTF* rect); // Experimental API. // Function: FPDFText_GetMatrix // Get the effective transformation matrix for a particular character. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage(). // index - Zero-based index of the character. // matrix - Pointer to a FS_MATRIX receiving the transformation // matrix. // Return Value: // On success, return TRUE and fill in |matrix|. If |text_page| is // invalid, or if |index| is out of bounds, or if |matrix| is NULL, // then return FALSE, and |matrix| remains unmodified. // FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFText_GetMatrix(FPDF_TEXTPAGE text_page, int index, FS_MATRIX* matrix); // Function: FPDFText_GetCharOrigin // Get origin of a particular character. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // index - Zero-based index of the character. // x - Pointer to a double number receiving x coordinate of // the character origin. // y - Pointer to a double number receiving y coordinate of // the character origin. // Return Value: // Whether the call succeeded. If false, x and y are unchanged. // Comments: // All positions are measured in PDF "user space". // FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFText_GetCharOrigin(FPDF_TEXTPAGE text_page, int index, double* x, double* y); // Function: FPDFText_GetCharIndexAtPos // Get the index of a character at or nearby a certain position on the // page. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // x - X position in PDF "user space". // y - Y position in PDF "user space". // xTolerance - An x-axis tolerance value for character hit // detection, in point units. // yTolerance - A y-axis tolerance value for character hit // detection, in point units. // Return Value: // The zero-based index of the character at, or nearby the point (x,y). // If there is no character at or nearby the point, return value will // be -1. If an error occurs, -3 will be returned. // FPDF_EXPORT int FPDF_CALLCONV FPDFText_GetCharIndexAtPos(FPDF_TEXTPAGE text_page, double x, double y, double xTolerance, double yTolerance); // Function: FPDFText_GetText // Extract unicode text string from the page. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // start_index - Index for the start characters. // count - Number of UCS-2 values to be extracted. // result - A buffer (allocated by application) receiving the // extracted UCS-2 values. The buffer must be able to // hold `count` UCS-2 values plus a terminator. // Return Value: // Number of characters written into the result buffer, including the // trailing terminator. // Comments: // This function ignores characters without UCS-2 representations. // It considers all characters on the page, even those that are not // visible when the page has a cropbox. To filter out the characters // outside of the cropbox, use FPDF_GetPageBoundingBox() and // FPDFText_GetCharBox(). // FPDF_EXPORT int FPDF_CALLCONV FPDFText_GetText(FPDF_TEXTPAGE text_page, int start_index, int count, unsigned short* result); // Function: FPDFText_CountRects // Counts number of rectangular areas occupied by a segment of text, // and caches the result for subsequent FPDFText_GetRect() calls. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // start_index - Index for the start character. // count - Number of characters, or -1 for all remaining. // Return value: // Number of rectangles, 0 if text_page is null, or -1 on bad // start_index. // Comments: // This function, along with FPDFText_GetRect can be used by // applications to detect the position on the page for a text segment, // so proper areas can be highlighted. The FPDFText_* functions will // automatically merge small character boxes into bigger one if those // characters are on the same line and use same font settings. // FPDF_EXPORT int FPDF_CALLCONV FPDFText_CountRects(FPDF_TEXTPAGE text_page, int start_index, int count); // Function: FPDFText_GetRect // Get a rectangular area from the result generated by // FPDFText_CountRects. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // rect_index - Zero-based index for the rectangle. // left - Pointer to a double value receiving the rectangle // left boundary. // top - Pointer to a double value receiving the rectangle // top boundary. // right - Pointer to a double value receiving the rectangle // right boundary. // bottom - Pointer to a double value receiving the rectangle // bottom boundary. // Return Value: // On success, return TRUE and fill in |left|, |top|, |right|, and // |bottom|. If |text_page| is invalid then return FALSE, and the out // parameters remain unmodified. If |text_page| is valid but // |rect_index| is out of bounds, then return FALSE and set the out // parameters to 0. // FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFText_GetRect(FPDF_TEXTPAGE text_page, int rect_index, double* left, double* top, double* right, double* bottom); // Function: FPDFText_GetBoundedText // Extract unicode text within a rectangular boundary on the page. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // left - Left boundary. // top - Top boundary. // right - Right boundary. // bottom - Bottom boundary. // buffer - Caller-allocated buffer to receive UTF-16 values. // buflen - Number of UTF-16 values (not bytes) that `buffer` // is capable of holding. // Return Value: // If buffer is NULL or buflen is zero, return number of UTF-16 // values (not bytes) of text present within the rectangle, excluding // a terminating NUL. Generally you should pass a buffer at least one // larger than this if you want a terminating NUL, which will be // provided if space is available. Otherwise, return number of UTF-16 // values copied into the buffer, including the terminating NUL when // space for it is available. // Comment: // If the buffer is too small, as much text as will fit is copied into // it. May return a split surrogate in that case. // FPDF_EXPORT int FPDF_CALLCONV FPDFText_GetBoundedText(FPDF_TEXTPAGE text_page, double left, double top, double right, double bottom, unsigned short* buffer, int buflen); // Flags used by FPDFText_FindStart function. // // If not set, it will not match case by default. #define FPDF_MATCHCASE 0x00000001 // If not set, it will not match the whole word by default. #define FPDF_MATCHWHOLEWORD 0x00000002 // If not set, it will skip past the current match to look for the next match. #define FPDF_CONSECUTIVE 0x00000004 // Function: FPDFText_FindStart // Start a search. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // findwhat - A unicode match pattern. // flags - Option flags. // start_index - Start from this character. -1 for end of the page. // Return Value: // A handle for the search context. FPDFText_FindClose must be called // to release this handle. // FPDF_EXPORT FPDF_SCHHANDLE FPDF_CALLCONV FPDFText_FindStart(FPDF_TEXTPAGE text_page, FPDF_WIDESTRING findwhat, unsigned long flags, int start_index); // Function: FPDFText_FindNext // Search in the direction from page start to end. // Parameters: // handle - A search context handle returned by // FPDFText_FindStart. // Return Value: // Whether a match is found. // FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFText_FindNext(FPDF_SCHHANDLE handle); // Function: FPDFText_FindPrev // Search in the direction from page end to start. // Parameters: // handle - A search context handle returned by // FPDFText_FindStart. // Return Value: // Whether a match is found. // FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFText_FindPrev(FPDF_SCHHANDLE handle); // Function: FPDFText_GetSchResultIndex // Get the starting character index of the search result. // Parameters: // handle - A search context handle returned by // FPDFText_FindStart. // Return Value: // Index for the starting character. // FPDF_EXPORT int FPDF_CALLCONV FPDFText_GetSchResultIndex(FPDF_SCHHANDLE handle); // Function: FPDFText_GetSchCount // Get the number of matched characters in the search result. // Parameters: // handle - A search context handle returned by // FPDFText_FindStart. // Return Value: // Number of matched characters. // FPDF_EXPORT int FPDF_CALLCONV FPDFText_GetSchCount(FPDF_SCHHANDLE handle); // Function: FPDFText_FindClose // Release a search context. // Parameters: // handle - A search context handle returned by // FPDFText_FindStart. // Return Value: // None. // FPDF_EXPORT void FPDF_CALLCONV FPDFText_FindClose(FPDF_SCHHANDLE handle); // Function: FPDFLink_LoadWebLinks // Prepare information about weblinks in a page. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // Return Value: // A handle to the page's links information structure, or // NULL if something goes wrong. // Comments: // Weblinks are those links implicitly embedded in PDF pages. PDF also // has a type of annotation called "link" (FPDFTEXT doesn't deal with // that kind of link). FPDFTEXT weblink feature is useful for // automatically detecting links in the page contents. For example, // things like "https://www.example.com" will be detected, so // applications can allow user to click on those characters to activate // the link, even the PDF doesn't come with link annotations. // // FPDFLink_CloseWebLinks must be called to release resources. // FPDF_EXPORT FPDF_PAGELINK FPDF_CALLCONV FPDFLink_LoadWebLinks(FPDF_TEXTPAGE text_page); // Function: FPDFLink_CountWebLinks // Count number of detected web links. // Parameters: // link_page - Handle returned by FPDFLink_LoadWebLinks. // Return Value: // Number of detected web links. // FPDF_EXPORT int FPDF_CALLCONV FPDFLink_CountWebLinks(FPDF_PAGELINK link_page); // Function: FPDFLink_GetURL // Fetch the URL information for a detected web link. // Parameters: // link_page - Handle returned by FPDFLink_LoadWebLinks. // link_index - Zero-based index for the link. // buffer - A unicode buffer for the result. // buflen - Number of 16-bit code units (not bytes) for the // buffer, including an additional terminator. // Return Value: // If |buffer| is NULL or |buflen| is zero, return the number of 16-bit // code units (not bytes) needed to buffer the result (an additional // terminator is included in this count). // Otherwise, copy the result into |buffer|, truncating at |buflen| if // the result is too large to fit, and return the number of 16-bit code // units actually copied into the buffer (the additional terminator is // also included in this count). // If |link_index| does not correspond to a valid link, then the result // is an empty string. // FPDF_EXPORT int FPDF_CALLCONV FPDFLink_GetURL(FPDF_PAGELINK link_page, int link_index, unsigned short* buffer, int buflen); // Function: FPDFLink_CountRects // Count number of rectangular areas for the link. // Parameters: // link_page - Handle returned by FPDFLink_LoadWebLinks. // link_index - Zero-based index for the link. // Return Value: // Number of rectangular areas for the link. If |link_index| does // not correspond to a valid link, then 0 is returned. // FPDF_EXPORT int FPDF_CALLCONV FPDFLink_CountRects(FPDF_PAGELINK link_page, int link_index); // Function: FPDFLink_GetRect // Fetch the boundaries of a rectangle for a link. // Parameters: // link_page - Handle returned by FPDFLink_LoadWebLinks. // link_index - Zero-based index for the link. // rect_index - Zero-based index for a rectangle. // left - Pointer to a double value receiving the rectangle // left boundary. // top - Pointer to a double value receiving the rectangle // top boundary. // right - Pointer to a double value receiving the rectangle // right boundary. // bottom - Pointer to a double value receiving the rectangle // bottom boundary. // Return Value: // On success, return TRUE and fill in |left|, |top|, |right|, and // |bottom|. If |link_page| is invalid or if |link_index| does not // correspond to a valid link, then return FALSE, and the out // parameters remain unmodified. // FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFLink_GetRect(FPDF_PAGELINK link_page, int link_index, int rect_index, double* left, double* top, double* right, double* bottom); // Experimental API. // Function: FPDFLink_GetTextRange // Fetch the start char index and char count for a link. // Parameters: // link_page - Handle returned by FPDFLink_LoadWebLinks. // link_index - Zero-based index for the link. // start_char_index - pointer to int receiving the start char index // char_count - pointer to int receiving the char count // Return Value: // On success, return TRUE and fill in |start_char_index| and // |char_count|. if |link_page| is invalid or if |link_index| does // not correspond to a valid link, then return FALSE and the out // parameters remain unmodified. // FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFLink_GetTextRange(FPDF_PAGELINK link_page, int link_index, int* start_char_index, int* char_count); // Function: FPDFLink_CloseWebLinks // Release resources used by weblink feature. // Parameters: // link_page - Handle returned by FPDFLink_LoadWebLinks. // Return Value: // None. // FPDF_EXPORT void FPDF_CALLCONV FPDFLink_CloseWebLinks(FPDF_PAGELINK link_page); #ifdef __cplusplus } #endif #endif // PUBLIC_FPDF_TEXT_H_ ================================================ FILE: external/pdfium/linux-x64/include/fpdf_thumbnail.h ================================================ // Copyright 2019 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef PUBLIC_FPDF_THUMBNAIL_H_ #define PUBLIC_FPDF_THUMBNAIL_H_ #include // NOLINTNEXTLINE(build/include) #include "fpdfview.h" #ifdef __cplusplus extern "C" { #endif // Experimental API. // Gets the decoded data from the thumbnail of |page| if it exists. // This only modifies |buffer| if |buflen| less than or equal to the // size of the decoded data. Returns the size of the decoded // data or 0 if thumbnail DNE. Optional, pass null to just retrieve // the size of the buffer needed. // // page - handle to a page. // buffer - buffer for holding the decoded image data. // buflen - length of the buffer in bytes. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFPage_GetDecodedThumbnailData(FPDF_PAGE page, void* buffer, unsigned long buflen); // Experimental API. // Gets the raw data from the thumbnail of |page| if it exists. // This only modifies |buffer| if |buflen| is less than or equal to // the size of the raw data. Returns the size of the raw data or 0 // if thumbnail DNE. Optional, pass null to just retrieve the size // of the buffer needed. // // page - handle to a page. // buffer - buffer for holding the raw image data. // buflen - length of the buffer in bytes. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFPage_GetRawThumbnailData(FPDF_PAGE page, void* buffer, unsigned long buflen); // Experimental API. // Returns the thumbnail of |page| as a FPDF_BITMAP. Returns a nullptr // if unable to access the thumbnail's stream. // // page - handle to a page. FPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV FPDFPage_GetThumbnailAsBitmap(FPDF_PAGE page); #ifdef __cplusplus } #endif #endif // PUBLIC_FPDF_THUMBNAIL_H_ ================================================ FILE: external/pdfium/linux-x64/include/fpdf_transformpage.h ================================================ // Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #ifndef PUBLIC_FPDF_TRANSFORMPAGE_H_ #define PUBLIC_FPDF_TRANSFORMPAGE_H_ // NOLINTNEXTLINE(build/include) #include "fpdfview.h" #ifdef __cplusplus extern "C" { #endif // Set "MediaBox" entry to the page dictionary. // // page - Handle to a page. // left - The left of the rectangle. // bottom - The bottom of the rectangle. // right - The right of the rectangle. // top - The top of the rectangle. FPDF_EXPORT void FPDF_CALLCONV FPDFPage_SetMediaBox(FPDF_PAGE page, float left, float bottom, float right, float top); // Set "CropBox" entry to the page dictionary. // // page - Handle to a page. // left - The left of the rectangle. // bottom - The bottom of the rectangle. // right - The right of the rectangle. // top - The top of the rectangle. FPDF_EXPORT void FPDF_CALLCONV FPDFPage_SetCropBox(FPDF_PAGE page, float left, float bottom, float right, float top); // Set "BleedBox" entry to the page dictionary. // // page - Handle to a page. // left - The left of the rectangle. // bottom - The bottom of the rectangle. // right - The right of the rectangle. // top - The top of the rectangle. FPDF_EXPORT void FPDF_CALLCONV FPDFPage_SetBleedBox(FPDF_PAGE page, float left, float bottom, float right, float top); // Set "TrimBox" entry to the page dictionary. // // page - Handle to a page. // left - The left of the rectangle. // bottom - The bottom of the rectangle. // right - The right of the rectangle. // top - The top of the rectangle. FPDF_EXPORT void FPDF_CALLCONV FPDFPage_SetTrimBox(FPDF_PAGE page, float left, float bottom, float right, float top); // Set "ArtBox" entry to the page dictionary. // // page - Handle to a page. // left - The left of the rectangle. // bottom - The bottom of the rectangle. // right - The right of the rectangle. // top - The top of the rectangle. FPDF_EXPORT void FPDF_CALLCONV FPDFPage_SetArtBox(FPDF_PAGE page, float left, float bottom, float right, float top); // Get "MediaBox" entry from the page dictionary. // // page - Handle to a page. // left - Pointer to a float value receiving the left of the rectangle. // bottom - Pointer to a float value receiving the bottom of the rectangle. // right - Pointer to a float value receiving the right of the rectangle. // top - Pointer to a float value receiving the top of the rectangle. // // On success, return true and write to the out parameters. Otherwise return // false and leave the out parameters unmodified. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_GetMediaBox(FPDF_PAGE page, float* left, float* bottom, float* right, float* top); // Get "CropBox" entry from the page dictionary. // // page - Handle to a page. // left - Pointer to a float value receiving the left of the rectangle. // bottom - Pointer to a float value receiving the bottom of the rectangle. // right - Pointer to a float value receiving the right of the rectangle. // top - Pointer to a float value receiving the top of the rectangle. // // On success, return true and write to the out parameters. Otherwise return // false and leave the out parameters unmodified. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_GetCropBox(FPDF_PAGE page, float* left, float* bottom, float* right, float* top); // Get "BleedBox" entry from the page dictionary. // // page - Handle to a page. // left - Pointer to a float value receiving the left of the rectangle. // bottom - Pointer to a float value receiving the bottom of the rectangle. // right - Pointer to a float value receiving the right of the rectangle. // top - Pointer to a float value receiving the top of the rectangle. // // On success, return true and write to the out parameters. Otherwise return // false and leave the out parameters unmodified. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_GetBleedBox(FPDF_PAGE page, float* left, float* bottom, float* right, float* top); // Get "TrimBox" entry from the page dictionary. // // page - Handle to a page. // left - Pointer to a float value receiving the left of the rectangle. // bottom - Pointer to a float value receiving the bottom of the rectangle. // right - Pointer to a float value receiving the right of the rectangle. // top - Pointer to a float value receiving the top of the rectangle. // // On success, return true and write to the out parameters. Otherwise return // false and leave the out parameters unmodified. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_GetTrimBox(FPDF_PAGE page, float* left, float* bottom, float* right, float* top); // Get "ArtBox" entry from the page dictionary. // // page - Handle to a page. // left - Pointer to a float value receiving the left of the rectangle. // bottom - Pointer to a float value receiving the bottom of the rectangle. // right - Pointer to a float value receiving the right of the rectangle. // top - Pointer to a float value receiving the top of the rectangle. // // On success, return true and write to the out parameters. Otherwise return // false and leave the out parameters unmodified. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_GetArtBox(FPDF_PAGE page, float* left, float* bottom, float* right, float* top); // Apply transforms to |page|. // // If |matrix| is provided it will be applied to transform the page. // If |clipRect| is provided it will be used to clip the resulting page. // If neither |matrix| or |clipRect| are provided this method returns |false|. // Returns |true| if transforms are applied. // // This function will transform the whole page, and would take effect to all the // objects in the page. // // page - Page handle. // matrix - Transform matrix. // clipRect - Clipping rectangle. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_TransFormWithClip(FPDF_PAGE page, const FS_MATRIX* matrix, const FS_RECTF* clipRect); // Transform (scale, rotate, shear, move) the clip path of page object. // page_object - Handle to a page object. Returned by // FPDFPageObj_NewImageObj(). // // a - The coefficient "a" of the matrix. // b - The coefficient "b" of the matrix. // c - The coefficient "c" of the matrix. // d - The coefficient "d" of the matrix. // e - The coefficient "e" of the matrix. // f - The coefficient "f" of the matrix. FPDF_EXPORT void FPDF_CALLCONV FPDFPageObj_TransformClipPath(FPDF_PAGEOBJECT page_object, double a, double b, double c, double d, double e, double f); // Experimental API. // Get the clip path of the page object. // // page object - Handle to a page object. Returned by e.g. // FPDFPage_GetObject(). // // Returns the handle to the clip path, or NULL on failure. The caller does not // take ownership of the returned FPDF_CLIPPATH. Instead, it remains valid until // FPDF_ClosePage() is called for the page containing |page_object|. FPDF_EXPORT FPDF_CLIPPATH FPDF_CALLCONV FPDFPageObj_GetClipPath(FPDF_PAGEOBJECT page_object); // Experimental API. // Get number of paths inside |clip_path|. // // clip_path - handle to a clip_path. // // Returns the number of objects in |clip_path| or -1 on failure. FPDF_EXPORT int FPDF_CALLCONV FPDFClipPath_CountPaths(FPDF_CLIPPATH clip_path); // Experimental API. // Get number of segments inside one path of |clip_path|. // // clip_path - handle to a clip_path. // path_index - index into the array of paths of the clip path. // // Returns the number of segments or -1 on failure. FPDF_EXPORT int FPDF_CALLCONV FPDFClipPath_CountPathSegments(FPDF_CLIPPATH clip_path, int path_index); // Experimental API. // Get segment in one specific path of |clip_path| at index. // // clip_path - handle to a clip_path. // path_index - the index of a path. // segment_index - the index of a segment. // // Returns the handle to the segment, or NULL on failure. The caller does not // take ownership of the returned FPDF_PATHSEGMENT. Instead, it remains valid // until FPDF_ClosePage() is called for the page containing |clip_path|. FPDF_EXPORT FPDF_PATHSEGMENT FPDF_CALLCONV FPDFClipPath_GetPathSegment(FPDF_CLIPPATH clip_path, int path_index, int segment_index); // Create a new clip path, with a rectangle inserted. // // Caller takes ownership of the returned FPDF_CLIPPATH. It should be freed with // FPDF_DestroyClipPath(). // // left - The left of the clip box. // bottom - The bottom of the clip box. // right - The right of the clip box. // top - The top of the clip box. FPDF_EXPORT FPDF_CLIPPATH FPDF_CALLCONV FPDF_CreateClipPath(float left, float bottom, float right, float top); // Destroy the clip path. // // clipPath - A handle to the clip path. It will be invalid after this call. FPDF_EXPORT void FPDF_CALLCONV FPDF_DestroyClipPath(FPDF_CLIPPATH clipPath); // Clip the page content, the page content that outside the clipping region // become invisible. // // A clip path will be inserted before the page content stream or content array. // In this way, the page content will be clipped by this clip path. // // page - A page handle. // clipPath - A handle to the clip path. (Does not take ownership.) FPDF_EXPORT void FPDF_CALLCONV FPDFPage_InsertClipPath(FPDF_PAGE page, FPDF_CLIPPATH clipPath); #ifdef __cplusplus } #endif #endif // PUBLIC_FPDF_TRANSFORMPAGE_H_ ================================================ FILE: external/pdfium/linux-x64/include/fpdfview.h ================================================ // Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com // This is the main header file for embedders of PDFium. It provides APIs to // initialize the library, load documents, and render pages, amongst other // things. // // NOTE: None of the PDFium APIs are thread-safe. They expect to be called // from a single thread. Barring that, embedders are required to ensure (via // a mutex or similar) that only a single PDFium call can be made at a time. // // NOTE: External docs refer to this file as "fpdfview.h", so do not rename // despite lack of consistency with other public files. #ifndef PUBLIC_FPDFVIEW_H_ #define PUBLIC_FPDFVIEW_H_ // clang-format off #include #if defined(_WIN32) && !defined(__WINDOWS__) #include #endif #ifdef PDF_ENABLE_XFA // PDF_USE_XFA is set in confirmation that this version of PDFium can support // XFA forms as requested by the PDF_ENABLE_XFA setting. #define PDF_USE_XFA #endif // PDF_ENABLE_XFA // PDF object types #define FPDF_OBJECT_UNKNOWN 0 #define FPDF_OBJECT_BOOLEAN 1 #define FPDF_OBJECT_NUMBER 2 #define FPDF_OBJECT_STRING 3 #define FPDF_OBJECT_NAME 4 #define FPDF_OBJECT_ARRAY 5 #define FPDF_OBJECT_DICTIONARY 6 #define FPDF_OBJECT_STREAM 7 #define FPDF_OBJECT_NULLOBJ 8 #define FPDF_OBJECT_REFERENCE 9 // PDF text rendering modes typedef enum { FPDF_TEXTRENDERMODE_UNKNOWN = -1, FPDF_TEXTRENDERMODE_FILL = 0, FPDF_TEXTRENDERMODE_STROKE = 1, FPDF_TEXTRENDERMODE_FILL_STROKE = 2, FPDF_TEXTRENDERMODE_INVISIBLE = 3, FPDF_TEXTRENDERMODE_FILL_CLIP = 4, FPDF_TEXTRENDERMODE_STROKE_CLIP = 5, FPDF_TEXTRENDERMODE_FILL_STROKE_CLIP = 6, FPDF_TEXTRENDERMODE_CLIP = 7, FPDF_TEXTRENDERMODE_LAST = FPDF_TEXTRENDERMODE_CLIP, } FPDF_TEXT_RENDERMODE; // PDF types - use incomplete types (never completed) to force API type safety. typedef struct fpdf_action_t__* FPDF_ACTION; typedef struct fpdf_annotation_t__* FPDF_ANNOTATION; typedef struct fpdf_attachment_t__* FPDF_ATTACHMENT; typedef struct fpdf_avail_t__* FPDF_AVAIL; typedef struct fpdf_bitmap_t__* FPDF_BITMAP; typedef struct fpdf_bookmark_t__* FPDF_BOOKMARK; typedef struct fpdf_clippath_t__* FPDF_CLIPPATH; typedef struct fpdf_dest_t__* FPDF_DEST; typedef struct fpdf_document_t__* FPDF_DOCUMENT; typedef struct fpdf_font_t__* FPDF_FONT; typedef struct fpdf_form_handle_t__* FPDF_FORMHANDLE; typedef const struct fpdf_glyphpath_t__* FPDF_GLYPHPATH; typedef struct fpdf_javascript_action_t* FPDF_JAVASCRIPT_ACTION; typedef struct fpdf_link_t__* FPDF_LINK; typedef struct fpdf_page_t__* FPDF_PAGE; typedef struct fpdf_pagelink_t__* FPDF_PAGELINK; typedef struct fpdf_pageobject_t__* FPDF_PAGEOBJECT; // (text, path, etc.) typedef struct fpdf_pageobjectmark_t__* FPDF_PAGEOBJECTMARK; typedef const struct fpdf_pagerange_t__* FPDF_PAGERANGE; typedef const struct fpdf_pathsegment_t* FPDF_PATHSEGMENT; typedef struct fpdf_schhandle_t__* FPDF_SCHHANDLE; typedef const struct fpdf_signature_t__* FPDF_SIGNATURE; typedef void* FPDF_SKIA_CANVAS; // Passed into Skia as an SkCanvas. typedef struct fpdf_structelement_t__* FPDF_STRUCTELEMENT; typedef const struct fpdf_structelement_attr_t__* FPDF_STRUCTELEMENT_ATTR; typedef const struct fpdf_structelement_attr_value_t__* FPDF_STRUCTELEMENT_ATTR_VALUE; typedef struct fpdf_structtree_t__* FPDF_STRUCTTREE; typedef struct fpdf_textpage_t__* FPDF_TEXTPAGE; typedef struct fpdf_widget_t__* FPDF_WIDGET; typedef struct fpdf_xobject_t__* FPDF_XOBJECT; // Basic data types typedef int FPDF_BOOL; typedef int FPDF_RESULT; typedef unsigned long FPDF_DWORD; typedef float FS_FLOAT; // Duplex types typedef enum _FPDF_DUPLEXTYPE_ { DuplexUndefined = 0, Simplex, DuplexFlipShortEdge, DuplexFlipLongEdge } FPDF_DUPLEXTYPE; // String types typedef unsigned short FPDF_WCHAR; // The public PDFium API uses three types of strings: byte string, wide string // (UTF-16LE encoded), and platform dependent string. // Public PDFium API type for byte strings. typedef const char* FPDF_BYTESTRING; // The public PDFium API always uses UTF-16LE encoded wide strings, each // character uses 2 bytes (except surrogation), with the low byte first. typedef const FPDF_WCHAR* FPDF_WIDESTRING; // Structure for persisting a string beyond the duration of a callback. // Note: although represented as a char*, string may be interpreted as // a UTF-16LE formated string. Used only by XFA callbacks. typedef struct FPDF_BSTR_ { char* str; // String buffer, manipulate only with FPDF_BStr_* methods. int len; // Length of the string, in bytes. } FPDF_BSTR; // For Windows programmers: In most cases it's OK to treat FPDF_WIDESTRING as a // Windows unicode string, however, special care needs to be taken if you // expect to process Unicode larger than 0xffff. // // For Linux/Unix programmers: most compiler/library environments use 4 bytes // for a Unicode character, and you have to convert between FPDF_WIDESTRING and // system wide string by yourself. typedef const char* FPDF_STRING; // Matrix for transformation, in the form [a b c d e f], equivalent to: // | a b 0 | // | c d 0 | // | e f 1 | // // Translation is performed with [1 0 0 1 tx ty]. // Scaling is performed with [sx 0 0 sy 0 0]. // See PDF Reference 1.7, 4.2.2 Common Transformations for more. typedef struct _FS_MATRIX_ { float a; float b; float c; float d; float e; float f; } FS_MATRIX; // Rectangle area(float) in device or page coordinate system. typedef struct _FS_RECTF_ { // The x-coordinate of the left-top corner. float left; // The y-coordinate of the left-top corner. float top; // The x-coordinate of the right-bottom corner. float right; // The y-coordinate of the right-bottom corner. float bottom; } * FS_LPRECTF, FS_RECTF; // Const Pointer to FS_RECTF structure. typedef const FS_RECTF* FS_LPCRECTF; // Rectangle size. Coordinate system agnostic. typedef struct FS_SIZEF_ { float width; float height; } * FS_LPSIZEF, FS_SIZEF; // Const Pointer to FS_SIZEF structure. typedef const FS_SIZEF* FS_LPCSIZEF; // 2D Point. Coordinate system agnostic. typedef struct FS_POINTF_ { float x; float y; } * FS_LPPOINTF, FS_POINTF; // Const Pointer to FS_POINTF structure. typedef const FS_POINTF* FS_LPCPOINTF; typedef struct _FS_QUADPOINTSF { FS_FLOAT x1; FS_FLOAT y1; FS_FLOAT x2; FS_FLOAT y2; FS_FLOAT x3; FS_FLOAT y3; FS_FLOAT x4; FS_FLOAT y4; } FS_QUADPOINTSF; // Annotation enums. typedef int FPDF_ANNOTATION_SUBTYPE; typedef int FPDF_ANNOT_APPEARANCEMODE; // Dictionary value types. typedef int FPDF_OBJECT_TYPE; #if defined(WIN32) #if defined(FPDF_IMPLEMENTATION) #define FPDF_EXPORT __declspec(dllexport) #else #define FPDF_EXPORT __declspec(dllimport) #endif // defined(FPDF_IMPLEMENTATION) #else #if defined(FPDF_IMPLEMENTATION) #define FPDF_EXPORT __attribute__((visibility("default"))) #else #define FPDF_EXPORT #endif // defined(FPDF_IMPLEMENTATION) #endif // defined(WIN32) #if defined(WIN32) && defined(FPDFSDK_EXPORTS) #define FPDF_CALLCONV __stdcall #else #define FPDF_CALLCONV #endif // Exported Functions #ifdef __cplusplus extern "C" { #endif // PDF renderer types - Experimental. // Selection of 2D graphics library to use for rendering to FPDF_BITMAPs. typedef enum { // Anti-Grain Geometry - https://sourceforge.net/projects/agg/ FPDF_RENDERERTYPE_AGG = 0, // Skia - https://skia.org/ FPDF_RENDERERTYPE_SKIA = 1, } FPDF_RENDERER_TYPE; // PDF font library types - Experimental. // Selection of font backend library to use. typedef enum { // FreeType - https://freetype.org/ FPDF_FONTBACKENDTYPE_FREETYPE = 0, // Fontations - https://github.com/googlefonts/fontations/ FPDF_FONTBACKENDTYPE_FONTATIONS = 1, } FPDF_FONT_BACKEND_TYPE; // Process-wide options for initializing the library. typedef struct FPDF_LIBRARY_CONFIG_ { // Version number of the interface. Currently must be 2. // Support for version 1 will be deprecated in the future. int version; // Array of paths to scan in place of the defaults when using built-in // FXGE font loading code. The array is terminated by a NULL pointer. // The Array may be NULL itself to use the default paths. May be ignored // entirely depending upon the platform. const char** m_pUserFontPaths; // Version 2. // Pointer to the v8::Isolate to use, or NULL to force PDFium to create one. void* m_pIsolate; // The embedder data slot to use in the v8::Isolate to store PDFium's // per-isolate data. The value needs to be in the range // [0, |v8::Internals::kNumIsolateDataLots|). Note that 0 is fine for most // embedders. unsigned int m_v8EmbedderSlot; // Version 3 - Experimental. // Pointer to the V8::Platform to use. void* m_pPlatform; // Version 4 - Experimental. // Explicit specification of 2D graphics rendering library to use. // |m_RendererType| must be a valid value for |FPDF_LIBRARY_CONFIG| versions // of this level or higher, or else the initialization will fail with an // immediate crash. // Note that use of a specified |FPDF_RENDERER_TYPE| value for which the // corresponding 2D graphics rendering library is not included in the build // will similarly fail with an immediate crash. FPDF_RENDERER_TYPE m_RendererType; // Version 5 - Experimental. // Explicit specification of font library to use when |m_RendererType| is set // to |FPDF_RENDERERTYPE_SKIA|. // |m_FontLibraryType| must be a valid value for |FPDF_LIBRARY_CONFIG| // versions of this level or higher, or else the initialization will fail with // an immediate crash. // Note that use of a specified |FPDF_FONT_BACKEND_TYPE| value for which the // corresponding font library is not included in the build will similarly fail // with an immediate crash. FPDF_FONT_BACKEND_TYPE m_FontLibraryType; } FPDF_LIBRARY_CONFIG; // Function: FPDF_InitLibraryWithConfig // Initialize the PDFium library and allocate global resources for it. // Parameters: // config - configuration information as above. // Return value: // None. // Comments: // You have to call this function before you can call any PDF // processing functions. FPDF_EXPORT void FPDF_CALLCONV FPDF_InitLibraryWithConfig(const FPDF_LIBRARY_CONFIG* config); // Function: FPDF_InitLibrary // Initialize the PDFium library (alternative form). // Parameters: // None // Return value: // None. // Comments: // Convenience function to call FPDF_InitLibraryWithConfig() with a // default configuration for backwards compatibility purposes. New // code should call FPDF_InitLibraryWithConfig() instead. This will // be deprecated in the future. FPDF_EXPORT void FPDF_CALLCONV FPDF_InitLibrary(); // Function: FPDF_DestroyLibrary // Release global resources allocated to the PDFium library by // FPDF_InitLibrary() or FPDF_InitLibraryWithConfig(). // Parameters: // None. // Return value: // None. // Comments: // After this function is called, you must not call any PDF // processing functions. // // Calling this function does not automatically close other // objects. It is recommended to close other objects before // closing the library with this function. FPDF_EXPORT void FPDF_CALLCONV FPDF_DestroyLibrary(); // Policy for accessing the local machine time. #define FPDF_POLICY_MACHINETIME_ACCESS 0 // Function: FPDF_SetSandBoxPolicy // Set the policy for the sandbox environment. // Parameters: // policy - The specified policy for setting, for example: // FPDF_POLICY_MACHINETIME_ACCESS. // enable - True to enable, false to disable the policy. // Return value: // None. FPDF_EXPORT void FPDF_CALLCONV FPDF_SetSandBoxPolicy(FPDF_DWORD policy, FPDF_BOOL enable); #if defined(_WIN32) // Experimental API. // Function: FPDF_SetPrintMode // Set printing mode when printing on Windows. // Parameters: // mode - FPDF_PRINTMODE_EMF to output EMF (default) // FPDF_PRINTMODE_TEXTONLY to output text only (for charstream // devices) // FPDF_PRINTMODE_POSTSCRIPT2 to output level 2 PostScript into // EMF as a series of GDI comments. // FPDF_PRINTMODE_POSTSCRIPT3 to output level 3 PostScript into // EMF as a series of GDI comments. // FPDF_PRINTMODE_POSTSCRIPT2_PASSTHROUGH to output level 2 // PostScript via ExtEscape() in PASSTHROUGH mode. // FPDF_PRINTMODE_POSTSCRIPT3_PASSTHROUGH to output level 3 // PostScript via ExtEscape() in PASSTHROUGH mode. // FPDF_PRINTMODE_EMF_IMAGE_MASKS to output EMF, with more // efficient processing of documents containing image masks. // FPDF_PRINTMODE_POSTSCRIPT3_TYPE42 to output level 3 // PostScript with embedded Type 42 fonts, when applicable, into // EMF as a series of GDI comments. // FPDF_PRINTMODE_POSTSCRIPT3_TYPE42_PASSTHROUGH to output level // 3 PostScript with embedded Type 42 fonts, when applicable, // via ExtEscape() in PASSTHROUGH mode. // Return value: // True if successful, false if unsuccessful (typically invalid input). FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_SetPrintMode(int mode); #endif // defined(_WIN32) // Function: FPDF_LoadDocument // Open and load a PDF document. // Parameters: // file_path - Path to the PDF file (including extension). // password - A string used as the password for the PDF file. // If no password is needed, empty or NULL can be used. // See comments below regarding the encoding. // Return value: // A handle to the loaded document, or NULL on failure. // Comments: // Loaded document can be closed by FPDF_CloseDocument(). // If this function fails, you can use FPDF_GetLastError() to retrieve // the reason why it failed. // // The encoding for |file_path| is UTF-8. // // The encoding for |password| can be either UTF-8 or Latin-1. PDFs, // depending on the security handler revision, will only accept one or // the other encoding. If |password|'s encoding and the PDF's expected // encoding do not match, FPDF_LoadDocument() will automatically // convert |password| to the other encoding. FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV FPDF_LoadDocument(FPDF_STRING file_path, FPDF_BYTESTRING password); // Function: FPDF_LoadMemDocument // Open and load a PDF document from memory. // Parameters: // data_buf - Pointer to a buffer containing the PDF document. // size - Number of bytes in the PDF document. // password - A string used as the password for the PDF file. // If no password is needed, empty or NULL can be used. // Return value: // A handle to the loaded document, or NULL on failure. // Comments: // The memory buffer must remain valid when the document is open. // The loaded document can be closed by FPDF_CloseDocument. // If this function fails, you can use FPDF_GetLastError() to retrieve // the reason why it failed. // // See the comments for FPDF_LoadDocument() regarding the encoding for // |password|. // Notes: // If PDFium is built with the XFA module, the application should call // FPDF_LoadXFA() function after the PDF document loaded to support XFA // fields defined in the fpdfformfill.h file. FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV FPDF_LoadMemDocument(const void* data_buf, int size, FPDF_BYTESTRING password); // Experimental API. // Function: FPDF_LoadMemDocument64 // Open and load a PDF document from memory. // Parameters: // data_buf - Pointer to a buffer containing the PDF document. // size - Number of bytes in the PDF document. // password - A string used as the password for the PDF file. // If no password is needed, empty or NULL can be used. // Return value: // A handle to the loaded document, or NULL on failure. // Comments: // The memory buffer must remain valid when the document is open. // The loaded document can be closed by FPDF_CloseDocument. // If this function fails, you can use FPDF_GetLastError() to retrieve // the reason why it failed. // // See the comments for FPDF_LoadDocument() regarding the encoding for // |password|. // Notes: // If PDFium is built with the XFA module, the application should call // FPDF_LoadXFA() function after the PDF document loaded to support XFA // fields defined in the fpdfformfill.h file. FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV FPDF_LoadMemDocument64(const void* data_buf, size_t size, FPDF_BYTESTRING password); // Structure for custom file access. typedef struct { // File length, in bytes. unsigned long m_FileLen; // A function pointer for getting a block of data from a specific position. // Position is specified by byte offset from the beginning of the file. // The pointer to the buffer is never NULL and the size is never 0. // The position and size will never go out of range of the file length. // It may be possible for PDFium to call this function multiple times for // the same position. // Return value: should be non-zero if successful, zero for error. int (*m_GetBlock)(void* param, unsigned long position, unsigned char* pBuf, unsigned long size); // A custom pointer for all implementation specific data. This pointer will // be used as the first parameter to the m_GetBlock callback. void* m_Param; } FPDF_FILEACCESS; // Structure for file reading or writing (I/O). // // Note: This is a handler and should be implemented by callers, // and is only used from XFA. typedef struct FPDF_FILEHANDLER_ { // User-defined data. // Note: Callers can use this field to track controls. void* clientData; // Callback function to release the current file stream object. // // Parameters: // clientData - Pointer to user-defined data. // Returns: // None. void (*Release)(void* clientData); // Callback function to retrieve the current file stream size. // // Parameters: // clientData - Pointer to user-defined data. // Returns: // Size of file stream. FPDF_DWORD (*GetSize)(void* clientData); // Callback function to read data from the current file stream. // // Parameters: // clientData - Pointer to user-defined data. // offset - Offset position starts from the beginning of file // stream. This parameter indicates reading position. // buffer - Memory buffer to store data which are read from // file stream. This parameter should not be NULL. // size - Size of data which should be read from file stream, // in bytes. The buffer indicated by |buffer| must be // large enough to store specified data. // Returns: // 0 for success, other value for failure. FPDF_RESULT (*ReadBlock)(void* clientData, FPDF_DWORD offset, void* buffer, FPDF_DWORD size); // Callback function to write data into the current file stream. // // Parameters: // clientData - Pointer to user-defined data. // offset - Offset position starts from the beginning of file // stream. This parameter indicates writing position. // buffer - Memory buffer contains data which is written into // file stream. This parameter should not be NULL. // size - Size of data which should be written into file // stream, in bytes. // Returns: // 0 for success, other value for failure. FPDF_RESULT (*WriteBlock)(void* clientData, FPDF_DWORD offset, const void* buffer, FPDF_DWORD size); // Callback function to flush all internal accessing buffers. // // Parameters: // clientData - Pointer to user-defined data. // Returns: // 0 for success, other value for failure. FPDF_RESULT (*Flush)(void* clientData); // Callback function to change file size. // // Description: // This function is called under writing mode usually. Implementer // can determine whether to realize it based on application requests. // Parameters: // clientData - Pointer to user-defined data. // size - New size of file stream, in bytes. // Returns: // 0 for success, other value for failure. FPDF_RESULT (*Truncate)(void* clientData, FPDF_DWORD size); } FPDF_FILEHANDLER; // Function: FPDF_LoadCustomDocument // Load PDF document from a custom access descriptor. // Parameters: // pFileAccess - A structure for accessing the file. // password - Optional password for decrypting the PDF file. // Return value: // A handle to the loaded document, or NULL on failure. // Comments: // The application must keep the file resources |pFileAccess| points to // valid until the returned FPDF_DOCUMENT is closed. |pFileAccess| // itself does not need to outlive the FPDF_DOCUMENT. // // The loaded document can be closed with FPDF_CloseDocument(). // // See the comments for FPDF_LoadDocument() regarding the encoding for // |password|. // Notes: // If PDFium is built with the XFA module, the application should call // FPDF_LoadXFA() function after the PDF document loaded to support XFA // fields defined in the fpdfformfill.h file. FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV FPDF_LoadCustomDocument(FPDF_FILEACCESS* pFileAccess, FPDF_BYTESTRING password); // Function: FPDF_GetFileVersion // Get the file version of the given PDF document. // Parameters: // doc - Handle to a document. // fileVersion - The PDF file version. File version: 14 for 1.4, 15 // for 1.5, ... // Return value: // True if succeeds, false otherwise. // Comments: // If the document was created by FPDF_CreateNewDocument, // then this function will always fail. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_GetFileVersion(FPDF_DOCUMENT doc, int* fileVersion); #define FPDF_ERR_SUCCESS 0 // No error. #define FPDF_ERR_UNKNOWN 1 // Unknown error. #define FPDF_ERR_FILE 2 // File not found or could not be opened. #define FPDF_ERR_FORMAT 3 // File not in PDF format or corrupted. #define FPDF_ERR_PASSWORD 4 // Password required or incorrect password. #define FPDF_ERR_SECURITY 5 // Unsupported security scheme. #define FPDF_ERR_PAGE 6 // Page not found or content error. #ifdef PDF_ENABLE_XFA #define FPDF_ERR_XFALOAD 7 // Load XFA error. #define FPDF_ERR_XFALAYOUT 8 // Layout XFA error. #endif // PDF_ENABLE_XFA // Function: FPDF_GetLastError // Get last error code when a function fails. // Parameters: // None. // Return value: // A 32-bit integer indicating error code as defined above. // Comments: // If the previous SDK call succeeded, the return value of this // function is not defined. This function only works in conjunction // with APIs that mention FPDF_GetLastError() in their documentation. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetLastError(); // Experimental API. // Function: FPDF_DocumentHasValidCrossReferenceTable // Whether the document's cross reference table is valid or not. // Parameters: // document - Handle to a document. Returned by FPDF_LoadDocument. // Return value: // True if the PDF parser did not encounter problems parsing the cross // reference table. False if the parser could not parse the cross // reference table and the table had to be rebuild from other data // within the document. // Comments: // The return value can change over time as the PDF parser evolves. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_DocumentHasValidCrossReferenceTable(FPDF_DOCUMENT document); // Experimental API. // Function: FPDF_GetTrailerEnds // Get the byte offsets of trailer ends. // Parameters: // document - Handle to document. Returned by FPDF_LoadDocument(). // buffer - The address of a buffer that receives the // byte offsets. // length - The size, in ints, of |buffer|. // Return value: // Returns the number of ints in the buffer on success, 0 on error. // // |buffer| is an array of integers that describes the exact byte offsets of the // trailer ends in the document. If |length| is less than the returned length, // or |document| or |buffer| is NULL, |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetTrailerEnds(FPDF_DOCUMENT document, unsigned int* buffer, unsigned long length); // Function: FPDF_GetDocPermissions // Get file permission flags of the document. // Parameters: // document - Handle to a document. Returned by FPDF_LoadDocument. // Return value: // A 32-bit integer indicating permission flags. Please refer to the // PDF Reference for detailed descriptions. If the document is not // protected or was unlocked by the owner, 0xffffffff will be returned. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetDocPermissions(FPDF_DOCUMENT document); // Function: FPDF_GetDocUserPermissions // Get user file permission flags of the document. // Parameters: // document - Handle to a document. Returned by FPDF_LoadDocument. // Return value: // A 32-bit integer indicating permission flags. Please refer to the // PDF Reference for detailed descriptions. If the document is not // protected, 0xffffffff will be returned. Always returns user // permissions, even if the document was unlocked by the owner. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetDocUserPermissions(FPDF_DOCUMENT document); // Function: FPDF_GetSecurityHandlerRevision // Get the revision for the security handler. // Parameters: // document - Handle to a document. Returned by FPDF_LoadDocument. // Return value: // The security handler revision number. Please refer to the PDF // Reference for a detailed description. If the document is not // protected, -1 will be returned. FPDF_EXPORT int FPDF_CALLCONV FPDF_GetSecurityHandlerRevision(FPDF_DOCUMENT document); // Function: FPDF_GetPageCount // Get total number of pages in the document. // Parameters: // document - Handle to document. Returned by FPDF_LoadDocument. // Return value: // Total number of pages in the document. FPDF_EXPORT int FPDF_CALLCONV FPDF_GetPageCount(FPDF_DOCUMENT document); // Function: FPDF_LoadPage // Load a page inside the document. // Parameters: // document - Handle to document. Returned by FPDF_LoadDocument // page_index - Index number of the page. 0 for the first page. // Return value: // A handle to the loaded page, or NULL if page load fails. // Comments: // The loaded page can be rendered to devices using FPDF_RenderPage. // The loaded page can be closed using FPDF_ClosePage. FPDF_EXPORT FPDF_PAGE FPDF_CALLCONV FPDF_LoadPage(FPDF_DOCUMENT document, int page_index); // Experimental API // Function: FPDF_GetPageWidthF // Get page width. // Parameters: // page - Handle to the page. Returned by FPDF_LoadPage(). // Return value: // Page width (excluding non-displayable area) measured in points. // One point is 1/72 inch (around 0.3528 mm). // Comments: // Changing the rotation of |page| affects the return value. FPDF_EXPORT float FPDF_CALLCONV FPDF_GetPageWidthF(FPDF_PAGE page); // Function: FPDF_GetPageWidth // Get page width. // Parameters: // page - Handle to the page. Returned by FPDF_LoadPage. // Return value: // Page width (excluding non-displayable area) measured in points. // One point is 1/72 inch (around 0.3528 mm). // Note: // Prefer FPDF_GetPageWidthF() above. This will be deprecated in the // future. // Comments: // Changing the rotation of |page| affects the return value. FPDF_EXPORT double FPDF_CALLCONV FPDF_GetPageWidth(FPDF_PAGE page); // Experimental API // Function: FPDF_GetPageHeightF // Get page height. // Parameters: // page - Handle to the page. Returned by FPDF_LoadPage(). // Return value: // Page height (excluding non-displayable area) measured in points. // One point is 1/72 inch (around 0.3528 mm) // Comments: // Changing the rotation of |page| affects the return value. FPDF_EXPORT float FPDF_CALLCONV FPDF_GetPageHeightF(FPDF_PAGE page); // Function: FPDF_GetPageHeight // Get page height. // Parameters: // page - Handle to the page. Returned by FPDF_LoadPage. // Return value: // Page height (excluding non-displayable area) measured in points. // One point is 1/72 inch (around 0.3528 mm) // Note: // Prefer FPDF_GetPageHeightF() above. This will be deprecated in the // future. // Comments: // Changing the rotation of |page| affects the return value. FPDF_EXPORT double FPDF_CALLCONV FPDF_GetPageHeight(FPDF_PAGE page); // Experimental API. // Function: FPDF_GetPageBoundingBox // Get the bounding box of the page. This is the intersection between // its media box and its crop box. // Parameters: // page - Handle to the page. Returned by FPDF_LoadPage. // rect - Pointer to a rect to receive the page bounding box. // On an error, |rect| won't be filled. // Return value: // True for success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_GetPageBoundingBox(FPDF_PAGE page, FS_RECTF* rect); // Experimental API. // Function: FPDF_GetPageSizeByIndexF // Get the size of the page at the given index. // Parameters: // document - Handle to document. Returned by FPDF_LoadDocument(). // page_index - Page index, zero for the first page. // size - Pointer to a FS_SIZEF to receive the page size. // (in points). // Return value: // Non-zero for success. 0 for error (document or page not found). FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_GetPageSizeByIndexF(FPDF_DOCUMENT document, int page_index, FS_SIZEF* size); // Function: FPDF_GetPageSizeByIndex // Get the size of the page at the given index. // Parameters: // document - Handle to document. Returned by FPDF_LoadDocument. // page_index - Page index, zero for the first page. // width - Pointer to a double to receive the page width // (in points). // height - Pointer to a double to receive the page height // (in points). // Return value: // Non-zero for success. 0 for error (document or page not found). // Note: // Prefer FPDF_GetPageSizeByIndexF() above. This will be deprecated in // the future. FPDF_EXPORT int FPDF_CALLCONV FPDF_GetPageSizeByIndex(FPDF_DOCUMENT document, int page_index, double* width, double* height); // Page rendering flags. They can be combined with bit-wise OR. // // Set if annotations are to be rendered. #define FPDF_ANNOT 0x01 // Set if using text rendering optimized for LCD display. This flag will only // take effect if anti-aliasing is enabled for text. #define FPDF_LCD_TEXT 0x02 // Don't use the native text output available on some platforms #define FPDF_NO_NATIVETEXT 0x04 // Grayscale output. #define FPDF_GRAYSCALE 0x08 // Obsolete, has no effect, retained for compatibility. #define FPDF_DEBUG_INFO 0x80 // Obsolete, has no effect, retained for compatibility. #define FPDF_NO_CATCH 0x100 // Limit image cache size. #define FPDF_RENDER_LIMITEDIMAGECACHE 0x200 // Always use halftone for image stretching. #define FPDF_RENDER_FORCEHALFTONE 0x400 // Render for printing. #define FPDF_PRINTING 0x800 // Set to disable anti-aliasing on text. This flag will also disable LCD // optimization for text rendering. #define FPDF_RENDER_NO_SMOOTHTEXT 0x1000 // Set to disable anti-aliasing on images. #define FPDF_RENDER_NO_SMOOTHIMAGE 0x2000 // Set to disable anti-aliasing on paths. #define FPDF_RENDER_NO_SMOOTHPATH 0x4000 // Set whether to render in a reverse Byte order, this flag is only used when // rendering to a bitmap. #define FPDF_REVERSE_BYTE_ORDER 0x10 // Set whether fill paths need to be stroked. This flag is only used when // FPDF_COLORSCHEME is passed in, since with a single fill color for paths the // boundaries of adjacent fill paths are less visible. #define FPDF_CONVERT_FILL_TO_STROKE 0x20 // Struct for color scheme. // Each should be a 32-bit value specifying the color, in 8888 ARGB format. typedef struct FPDF_COLORSCHEME_ { FPDF_DWORD path_fill_color; FPDF_DWORD path_stroke_color; FPDF_DWORD text_fill_color; FPDF_DWORD text_stroke_color; } FPDF_COLORSCHEME; #ifdef _WIN32 // Function: FPDF_RenderPage // Render contents of a page to a device (screen, bitmap, or printer). // This function is only supported on Windows. // Parameters: // dc - Handle to the device context. // page - Handle to the page. Returned by FPDF_LoadPage. // start_x - Left pixel position of the display area in // device coordinates. // start_y - Top pixel position of the display area in device // coordinates. // size_x - Horizontal size (in pixels) for displaying the page. // size_y - Vertical size (in pixels) for displaying the page. // rotate - Page orientation: // 0 (normal) // 1 (rotated 90 degrees clockwise) // 2 (rotated 180 degrees) // 3 (rotated 90 degrees counter-clockwise) // flags - 0 for normal display, or combination of flags // defined above. // Return value: // Returns true if the page is rendered successfully, false otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_RenderPage(HDC dc, FPDF_PAGE page, int start_x, int start_y, int size_x, int size_y, int rotate, int flags); #endif // Function: FPDF_RenderPageBitmap // Render contents of a page to a device independent bitmap. // Parameters: // bitmap - Handle to the device independent bitmap (as the // output buffer). The bitmap handle can be created // by FPDFBitmap_Create or retrieved from an image // object by FPDFImageObj_GetBitmap. // page - Handle to the page. Returned by FPDF_LoadPage // start_x - Left pixel position of the display area in // bitmap coordinates. // start_y - Top pixel position of the display area in bitmap // coordinates. // size_x - Horizontal size (in pixels) for displaying the page. // size_y - Vertical size (in pixels) for displaying the page. // rotate - Page orientation: // 0 (normal) // 1 (rotated 90 degrees clockwise) // 2 (rotated 180 degrees) // 3 (rotated 90 degrees counter-clockwise) // flags - 0 for normal display, or combination of the Page // Rendering flags defined above. With the FPDF_ANNOT // flag, it renders all annotations that do not require // user-interaction, which are all annotations except // widget and popup annotations. // Return value: // None. FPDF_EXPORT void FPDF_CALLCONV FPDF_RenderPageBitmap(FPDF_BITMAP bitmap, FPDF_PAGE page, int start_x, int start_y, int size_x, int size_y, int rotate, int flags); // Function: FPDF_RenderPageBitmapWithMatrix // Render contents of a page to a device independent bitmap. // Parameters: // bitmap - Handle to the device independent bitmap (as the // output buffer). The bitmap handle can be created // by FPDFBitmap_Create or retrieved by // FPDFImageObj_GetBitmap. // page - Handle to the page. Returned by FPDF_LoadPage. // matrix - The transform matrix, which must be invertible. // See PDF Reference 1.7, 4.2.2 Common Transformations. // clipping - The rect to clip to in device coords. // flags - 0 for normal display, or combination of the Page // Rendering flags defined above. With the FPDF_ANNOT // flag, it renders all annotations that do not require // user-interaction, which are all annotations except // widget and popup annotations. // Return value: // None. Note that behavior is undefined if det of |matrix| is 0. FPDF_EXPORT void FPDF_CALLCONV FPDF_RenderPageBitmapWithMatrix(FPDF_BITMAP bitmap, FPDF_PAGE page, const FS_MATRIX* matrix, const FS_RECTF* clipping, int flags); #if defined(PDF_USE_SKIA) // Experimental API. // Function: FPDF_RenderPageSkia // Render contents of a page to a Skia SkCanvas. // Parameters: // canvas - SkCanvas to render to. // page - Handle to the page. // size_x - Horizontal size (in pixels) for displaying the page. // size_y - Vertical size (in pixels) for displaying the page. // Return value: // None. FPDF_EXPORT void FPDF_CALLCONV FPDF_RenderPageSkia(FPDF_SKIA_CANVAS canvas, FPDF_PAGE page, int size_x, int size_y); #endif // Function: FPDF_ClosePage // Close a loaded PDF page. // Parameters: // page - Handle to the loaded page. // Return value: // None. FPDF_EXPORT void FPDF_CALLCONV FPDF_ClosePage(FPDF_PAGE page); // Function: FPDF_CloseDocument // Close a loaded PDF document. // Parameters: // document - Handle to the loaded document. // Return value: // None. FPDF_EXPORT void FPDF_CALLCONV FPDF_CloseDocument(FPDF_DOCUMENT document); // Function: FPDF_DeviceToPage // Convert the screen coordinates of a point to page coordinates. // Parameters: // page - Handle to the page. Returned by FPDF_LoadPage. // start_x - Left pixel position of the display area in // device coordinates. // start_y - Top pixel position of the display area in device // coordinates. // size_x - Horizontal size (in pixels) for displaying the page. // size_y - Vertical size (in pixels) for displaying the page. // rotate - Page orientation: // 0 (normal) // 1 (rotated 90 degrees clockwise) // 2 (rotated 180 degrees) // 3 (rotated 90 degrees counter-clockwise) // device_x - X value in device coordinates to be converted. // device_y - Y value in device coordinates to be converted. // page_x - A pointer to a double receiving the converted X // value in page coordinates. // page_y - A pointer to a double receiving the converted Y // value in page coordinates. // Return value: // Returns true if the conversion succeeds, and |page_x| and |page_y| // successfully receives the converted coordinates. // Comments: // The page coordinate system has its origin at the left-bottom corner // of the page, with the X-axis on the bottom going to the right, and // the Y-axis on the left side going up. // // NOTE: this coordinate system can be altered when you zoom, scroll, // or rotate a page, however, a point on the page should always have // the same coordinate values in the page coordinate system. // // The device coordinate system is device dependent. For screen device, // its origin is at the left-top corner of the window. However this // origin can be altered by the Windows coordinate transformation // utilities. // // You must make sure the start_x, start_y, size_x, size_y // and rotate parameters have exactly same values as you used in // the FPDF_RenderPage() function call. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_DeviceToPage(FPDF_PAGE page, int start_x, int start_y, int size_x, int size_y, int rotate, int device_x, int device_y, double* page_x, double* page_y); // Function: FPDF_PageToDevice // Convert the page coordinates of a point to screen coordinates. // Parameters: // page - Handle to the page. Returned by FPDF_LoadPage. // start_x - Left pixel position of the display area in // device coordinates. // start_y - Top pixel position of the display area in device // coordinates. // size_x - Horizontal size (in pixels) for displaying the page. // size_y - Vertical size (in pixels) for displaying the page. // rotate - Page orientation: // 0 (normal) // 1 (rotated 90 degrees clockwise) // 2 (rotated 180 degrees) // 3 (rotated 90 degrees counter-clockwise) // page_x - X value in page coordinates. // page_y - Y value in page coordinate. // device_x - A pointer to an integer receiving the result X // value in device coordinates. // device_y - A pointer to an integer receiving the result Y // value in device coordinates. // Return value: // Returns true if the conversion succeeds, and |device_x| and // |device_y| successfully receives the converted coordinates. // Comments: // See comments for FPDF_DeviceToPage(). FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_PageToDevice(FPDF_PAGE page, int start_x, int start_y, int size_x, int size_y, int rotate, double page_x, double page_y, int* device_x, int* device_y); // Function: FPDFBitmap_Create // Create a device independent bitmap (FXDIB). // Parameters: // width - The number of pixels in width for the bitmap. // Must be greater than 0. // height - The number of pixels in height for the bitmap. // Must be greater than 0. // alpha - A flag indicating whether the alpha channel is used. // Non-zero for using alpha, zero for not using. // Return value: // The created bitmap handle, or NULL if a parameter error or out of // memory. // Comments: // The bitmap always uses 4 bytes per pixel. The first byte is always // double word aligned. // // The byte order is BGRx (the last byte unused if no alpha channel) or // BGRA. // // The pixels in a horizontal line are stored side by side, with the // left most pixel stored first (with lower memory address). // Each line uses width * 4 bytes. // // Lines are stored one after another, with the top most line stored // first. There is no gap between adjacent lines. // // This function allocates enough memory for holding all pixels in the // bitmap, but it doesn't initialize the buffer. Applications can use // FPDFBitmap_FillRect() to fill the bitmap using any color. If the OS // allows it, this function can allocate up to 4 GB of memory. FPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV FPDFBitmap_Create(int width, int height, int alpha); // More DIB formats // Unknown or unsupported format. // All of the colors are listed in order of LSB to MSB. #define FPDFBitmap_Unknown 0 // Gray scale bitmap, one byte per pixel. #define FPDFBitmap_Gray 1 // 3 bytes per pixel, byte order: blue, green, red. #define FPDFBitmap_BGR 2 // 4 bytes per pixel, byte order: blue, green, red, unused. #define FPDFBitmap_BGRx 3 // 4 bytes per pixel, byte order: blue, green, red, alpha. // Pixel components are independent of alpha. #define FPDFBitmap_BGRA 4 // 4 bytes per pixel, byte order: blue, green, red, alpha. // Pixel components are premultiplied by alpha. // Note that this is experimental and only supported when rendering with // |FPDF_RENDERER_TYPE| is set to |FPDF_RENDERERTYPE_SKIA|. #define FPDFBitmap_BGRA_Premul 5 // Function: FPDFBitmap_CreateEx // Create a device independent bitmap (FXDIB) // Parameters: // width - The number of pixels in width for the bitmap. // Must be greater than 0. // height - The number of pixels in height for the bitmap. // Must be greater than 0. // format - A number indicating for bitmap format, as defined // above. // first_scan - A pointer to the first byte of the first line if // using an external buffer. If this parameter is NULL, // then a new buffer will be created. // stride - Number of bytes for each scan line. The value must // be 0 or greater. When the value is 0, // FPDFBitmap_CreateEx() will automatically calculate // the appropriate value using |width| and |format|. // When using an external buffer, it is recommended for // the caller to pass in the value. // When not using an external buffer, it is recommended // for the caller to pass in 0. // Return value: // The bitmap handle, or NULL if parameter error or out of memory. // Comments: // Similar to FPDFBitmap_Create function, but allows for more formats // and an external buffer is supported. The bitmap created by this // function can be used in any place that a FPDF_BITMAP handle is // required. // // If an external buffer is used, then the caller should destroy the // buffer. FPDFBitmap_Destroy() will not destroy the buffer. // // It is recommended to use FPDFBitmap_GetStride() to get the stride // value. FPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV FPDFBitmap_CreateEx(int width, int height, int format, void* first_scan, int stride); // Function: FPDFBitmap_GetFormat // Get the format of the bitmap. // Parameters: // bitmap - Handle to the bitmap. Returned by FPDFBitmap_Create // or FPDFImageObj_GetBitmap. // Return value: // The format of the bitmap. // Comments: // Only formats supported by FPDFBitmap_CreateEx are supported by this // function; see the list of such formats above. FPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetFormat(FPDF_BITMAP bitmap); // Function: FPDFBitmap_FillRect // Fill a rectangle in a bitmap. // Parameters: // bitmap - The handle to the bitmap. Returned by // FPDFBitmap_Create. // left - The left position. Starting from 0 at the // left-most pixel. // top - The top position. Starting from 0 at the // top-most line. // width - Width in pixels to be filled. // height - Height in pixels to be filled. // color - A 32-bit value specifing the color, in 8888 ARGB // format. // Return value: // Returns whether the operation succeeded or not. // Comments: // This function sets the color and (optionally) alpha value in the // specified region of the bitmap. // // NOTE: If the alpha channel is used, this function does NOT // composite the background with the source color, instead the // background will be replaced by the source color and the alpha. // // If the alpha channel is not used, the alpha parameter is ignored. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFBitmap_FillRect(FPDF_BITMAP bitmap, int left, int top, int width, int height, FPDF_DWORD color); // Function: FPDFBitmap_GetBuffer // Get data buffer of a bitmap. // Parameters: // bitmap - Handle to the bitmap. Returned by FPDFBitmap_Create // or FPDFImageObj_GetBitmap. // Return value: // The pointer to the first byte of the bitmap buffer. // Comments: // The stride may be more than width * number of bytes per pixel // // Applications can use this function to get the bitmap buffer pointer, // then manipulate any color and/or alpha values for any pixels in the // bitmap. // // Use FPDFBitmap_GetFormat() to find out the format of the data. FPDF_EXPORT void* FPDF_CALLCONV FPDFBitmap_GetBuffer(FPDF_BITMAP bitmap); // Function: FPDFBitmap_GetWidth // Get width of a bitmap. // Parameters: // bitmap - Handle to the bitmap. Returned by FPDFBitmap_Create // or FPDFImageObj_GetBitmap. // Return value: // The width of the bitmap in pixels. FPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetWidth(FPDF_BITMAP bitmap); // Function: FPDFBitmap_GetHeight // Get height of a bitmap. // Parameters: // bitmap - Handle to the bitmap. Returned by FPDFBitmap_Create // or FPDFImageObj_GetBitmap. // Return value: // The height of the bitmap in pixels. FPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetHeight(FPDF_BITMAP bitmap); // Function: FPDFBitmap_GetStride // Get number of bytes for each line in the bitmap buffer. // Parameters: // bitmap - Handle to the bitmap. Returned by FPDFBitmap_Create // or FPDFImageObj_GetBitmap. // Return value: // The number of bytes for each line in the bitmap buffer. // Comments: // The stride may be more than width * number of bytes per pixel. FPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetStride(FPDF_BITMAP bitmap); // Function: FPDFBitmap_Destroy // Destroy a bitmap and release all related buffers. // Parameters: // bitmap - Handle to the bitmap. Returned by FPDFBitmap_Create // or FPDFImageObj_GetBitmap. // Return value: // None. // Comments: // This function will not destroy any external buffers provided when // the bitmap was created. FPDF_EXPORT void FPDF_CALLCONV FPDFBitmap_Destroy(FPDF_BITMAP bitmap); // Function: FPDF_VIEWERREF_GetPrintScaling // Whether the PDF document prefers to be scaled or not. // Parameters: // document - Handle to the loaded document. // Return value: // None. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_VIEWERREF_GetPrintScaling(FPDF_DOCUMENT document); // Function: FPDF_VIEWERREF_GetNumCopies // Returns the number of copies to be printed. // Parameters: // document - Handle to the loaded document. // Return value: // The number of copies to be printed. FPDF_EXPORT int FPDF_CALLCONV FPDF_VIEWERREF_GetNumCopies(FPDF_DOCUMENT document); // Function: FPDF_VIEWERREF_GetPrintPageRange // Page numbers to initialize print dialog box when file is printed. // Parameters: // document - Handle to the loaded document. // Return value: // The print page range to be used for printing. FPDF_EXPORT FPDF_PAGERANGE FPDF_CALLCONV FPDF_VIEWERREF_GetPrintPageRange(FPDF_DOCUMENT document); // Experimental API. // Function: FPDF_VIEWERREF_GetPrintPageRangeCount // Returns the number of elements in a FPDF_PAGERANGE. // Parameters: // pagerange - Handle to the page range. // Return value: // The number of elements in the page range. Returns 0 on error. FPDF_EXPORT size_t FPDF_CALLCONV FPDF_VIEWERREF_GetPrintPageRangeCount(FPDF_PAGERANGE pagerange); // Experimental API. // Function: FPDF_VIEWERREF_GetPrintPageRangeElement // Returns an element from a FPDF_PAGERANGE. // Parameters: // pagerange - Handle to the page range. // index - Index of the element. // Return value: // The value of the element in the page range at a given index. // Returns -1 on error. FPDF_EXPORT int FPDF_CALLCONV FPDF_VIEWERREF_GetPrintPageRangeElement(FPDF_PAGERANGE pagerange, size_t index); // Function: FPDF_VIEWERREF_GetDuplex // Returns the paper handling option to be used when printing from // the print dialog. // Parameters: // document - Handle to the loaded document. // Return value: // The paper handling option to be used when printing. FPDF_EXPORT FPDF_DUPLEXTYPE FPDF_CALLCONV FPDF_VIEWERREF_GetDuplex(FPDF_DOCUMENT document); // Function: FPDF_VIEWERREF_GetName // Gets the contents for a viewer ref, with a given key. The value must // be of type "name". // Parameters: // document - Handle to the loaded document. // key - Name of the key in the viewer pref dictionary, // encoded in UTF-8. // buffer - Caller-allocate buffer to receive the key, or NULL // - to query the required length. // length - Length of the buffer. // Return value: // The number of bytes in the contents, including the NULL terminator. // Thus if the return value is 0, then that indicates an error, such // as when |document| is invalid. If |length| is less than the required // length, or |buffer| is NULL, |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_VIEWERREF_GetName(FPDF_DOCUMENT document, FPDF_BYTESTRING key, char* buffer, unsigned long length); // Function: FPDF_CountNamedDests // Get the count of named destinations in the PDF document. // Parameters: // document - Handle to a document // Return value: // The count of named destinations. FPDF_EXPORT FPDF_DWORD FPDF_CALLCONV FPDF_CountNamedDests(FPDF_DOCUMENT document); // Function: FPDF_GetNamedDestByName // Get a the destination handle for the given name. // Parameters: // document - Handle to the loaded document. // name - The name of a destination. // Return value: // The handle to the destination. FPDF_EXPORT FPDF_DEST FPDF_CALLCONV FPDF_GetNamedDestByName(FPDF_DOCUMENT document, FPDF_BYTESTRING name); // Function: FPDF_GetNamedDest // Get the named destination by index. // Parameters: // document - Handle to a document // index - The index of a named destination. // buffer - The buffer to store the destination name, // used as wchar_t*. // buflen [in/out] - Size of the buffer in bytes on input, // length of the result in bytes on output // or -1 if the buffer is too small. // Return value: // The destination handle for a given index, or NULL if there is no // named destination corresponding to |index|. // Comments: // Call this function twice to get the name of the named destination: // 1) First time pass in |buffer| as NULL and get buflen. // 2) Second time pass in allocated |buffer| and buflen to retrieve // |buffer|, which should be used as wchar_t*. // // If buflen is not sufficiently large, it will be set to -1 upon // return. FPDF_EXPORT FPDF_DEST FPDF_CALLCONV FPDF_GetNamedDest(FPDF_DOCUMENT document, int index, void* buffer, long* buflen); // Experimental API. // Function: FPDF_GetXFAPacketCount // Get the number of valid packets in the XFA entry. // Parameters: // document - Handle to the document. // Return value: // The number of valid packets, or -1 on error. FPDF_EXPORT int FPDF_CALLCONV FPDF_GetXFAPacketCount(FPDF_DOCUMENT document); // Experimental API. // Function: FPDF_GetXFAPacketName // Get the name of a packet in the XFA array. // Parameters: // document - Handle to the document. // index - Index number of the packet. 0 for the first packet. // buffer - Buffer for holding the name of the XFA packet. // buflen - Length of |buffer| in bytes. // Return value: // The length of the packet name in bytes, or 0 on error. // // |document| must be valid and |index| must be in the range [0, N), where N is // the value returned by FPDF_GetXFAPacketCount(). // |buffer| is only modified if it is non-NULL and |buflen| is greater than or // equal to the length of the packet name. The packet name includes a // terminating NUL character. |buffer| is unmodified on error. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetXFAPacketName( FPDF_DOCUMENT document, int index, void* buffer, unsigned long buflen); // Experimental API. // Function: FPDF_GetXFAPacketContent // Get the content of a packet in the XFA array. // Parameters: // document - Handle to the document. // index - Index number of the packet. 0 for the first packet. // buffer - Buffer for holding the content of the XFA packet. // buflen - Length of |buffer| in bytes. // out_buflen - Pointer to the variable that will receive the minimum // buffer size needed to contain the content of the XFA // packet. // Return value: // Whether the operation succeeded or not. // // |document| must be valid and |index| must be in the range [0, N), where N is // the value returned by FPDF_GetXFAPacketCount(). |out_buflen| must not be // NULL. When the aforementioned arguments are valid, the operation succeeds, // and |out_buflen| receives the content size. |buffer| is only modified if // |buffer| is non-null and long enough to contain the content. Callers must // check both the return value and the input |buflen| is no less than the // returned |out_buflen| before using the data in |buffer|. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_GetXFAPacketContent( FPDF_DOCUMENT document, int index, void* buffer, unsigned long buflen, unsigned long* out_buflen); #ifdef PDF_ENABLE_V8 // Function: FPDF_GetRecommendedV8Flags // Returns a space-separated string of command line flags that are // recommended to be passed into V8 via V8::SetFlagsFromString() // prior to initializing the PDFium library. // Parameters: // None. // Return value: // NUL-terminated string of the form "--flag1 --flag2". // The caller must not attempt to modify or free the result. FPDF_EXPORT const char* FPDF_CALLCONV FPDF_GetRecommendedV8Flags(); // Experimental API. // Function: FPDF_GetArrayBufferAllocatorSharedInstance() // Helper function for initializing V8 isolates that will // use PDFium's internal memory management. // Parameters: // None. // Return Value: // Pointer to a suitable v8::ArrayBuffer::Allocator, returned // as void for C compatibility. // Notes: // Use is optional, but allows external creation of isolates // matching the ones PDFium will make when none is provided // via |FPDF_LIBRARY_CONFIG::m_pIsolate|. // // Can only be called when the library is in an uninitialized or // destroyed state. FPDF_EXPORT void* FPDF_CALLCONV FPDF_GetArrayBufferAllocatorSharedInstance(); #endif // PDF_ENABLE_V8 #ifdef PDF_ENABLE_XFA // Function: FPDF_BStr_Init // Helper function to initialize a FPDF_BSTR. FPDF_EXPORT FPDF_RESULT FPDF_CALLCONV FPDF_BStr_Init(FPDF_BSTR* bstr); // Function: FPDF_BStr_Set // Helper function to copy string data into the FPDF_BSTR. FPDF_EXPORT FPDF_RESULT FPDF_CALLCONV FPDF_BStr_Set(FPDF_BSTR* bstr, const char* cstr, int length); // Function: FPDF_BStr_Clear // Helper function to clear a FPDF_BSTR. FPDF_EXPORT FPDF_RESULT FPDF_CALLCONV FPDF_BStr_Clear(FPDF_BSTR* bstr); #endif // PDF_ENABLE_XFA #ifdef __cplusplus } #endif #endif // PUBLIC_FPDFVIEW_H_ ================================================ FILE: external/pdfium/linux-x64/include/fpdfview.h.orig ================================================ // Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com // This is the main header file for embedders of PDFium. It provides APIs to // initialize the library, load documents, and render pages, amongst other // things. // // NOTE: None of the PDFium APIs are thread-safe. They expect to be called // from a single thread. Barring that, embedders are required to ensure (via // a mutex or similar) that only a single PDFium call can be made at a time. // // NOTE: External docs refer to this file as "fpdfview.h", so do not rename // despite lack of consistency with other public files. #ifndef PUBLIC_FPDFVIEW_H_ #define PUBLIC_FPDFVIEW_H_ // clang-format off #include #if defined(_WIN32) && !defined(__WINDOWS__) #include #endif #ifdef PDF_ENABLE_XFA // PDF_USE_XFA is set in confirmation that this version of PDFium can support // XFA forms as requested by the PDF_ENABLE_XFA setting. #define PDF_USE_XFA #endif // PDF_ENABLE_XFA // PDF object types #define FPDF_OBJECT_UNKNOWN 0 #define FPDF_OBJECT_BOOLEAN 1 #define FPDF_OBJECT_NUMBER 2 #define FPDF_OBJECT_STRING 3 #define FPDF_OBJECT_NAME 4 #define FPDF_OBJECT_ARRAY 5 #define FPDF_OBJECT_DICTIONARY 6 #define FPDF_OBJECT_STREAM 7 #define FPDF_OBJECT_NULLOBJ 8 #define FPDF_OBJECT_REFERENCE 9 // PDF text rendering modes typedef enum { FPDF_TEXTRENDERMODE_UNKNOWN = -1, FPDF_TEXTRENDERMODE_FILL = 0, FPDF_TEXTRENDERMODE_STROKE = 1, FPDF_TEXTRENDERMODE_FILL_STROKE = 2, FPDF_TEXTRENDERMODE_INVISIBLE = 3, FPDF_TEXTRENDERMODE_FILL_CLIP = 4, FPDF_TEXTRENDERMODE_STROKE_CLIP = 5, FPDF_TEXTRENDERMODE_FILL_STROKE_CLIP = 6, FPDF_TEXTRENDERMODE_CLIP = 7, FPDF_TEXTRENDERMODE_LAST = FPDF_TEXTRENDERMODE_CLIP, } FPDF_TEXT_RENDERMODE; // PDF types - use incomplete types (never completed) to force API type safety. typedef struct fpdf_action_t__* FPDF_ACTION; typedef struct fpdf_annotation_t__* FPDF_ANNOTATION; typedef struct fpdf_attachment_t__* FPDF_ATTACHMENT; typedef struct fpdf_avail_t__* FPDF_AVAIL; typedef struct fpdf_bitmap_t__* FPDF_BITMAP; typedef struct fpdf_bookmark_t__* FPDF_BOOKMARK; typedef struct fpdf_clippath_t__* FPDF_CLIPPATH; typedef struct fpdf_dest_t__* FPDF_DEST; typedef struct fpdf_document_t__* FPDF_DOCUMENT; typedef struct fpdf_font_t__* FPDF_FONT; typedef struct fpdf_form_handle_t__* FPDF_FORMHANDLE; typedef const struct fpdf_glyphpath_t__* FPDF_GLYPHPATH; typedef struct fpdf_javascript_action_t* FPDF_JAVASCRIPT_ACTION; typedef struct fpdf_link_t__* FPDF_LINK; typedef struct fpdf_page_t__* FPDF_PAGE; typedef struct fpdf_pagelink_t__* FPDF_PAGELINK; typedef struct fpdf_pageobject_t__* FPDF_PAGEOBJECT; // (text, path, etc.) typedef struct fpdf_pageobjectmark_t__* FPDF_PAGEOBJECTMARK; typedef const struct fpdf_pagerange_t__* FPDF_PAGERANGE; typedef const struct fpdf_pathsegment_t* FPDF_PATHSEGMENT; typedef struct fpdf_schhandle_t__* FPDF_SCHHANDLE; typedef const struct fpdf_signature_t__* FPDF_SIGNATURE; typedef void* FPDF_SKIA_CANVAS; // Passed into Skia as an SkCanvas. typedef struct fpdf_structelement_t__* FPDF_STRUCTELEMENT; typedef const struct fpdf_structelement_attr_t__* FPDF_STRUCTELEMENT_ATTR; typedef const struct fpdf_structelement_attr_value_t__* FPDF_STRUCTELEMENT_ATTR_VALUE; typedef struct fpdf_structtree_t__* FPDF_STRUCTTREE; typedef struct fpdf_textpage_t__* FPDF_TEXTPAGE; typedef struct fpdf_widget_t__* FPDF_WIDGET; typedef struct fpdf_xobject_t__* FPDF_XOBJECT; // Basic data types typedef int FPDF_BOOL; typedef int FPDF_RESULT; typedef unsigned long FPDF_DWORD; typedef float FS_FLOAT; // Duplex types typedef enum _FPDF_DUPLEXTYPE_ { DuplexUndefined = 0, Simplex, DuplexFlipShortEdge, DuplexFlipLongEdge } FPDF_DUPLEXTYPE; // String types typedef unsigned short FPDF_WCHAR; // The public PDFium API uses three types of strings: byte string, wide string // (UTF-16LE encoded), and platform dependent string. // Public PDFium API type for byte strings. typedef const char* FPDF_BYTESTRING; // The public PDFium API always uses UTF-16LE encoded wide strings, each // character uses 2 bytes (except surrogation), with the low byte first. typedef const FPDF_WCHAR* FPDF_WIDESTRING; // Structure for persisting a string beyond the duration of a callback. // Note: although represented as a char*, string may be interpreted as // a UTF-16LE formated string. Used only by XFA callbacks. typedef struct FPDF_BSTR_ { char* str; // String buffer, manipulate only with FPDF_BStr_* methods. int len; // Length of the string, in bytes. } FPDF_BSTR; // For Windows programmers: In most cases it's OK to treat FPDF_WIDESTRING as a // Windows unicode string, however, special care needs to be taken if you // expect to process Unicode larger than 0xffff. // // For Linux/Unix programmers: most compiler/library environments use 4 bytes // for a Unicode character, and you have to convert between FPDF_WIDESTRING and // system wide string by yourself. typedef const char* FPDF_STRING; // Matrix for transformation, in the form [a b c d e f], equivalent to: // | a b 0 | // | c d 0 | // | e f 1 | // // Translation is performed with [1 0 0 1 tx ty]. // Scaling is performed with [sx 0 0 sy 0 0]. // See PDF Reference 1.7, 4.2.2 Common Transformations for more. typedef struct _FS_MATRIX_ { float a; float b; float c; float d; float e; float f; } FS_MATRIX; // Rectangle area(float) in device or page coordinate system. typedef struct _FS_RECTF_ { // The x-coordinate of the left-top corner. float left; // The y-coordinate of the left-top corner. float top; // The x-coordinate of the right-bottom corner. float right; // The y-coordinate of the right-bottom corner. float bottom; } * FS_LPRECTF, FS_RECTF; // Const Pointer to FS_RECTF structure. typedef const FS_RECTF* FS_LPCRECTF; // Rectangle size. Coordinate system agnostic. typedef struct FS_SIZEF_ { float width; float height; } * FS_LPSIZEF, FS_SIZEF; // Const Pointer to FS_SIZEF structure. typedef const FS_SIZEF* FS_LPCSIZEF; // 2D Point. Coordinate system agnostic. typedef struct FS_POINTF_ { float x; float y; } * FS_LPPOINTF, FS_POINTF; // Const Pointer to FS_POINTF structure. typedef const FS_POINTF* FS_LPCPOINTF; typedef struct _FS_QUADPOINTSF { FS_FLOAT x1; FS_FLOAT y1; FS_FLOAT x2; FS_FLOAT y2; FS_FLOAT x3; FS_FLOAT y3; FS_FLOAT x4; FS_FLOAT y4; } FS_QUADPOINTSF; // Annotation enums. typedef int FPDF_ANNOTATION_SUBTYPE; typedef int FPDF_ANNOT_APPEARANCEMODE; // Dictionary value types. typedef int FPDF_OBJECT_TYPE; #if defined(COMPONENT_BUILD) // FPDF_EXPORT should be consistent with |export| in the pdfium_fuzzer // template in testing/fuzzers/BUILD.gn. #if defined(WIN32) #if defined(FPDF_IMPLEMENTATION) #define FPDF_EXPORT __declspec(dllexport) #else #define FPDF_EXPORT __declspec(dllimport) #endif // defined(FPDF_IMPLEMENTATION) #else #if defined(FPDF_IMPLEMENTATION) #define FPDF_EXPORT __attribute__((visibility("default"))) #else #define FPDF_EXPORT #endif // defined(FPDF_IMPLEMENTATION) #endif // defined(WIN32) #else #define FPDF_EXPORT #endif // defined(COMPONENT_BUILD) #if defined(WIN32) && defined(FPDFSDK_EXPORTS) #define FPDF_CALLCONV __stdcall #else #define FPDF_CALLCONV #endif // Exported Functions #ifdef __cplusplus extern "C" { #endif // PDF renderer types - Experimental. // Selection of 2D graphics library to use for rendering to FPDF_BITMAPs. typedef enum { // Anti-Grain Geometry - https://sourceforge.net/projects/agg/ FPDF_RENDERERTYPE_AGG = 0, // Skia - https://skia.org/ FPDF_RENDERERTYPE_SKIA = 1, } FPDF_RENDERER_TYPE; // PDF font library types - Experimental. // Selection of font backend library to use. typedef enum { // FreeType - https://freetype.org/ FPDF_FONTBACKENDTYPE_FREETYPE = 0, // Fontations - https://github.com/googlefonts/fontations/ FPDF_FONTBACKENDTYPE_FONTATIONS = 1, } FPDF_FONT_BACKEND_TYPE; // Process-wide options for initializing the library. typedef struct FPDF_LIBRARY_CONFIG_ { // Version number of the interface. Currently must be 2. // Support for version 1 will be deprecated in the future. int version; // Array of paths to scan in place of the defaults when using built-in // FXGE font loading code. The array is terminated by a NULL pointer. // The Array may be NULL itself to use the default paths. May be ignored // entirely depending upon the platform. const char** m_pUserFontPaths; // Version 2. // Pointer to the v8::Isolate to use, or NULL to force PDFium to create one. void* m_pIsolate; // The embedder data slot to use in the v8::Isolate to store PDFium's // per-isolate data. The value needs to be in the range // [0, |v8::Internals::kNumIsolateDataLots|). Note that 0 is fine for most // embedders. unsigned int m_v8EmbedderSlot; // Version 3 - Experimental. // Pointer to the V8::Platform to use. void* m_pPlatform; // Version 4 - Experimental. // Explicit specification of 2D graphics rendering library to use. // |m_RendererType| must be a valid value for |FPDF_LIBRARY_CONFIG| versions // of this level or higher, or else the initialization will fail with an // immediate crash. // Note that use of a specified |FPDF_RENDERER_TYPE| value for which the // corresponding 2D graphics rendering library is not included in the build // will similarly fail with an immediate crash. FPDF_RENDERER_TYPE m_RendererType; // Version 5 - Experimental. // Explicit specification of font library to use when |m_RendererType| is set // to |FPDF_RENDERERTYPE_SKIA|. // |m_FontLibraryType| must be a valid value for |FPDF_LIBRARY_CONFIG| // versions of this level or higher, or else the initialization will fail with // an immediate crash. // Note that use of a specified |FPDF_FONT_BACKEND_TYPE| value for which the // corresponding font library is not included in the build will similarly fail // with an immediate crash. FPDF_FONT_BACKEND_TYPE m_FontLibraryType; } FPDF_LIBRARY_CONFIG; // Function: FPDF_InitLibraryWithConfig // Initialize the PDFium library and allocate global resources for it. // Parameters: // config - configuration information as above. // Return value: // None. // Comments: // You have to call this function before you can call any PDF // processing functions. FPDF_EXPORT void FPDF_CALLCONV FPDF_InitLibraryWithConfig(const FPDF_LIBRARY_CONFIG* config); // Function: FPDF_InitLibrary // Initialize the PDFium library (alternative form). // Parameters: // None // Return value: // None. // Comments: // Convenience function to call FPDF_InitLibraryWithConfig() with a // default configuration for backwards compatibility purposes. New // code should call FPDF_InitLibraryWithConfig() instead. This will // be deprecated in the future. FPDF_EXPORT void FPDF_CALLCONV FPDF_InitLibrary(); // Function: FPDF_DestroyLibrary // Release global resources allocated to the PDFium library by // FPDF_InitLibrary() or FPDF_InitLibraryWithConfig(). // Parameters: // None. // Return value: // None. // Comments: // After this function is called, you must not call any PDF // processing functions. // // Calling this function does not automatically close other // objects. It is recommended to close other objects before // closing the library with this function. FPDF_EXPORT void FPDF_CALLCONV FPDF_DestroyLibrary(); // Policy for accessing the local machine time. #define FPDF_POLICY_MACHINETIME_ACCESS 0 // Function: FPDF_SetSandBoxPolicy // Set the policy for the sandbox environment. // Parameters: // policy - The specified policy for setting, for example: // FPDF_POLICY_MACHINETIME_ACCESS. // enable - True to enable, false to disable the policy. // Return value: // None. FPDF_EXPORT void FPDF_CALLCONV FPDF_SetSandBoxPolicy(FPDF_DWORD policy, FPDF_BOOL enable); #if defined(_WIN32) // Experimental API. // Function: FPDF_SetPrintMode // Set printing mode when printing on Windows. // Parameters: // mode - FPDF_PRINTMODE_EMF to output EMF (default) // FPDF_PRINTMODE_TEXTONLY to output text only (for charstream // devices) // FPDF_PRINTMODE_POSTSCRIPT2 to output level 2 PostScript into // EMF as a series of GDI comments. // FPDF_PRINTMODE_POSTSCRIPT3 to output level 3 PostScript into // EMF as a series of GDI comments. // FPDF_PRINTMODE_POSTSCRIPT2_PASSTHROUGH to output level 2 // PostScript via ExtEscape() in PASSTHROUGH mode. // FPDF_PRINTMODE_POSTSCRIPT3_PASSTHROUGH to output level 3 // PostScript via ExtEscape() in PASSTHROUGH mode. // FPDF_PRINTMODE_EMF_IMAGE_MASKS to output EMF, with more // efficient processing of documents containing image masks. // FPDF_PRINTMODE_POSTSCRIPT3_TYPE42 to output level 3 // PostScript with embedded Type 42 fonts, when applicable, into // EMF as a series of GDI comments. // FPDF_PRINTMODE_POSTSCRIPT3_TYPE42_PASSTHROUGH to output level // 3 PostScript with embedded Type 42 fonts, when applicable, // via ExtEscape() in PASSTHROUGH mode. // Return value: // True if successful, false if unsuccessful (typically invalid input). FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_SetPrintMode(int mode); #endif // defined(_WIN32) // Function: FPDF_LoadDocument // Open and load a PDF document. // Parameters: // file_path - Path to the PDF file (including extension). // password - A string used as the password for the PDF file. // If no password is needed, empty or NULL can be used. // See comments below regarding the encoding. // Return value: // A handle to the loaded document, or NULL on failure. // Comments: // Loaded document can be closed by FPDF_CloseDocument(). // If this function fails, you can use FPDF_GetLastError() to retrieve // the reason why it failed. // // The encoding for |file_path| is UTF-8. // // The encoding for |password| can be either UTF-8 or Latin-1. PDFs, // depending on the security handler revision, will only accept one or // the other encoding. If |password|'s encoding and the PDF's expected // encoding do not match, FPDF_LoadDocument() will automatically // convert |password| to the other encoding. FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV FPDF_LoadDocument(FPDF_STRING file_path, FPDF_BYTESTRING password); // Function: FPDF_LoadMemDocument // Open and load a PDF document from memory. // Parameters: // data_buf - Pointer to a buffer containing the PDF document. // size - Number of bytes in the PDF document. // password - A string used as the password for the PDF file. // If no password is needed, empty or NULL can be used. // Return value: // A handle to the loaded document, or NULL on failure. // Comments: // The memory buffer must remain valid when the document is open. // The loaded document can be closed by FPDF_CloseDocument. // If this function fails, you can use FPDF_GetLastError() to retrieve // the reason why it failed. // // See the comments for FPDF_LoadDocument() regarding the encoding for // |password|. // Notes: // If PDFium is built with the XFA module, the application should call // FPDF_LoadXFA() function after the PDF document loaded to support XFA // fields defined in the fpdfformfill.h file. FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV FPDF_LoadMemDocument(const void* data_buf, int size, FPDF_BYTESTRING password); // Experimental API. // Function: FPDF_LoadMemDocument64 // Open and load a PDF document from memory. // Parameters: // data_buf - Pointer to a buffer containing the PDF document. // size - Number of bytes in the PDF document. // password - A string used as the password for the PDF file. // If no password is needed, empty or NULL can be used. // Return value: // A handle to the loaded document, or NULL on failure. // Comments: // The memory buffer must remain valid when the document is open. // The loaded document can be closed by FPDF_CloseDocument. // If this function fails, you can use FPDF_GetLastError() to retrieve // the reason why it failed. // // See the comments for FPDF_LoadDocument() regarding the encoding for // |password|. // Notes: // If PDFium is built with the XFA module, the application should call // FPDF_LoadXFA() function after the PDF document loaded to support XFA // fields defined in the fpdfformfill.h file. FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV FPDF_LoadMemDocument64(const void* data_buf, size_t size, FPDF_BYTESTRING password); // Structure for custom file access. typedef struct { // File length, in bytes. unsigned long m_FileLen; // A function pointer for getting a block of data from a specific position. // Position is specified by byte offset from the beginning of the file. // The pointer to the buffer is never NULL and the size is never 0. // The position and size will never go out of range of the file length. // It may be possible for PDFium to call this function multiple times for // the same position. // Return value: should be non-zero if successful, zero for error. int (*m_GetBlock)(void* param, unsigned long position, unsigned char* pBuf, unsigned long size); // A custom pointer for all implementation specific data. This pointer will // be used as the first parameter to the m_GetBlock callback. void* m_Param; } FPDF_FILEACCESS; // Structure for file reading or writing (I/O). // // Note: This is a handler and should be implemented by callers, // and is only used from XFA. typedef struct FPDF_FILEHANDLER_ { // User-defined data. // Note: Callers can use this field to track controls. void* clientData; // Callback function to release the current file stream object. // // Parameters: // clientData - Pointer to user-defined data. // Returns: // None. void (*Release)(void* clientData); // Callback function to retrieve the current file stream size. // // Parameters: // clientData - Pointer to user-defined data. // Returns: // Size of file stream. FPDF_DWORD (*GetSize)(void* clientData); // Callback function to read data from the current file stream. // // Parameters: // clientData - Pointer to user-defined data. // offset - Offset position starts from the beginning of file // stream. This parameter indicates reading position. // buffer - Memory buffer to store data which are read from // file stream. This parameter should not be NULL. // size - Size of data which should be read from file stream, // in bytes. The buffer indicated by |buffer| must be // large enough to store specified data. // Returns: // 0 for success, other value for failure. FPDF_RESULT (*ReadBlock)(void* clientData, FPDF_DWORD offset, void* buffer, FPDF_DWORD size); // Callback function to write data into the current file stream. // // Parameters: // clientData - Pointer to user-defined data. // offset - Offset position starts from the beginning of file // stream. This parameter indicates writing position. // buffer - Memory buffer contains data which is written into // file stream. This parameter should not be NULL. // size - Size of data which should be written into file // stream, in bytes. // Returns: // 0 for success, other value for failure. FPDF_RESULT (*WriteBlock)(void* clientData, FPDF_DWORD offset, const void* buffer, FPDF_DWORD size); // Callback function to flush all internal accessing buffers. // // Parameters: // clientData - Pointer to user-defined data. // Returns: // 0 for success, other value for failure. FPDF_RESULT (*Flush)(void* clientData); // Callback function to change file size. // // Description: // This function is called under writing mode usually. Implementer // can determine whether to realize it based on application requests. // Parameters: // clientData - Pointer to user-defined data. // size - New size of file stream, in bytes. // Returns: // 0 for success, other value for failure. FPDF_RESULT (*Truncate)(void* clientData, FPDF_DWORD size); } FPDF_FILEHANDLER; // Function: FPDF_LoadCustomDocument // Load PDF document from a custom access descriptor. // Parameters: // pFileAccess - A structure for accessing the file. // password - Optional password for decrypting the PDF file. // Return value: // A handle to the loaded document, or NULL on failure. // Comments: // The application must keep the file resources |pFileAccess| points to // valid until the returned FPDF_DOCUMENT is closed. |pFileAccess| // itself does not need to outlive the FPDF_DOCUMENT. // // The loaded document can be closed with FPDF_CloseDocument(). // // See the comments for FPDF_LoadDocument() regarding the encoding for // |password|. // Notes: // If PDFium is built with the XFA module, the application should call // FPDF_LoadXFA() function after the PDF document loaded to support XFA // fields defined in the fpdfformfill.h file. FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV FPDF_LoadCustomDocument(FPDF_FILEACCESS* pFileAccess, FPDF_BYTESTRING password); // Function: FPDF_GetFileVersion // Get the file version of the given PDF document. // Parameters: // doc - Handle to a document. // fileVersion - The PDF file version. File version: 14 for 1.4, 15 // for 1.5, ... // Return value: // True if succeeds, false otherwise. // Comments: // If the document was created by FPDF_CreateNewDocument, // then this function will always fail. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_GetFileVersion(FPDF_DOCUMENT doc, int* fileVersion); #define FPDF_ERR_SUCCESS 0 // No error. #define FPDF_ERR_UNKNOWN 1 // Unknown error. #define FPDF_ERR_FILE 2 // File not found or could not be opened. #define FPDF_ERR_FORMAT 3 // File not in PDF format or corrupted. #define FPDF_ERR_PASSWORD 4 // Password required or incorrect password. #define FPDF_ERR_SECURITY 5 // Unsupported security scheme. #define FPDF_ERR_PAGE 6 // Page not found or content error. #ifdef PDF_ENABLE_XFA #define FPDF_ERR_XFALOAD 7 // Load XFA error. #define FPDF_ERR_XFALAYOUT 8 // Layout XFA error. #endif // PDF_ENABLE_XFA // Function: FPDF_GetLastError // Get last error code when a function fails. // Parameters: // None. // Return value: // A 32-bit integer indicating error code as defined above. // Comments: // If the previous SDK call succeeded, the return value of this // function is not defined. This function only works in conjunction // with APIs that mention FPDF_GetLastError() in their documentation. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetLastError(); // Experimental API. // Function: FPDF_DocumentHasValidCrossReferenceTable // Whether the document's cross reference table is valid or not. // Parameters: // document - Handle to a document. Returned by FPDF_LoadDocument. // Return value: // True if the PDF parser did not encounter problems parsing the cross // reference table. False if the parser could not parse the cross // reference table and the table had to be rebuild from other data // within the document. // Comments: // The return value can change over time as the PDF parser evolves. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_DocumentHasValidCrossReferenceTable(FPDF_DOCUMENT document); // Experimental API. // Function: FPDF_GetTrailerEnds // Get the byte offsets of trailer ends. // Parameters: // document - Handle to document. Returned by FPDF_LoadDocument(). // buffer - The address of a buffer that receives the // byte offsets. // length - The size, in ints, of |buffer|. // Return value: // Returns the number of ints in the buffer on success, 0 on error. // // |buffer| is an array of integers that describes the exact byte offsets of the // trailer ends in the document. If |length| is less than the returned length, // or |document| or |buffer| is NULL, |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetTrailerEnds(FPDF_DOCUMENT document, unsigned int* buffer, unsigned long length); // Function: FPDF_GetDocPermissions // Get file permission flags of the document. // Parameters: // document - Handle to a document. Returned by FPDF_LoadDocument. // Return value: // A 32-bit integer indicating permission flags. Please refer to the // PDF Reference for detailed descriptions. If the document is not // protected or was unlocked by the owner, 0xffffffff will be returned. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetDocPermissions(FPDF_DOCUMENT document); // Function: FPDF_GetDocUserPermissions // Get user file permission flags of the document. // Parameters: // document - Handle to a document. Returned by FPDF_LoadDocument. // Return value: // A 32-bit integer indicating permission flags. Please refer to the // PDF Reference for detailed descriptions. If the document is not // protected, 0xffffffff will be returned. Always returns user // permissions, even if the document was unlocked by the owner. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetDocUserPermissions(FPDF_DOCUMENT document); // Function: FPDF_GetSecurityHandlerRevision // Get the revision for the security handler. // Parameters: // document - Handle to a document. Returned by FPDF_LoadDocument. // Return value: // The security handler revision number. Please refer to the PDF // Reference for a detailed description. If the document is not // protected, -1 will be returned. FPDF_EXPORT int FPDF_CALLCONV FPDF_GetSecurityHandlerRevision(FPDF_DOCUMENT document); // Function: FPDF_GetPageCount // Get total number of pages in the document. // Parameters: // document - Handle to document. Returned by FPDF_LoadDocument. // Return value: // Total number of pages in the document. FPDF_EXPORT int FPDF_CALLCONV FPDF_GetPageCount(FPDF_DOCUMENT document); // Function: FPDF_LoadPage // Load a page inside the document. // Parameters: // document - Handle to document. Returned by FPDF_LoadDocument // page_index - Index number of the page. 0 for the first page. // Return value: // A handle to the loaded page, or NULL if page load fails. // Comments: // The loaded page can be rendered to devices using FPDF_RenderPage. // The loaded page can be closed using FPDF_ClosePage. FPDF_EXPORT FPDF_PAGE FPDF_CALLCONV FPDF_LoadPage(FPDF_DOCUMENT document, int page_index); // Experimental API // Function: FPDF_GetPageWidthF // Get page width. // Parameters: // page - Handle to the page. Returned by FPDF_LoadPage(). // Return value: // Page width (excluding non-displayable area) measured in points. // One point is 1/72 inch (around 0.3528 mm). // Comments: // Changing the rotation of |page| affects the return value. FPDF_EXPORT float FPDF_CALLCONV FPDF_GetPageWidthF(FPDF_PAGE page); // Function: FPDF_GetPageWidth // Get page width. // Parameters: // page - Handle to the page. Returned by FPDF_LoadPage. // Return value: // Page width (excluding non-displayable area) measured in points. // One point is 1/72 inch (around 0.3528 mm). // Note: // Prefer FPDF_GetPageWidthF() above. This will be deprecated in the // future. // Comments: // Changing the rotation of |page| affects the return value. FPDF_EXPORT double FPDF_CALLCONV FPDF_GetPageWidth(FPDF_PAGE page); // Experimental API // Function: FPDF_GetPageHeightF // Get page height. // Parameters: // page - Handle to the page. Returned by FPDF_LoadPage(). // Return value: // Page height (excluding non-displayable area) measured in points. // One point is 1/72 inch (around 0.3528 mm) // Comments: // Changing the rotation of |page| affects the return value. FPDF_EXPORT float FPDF_CALLCONV FPDF_GetPageHeightF(FPDF_PAGE page); // Function: FPDF_GetPageHeight // Get page height. // Parameters: // page - Handle to the page. Returned by FPDF_LoadPage. // Return value: // Page height (excluding non-displayable area) measured in points. // One point is 1/72 inch (around 0.3528 mm) // Note: // Prefer FPDF_GetPageHeightF() above. This will be deprecated in the // future. // Comments: // Changing the rotation of |page| affects the return value. FPDF_EXPORT double FPDF_CALLCONV FPDF_GetPageHeight(FPDF_PAGE page); // Experimental API. // Function: FPDF_GetPageBoundingBox // Get the bounding box of the page. This is the intersection between // its media box and its crop box. // Parameters: // page - Handle to the page. Returned by FPDF_LoadPage. // rect - Pointer to a rect to receive the page bounding box. // On an error, |rect| won't be filled. // Return value: // True for success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_GetPageBoundingBox(FPDF_PAGE page, FS_RECTF* rect); // Experimental API. // Function: FPDF_GetPageSizeByIndexF // Get the size of the page at the given index. // Parameters: // document - Handle to document. Returned by FPDF_LoadDocument(). // page_index - Page index, zero for the first page. // size - Pointer to a FS_SIZEF to receive the page size. // (in points). // Return value: // Non-zero for success. 0 for error (document or page not found). FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_GetPageSizeByIndexF(FPDF_DOCUMENT document, int page_index, FS_SIZEF* size); // Function: FPDF_GetPageSizeByIndex // Get the size of the page at the given index. // Parameters: // document - Handle to document. Returned by FPDF_LoadDocument. // page_index - Page index, zero for the first page. // width - Pointer to a double to receive the page width // (in points). // height - Pointer to a double to receive the page height // (in points). // Return value: // Non-zero for success. 0 for error (document or page not found). // Note: // Prefer FPDF_GetPageSizeByIndexF() above. This will be deprecated in // the future. FPDF_EXPORT int FPDF_CALLCONV FPDF_GetPageSizeByIndex(FPDF_DOCUMENT document, int page_index, double* width, double* height); // Page rendering flags. They can be combined with bit-wise OR. // // Set if annotations are to be rendered. #define FPDF_ANNOT 0x01 // Set if using text rendering optimized for LCD display. This flag will only // take effect if anti-aliasing is enabled for text. #define FPDF_LCD_TEXT 0x02 // Don't use the native text output available on some platforms #define FPDF_NO_NATIVETEXT 0x04 // Grayscale output. #define FPDF_GRAYSCALE 0x08 // Obsolete, has no effect, retained for compatibility. #define FPDF_DEBUG_INFO 0x80 // Obsolete, has no effect, retained for compatibility. #define FPDF_NO_CATCH 0x100 // Limit image cache size. #define FPDF_RENDER_LIMITEDIMAGECACHE 0x200 // Always use halftone for image stretching. #define FPDF_RENDER_FORCEHALFTONE 0x400 // Render for printing. #define FPDF_PRINTING 0x800 // Set to disable anti-aliasing on text. This flag will also disable LCD // optimization for text rendering. #define FPDF_RENDER_NO_SMOOTHTEXT 0x1000 // Set to disable anti-aliasing on images. #define FPDF_RENDER_NO_SMOOTHIMAGE 0x2000 // Set to disable anti-aliasing on paths. #define FPDF_RENDER_NO_SMOOTHPATH 0x4000 // Set whether to render in a reverse Byte order, this flag is only used when // rendering to a bitmap. #define FPDF_REVERSE_BYTE_ORDER 0x10 // Set whether fill paths need to be stroked. This flag is only used when // FPDF_COLORSCHEME is passed in, since with a single fill color for paths the // boundaries of adjacent fill paths are less visible. #define FPDF_CONVERT_FILL_TO_STROKE 0x20 // Struct for color scheme. // Each should be a 32-bit value specifying the color, in 8888 ARGB format. typedef struct FPDF_COLORSCHEME_ { FPDF_DWORD path_fill_color; FPDF_DWORD path_stroke_color; FPDF_DWORD text_fill_color; FPDF_DWORD text_stroke_color; } FPDF_COLORSCHEME; #ifdef _WIN32 // Function: FPDF_RenderPage // Render contents of a page to a device (screen, bitmap, or printer). // This function is only supported on Windows. // Parameters: // dc - Handle to the device context. // page - Handle to the page. Returned by FPDF_LoadPage. // start_x - Left pixel position of the display area in // device coordinates. // start_y - Top pixel position of the display area in device // coordinates. // size_x - Horizontal size (in pixels) for displaying the page. // size_y - Vertical size (in pixels) for displaying the page. // rotate - Page orientation: // 0 (normal) // 1 (rotated 90 degrees clockwise) // 2 (rotated 180 degrees) // 3 (rotated 90 degrees counter-clockwise) // flags - 0 for normal display, or combination of flags // defined above. // Return value: // Returns true if the page is rendered successfully, false otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_RenderPage(HDC dc, FPDF_PAGE page, int start_x, int start_y, int size_x, int size_y, int rotate, int flags); #endif // Function: FPDF_RenderPageBitmap // Render contents of a page to a device independent bitmap. // Parameters: // bitmap - Handle to the device independent bitmap (as the // output buffer). The bitmap handle can be created // by FPDFBitmap_Create or retrieved from an image // object by FPDFImageObj_GetBitmap. // page - Handle to the page. Returned by FPDF_LoadPage // start_x - Left pixel position of the display area in // bitmap coordinates. // start_y - Top pixel position of the display area in bitmap // coordinates. // size_x - Horizontal size (in pixels) for displaying the page. // size_y - Vertical size (in pixels) for displaying the page. // rotate - Page orientation: // 0 (normal) // 1 (rotated 90 degrees clockwise) // 2 (rotated 180 degrees) // 3 (rotated 90 degrees counter-clockwise) // flags - 0 for normal display, or combination of the Page // Rendering flags defined above. With the FPDF_ANNOT // flag, it renders all annotations that do not require // user-interaction, which are all annotations except // widget and popup annotations. // Return value: // None. FPDF_EXPORT void FPDF_CALLCONV FPDF_RenderPageBitmap(FPDF_BITMAP bitmap, FPDF_PAGE page, int start_x, int start_y, int size_x, int size_y, int rotate, int flags); // Function: FPDF_RenderPageBitmapWithMatrix // Render contents of a page to a device independent bitmap. // Parameters: // bitmap - Handle to the device independent bitmap (as the // output buffer). The bitmap handle can be created // by FPDFBitmap_Create or retrieved by // FPDFImageObj_GetBitmap. // page - Handle to the page. Returned by FPDF_LoadPage. // matrix - The transform matrix, which must be invertible. // See PDF Reference 1.7, 4.2.2 Common Transformations. // clipping - The rect to clip to in device coords. // flags - 0 for normal display, or combination of the Page // Rendering flags defined above. With the FPDF_ANNOT // flag, it renders all annotations that do not require // user-interaction, which are all annotations except // widget and popup annotations. // Return value: // None. Note that behavior is undefined if det of |matrix| is 0. FPDF_EXPORT void FPDF_CALLCONV FPDF_RenderPageBitmapWithMatrix(FPDF_BITMAP bitmap, FPDF_PAGE page, const FS_MATRIX* matrix, const FS_RECTF* clipping, int flags); #if defined(PDF_USE_SKIA) // Experimental API. // Function: FPDF_RenderPageSkia // Render contents of a page to a Skia SkCanvas. // Parameters: // canvas - SkCanvas to render to. // page - Handle to the page. // size_x - Horizontal size (in pixels) for displaying the page. // size_y - Vertical size (in pixels) for displaying the page. // Return value: // None. FPDF_EXPORT void FPDF_CALLCONV FPDF_RenderPageSkia(FPDF_SKIA_CANVAS canvas, FPDF_PAGE page, int size_x, int size_y); #endif // Function: FPDF_ClosePage // Close a loaded PDF page. // Parameters: // page - Handle to the loaded page. // Return value: // None. FPDF_EXPORT void FPDF_CALLCONV FPDF_ClosePage(FPDF_PAGE page); // Function: FPDF_CloseDocument // Close a loaded PDF document. // Parameters: // document - Handle to the loaded document. // Return value: // None. FPDF_EXPORT void FPDF_CALLCONV FPDF_CloseDocument(FPDF_DOCUMENT document); // Function: FPDF_DeviceToPage // Convert the screen coordinates of a point to page coordinates. // Parameters: // page - Handle to the page. Returned by FPDF_LoadPage. // start_x - Left pixel position of the display area in // device coordinates. // start_y - Top pixel position of the display area in device // coordinates. // size_x - Horizontal size (in pixels) for displaying the page. // size_y - Vertical size (in pixels) for displaying the page. // rotate - Page orientation: // 0 (normal) // 1 (rotated 90 degrees clockwise) // 2 (rotated 180 degrees) // 3 (rotated 90 degrees counter-clockwise) // device_x - X value in device coordinates to be converted. // device_y - Y value in device coordinates to be converted. // page_x - A pointer to a double receiving the converted X // value in page coordinates. // page_y - A pointer to a double receiving the converted Y // value in page coordinates. // Return value: // Returns true if the conversion succeeds, and |page_x| and |page_y| // successfully receives the converted coordinates. // Comments: // The page coordinate system has its origin at the left-bottom corner // of the page, with the X-axis on the bottom going to the right, and // the Y-axis on the left side going up. // // NOTE: this coordinate system can be altered when you zoom, scroll, // or rotate a page, however, a point on the page should always have // the same coordinate values in the page coordinate system. // // The device coordinate system is device dependent. For screen device, // its origin is at the left-top corner of the window. However this // origin can be altered by the Windows coordinate transformation // utilities. // // You must make sure the start_x, start_y, size_x, size_y // and rotate parameters have exactly same values as you used in // the FPDF_RenderPage() function call. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_DeviceToPage(FPDF_PAGE page, int start_x, int start_y, int size_x, int size_y, int rotate, int device_x, int device_y, double* page_x, double* page_y); // Function: FPDF_PageToDevice // Convert the page coordinates of a point to screen coordinates. // Parameters: // page - Handle to the page. Returned by FPDF_LoadPage. // start_x - Left pixel position of the display area in // device coordinates. // start_y - Top pixel position of the display area in device // coordinates. // size_x - Horizontal size (in pixels) for displaying the page. // size_y - Vertical size (in pixels) for displaying the page. // rotate - Page orientation: // 0 (normal) // 1 (rotated 90 degrees clockwise) // 2 (rotated 180 degrees) // 3 (rotated 90 degrees counter-clockwise) // page_x - X value in page coordinates. // page_y - Y value in page coordinate. // device_x - A pointer to an integer receiving the result X // value in device coordinates. // device_y - A pointer to an integer receiving the result Y // value in device coordinates. // Return value: // Returns true if the conversion succeeds, and |device_x| and // |device_y| successfully receives the converted coordinates. // Comments: // See comments for FPDF_DeviceToPage(). FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_PageToDevice(FPDF_PAGE page, int start_x, int start_y, int size_x, int size_y, int rotate, double page_x, double page_y, int* device_x, int* device_y); // Function: FPDFBitmap_Create // Create a device independent bitmap (FXDIB). // Parameters: // width - The number of pixels in width for the bitmap. // Must be greater than 0. // height - The number of pixels in height for the bitmap. // Must be greater than 0. // alpha - A flag indicating whether the alpha channel is used. // Non-zero for using alpha, zero for not using. // Return value: // The created bitmap handle, or NULL if a parameter error or out of // memory. // Comments: // The bitmap always uses 4 bytes per pixel. The first byte is always // double word aligned. // // The byte order is BGRx (the last byte unused if no alpha channel) or // BGRA. // // The pixels in a horizontal line are stored side by side, with the // left most pixel stored first (with lower memory address). // Each line uses width * 4 bytes. // // Lines are stored one after another, with the top most line stored // first. There is no gap between adjacent lines. // // This function allocates enough memory for holding all pixels in the // bitmap, but it doesn't initialize the buffer. Applications can use // FPDFBitmap_FillRect() to fill the bitmap using any color. If the OS // allows it, this function can allocate up to 4 GB of memory. FPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV FPDFBitmap_Create(int width, int height, int alpha); // More DIB formats // Unknown or unsupported format. // All of the colors are listed in order of LSB to MSB. #define FPDFBitmap_Unknown 0 // Gray scale bitmap, one byte per pixel. #define FPDFBitmap_Gray 1 // 3 bytes per pixel, byte order: blue, green, red. #define FPDFBitmap_BGR 2 // 4 bytes per pixel, byte order: blue, green, red, unused. #define FPDFBitmap_BGRx 3 // 4 bytes per pixel, byte order: blue, green, red, alpha. // Pixel components are independent of alpha. #define FPDFBitmap_BGRA 4 // 4 bytes per pixel, byte order: blue, green, red, alpha. // Pixel components are premultiplied by alpha. // Note that this is experimental and only supported when rendering with // |FPDF_RENDERER_TYPE| is set to |FPDF_RENDERERTYPE_SKIA|. #define FPDFBitmap_BGRA_Premul 5 // Function: FPDFBitmap_CreateEx // Create a device independent bitmap (FXDIB) // Parameters: // width - The number of pixels in width for the bitmap. // Must be greater than 0. // height - The number of pixels in height for the bitmap. // Must be greater than 0. // format - A number indicating for bitmap format, as defined // above. // first_scan - A pointer to the first byte of the first line if // using an external buffer. If this parameter is NULL, // then a new buffer will be created. // stride - Number of bytes for each scan line. The value must // be 0 or greater. When the value is 0, // FPDFBitmap_CreateEx() will automatically calculate // the appropriate value using |width| and |format|. // When using an external buffer, it is recommended for // the caller to pass in the value. // When not using an external buffer, it is recommended // for the caller to pass in 0. // Return value: // The bitmap handle, or NULL if parameter error or out of memory. // Comments: // Similar to FPDFBitmap_Create function, but allows for more formats // and an external buffer is supported. The bitmap created by this // function can be used in any place that a FPDF_BITMAP handle is // required. // // If an external buffer is used, then the caller should destroy the // buffer. FPDFBitmap_Destroy() will not destroy the buffer. // // It is recommended to use FPDFBitmap_GetStride() to get the stride // value. FPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV FPDFBitmap_CreateEx(int width, int height, int format, void* first_scan, int stride); // Function: FPDFBitmap_GetFormat // Get the format of the bitmap. // Parameters: // bitmap - Handle to the bitmap. Returned by FPDFBitmap_Create // or FPDFImageObj_GetBitmap. // Return value: // The format of the bitmap. // Comments: // Only formats supported by FPDFBitmap_CreateEx are supported by this // function; see the list of such formats above. FPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetFormat(FPDF_BITMAP bitmap); // Function: FPDFBitmap_FillRect // Fill a rectangle in a bitmap. // Parameters: // bitmap - The handle to the bitmap. Returned by // FPDFBitmap_Create. // left - The left position. Starting from 0 at the // left-most pixel. // top - The top position. Starting from 0 at the // top-most line. // width - Width in pixels to be filled. // height - Height in pixels to be filled. // color - A 32-bit value specifing the color, in 8888 ARGB // format. // Return value: // Returns whether the operation succeeded or not. // Comments: // This function sets the color and (optionally) alpha value in the // specified region of the bitmap. // // NOTE: If the alpha channel is used, this function does NOT // composite the background with the source color, instead the // background will be replaced by the source color and the alpha. // // If the alpha channel is not used, the alpha parameter is ignored. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFBitmap_FillRect(FPDF_BITMAP bitmap, int left, int top, int width, int height, FPDF_DWORD color); // Function: FPDFBitmap_GetBuffer // Get data buffer of a bitmap. // Parameters: // bitmap - Handle to the bitmap. Returned by FPDFBitmap_Create // or FPDFImageObj_GetBitmap. // Return value: // The pointer to the first byte of the bitmap buffer. // Comments: // The stride may be more than width * number of bytes per pixel // // Applications can use this function to get the bitmap buffer pointer, // then manipulate any color and/or alpha values for any pixels in the // bitmap. // // Use FPDFBitmap_GetFormat() to find out the format of the data. FPDF_EXPORT void* FPDF_CALLCONV FPDFBitmap_GetBuffer(FPDF_BITMAP bitmap); // Function: FPDFBitmap_GetWidth // Get width of a bitmap. // Parameters: // bitmap - Handle to the bitmap. Returned by FPDFBitmap_Create // or FPDFImageObj_GetBitmap. // Return value: // The width of the bitmap in pixels. FPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetWidth(FPDF_BITMAP bitmap); // Function: FPDFBitmap_GetHeight // Get height of a bitmap. // Parameters: // bitmap - Handle to the bitmap. Returned by FPDFBitmap_Create // or FPDFImageObj_GetBitmap. // Return value: // The height of the bitmap in pixels. FPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetHeight(FPDF_BITMAP bitmap); // Function: FPDFBitmap_GetStride // Get number of bytes for each line in the bitmap buffer. // Parameters: // bitmap - Handle to the bitmap. Returned by FPDFBitmap_Create // or FPDFImageObj_GetBitmap. // Return value: // The number of bytes for each line in the bitmap buffer. // Comments: // The stride may be more than width * number of bytes per pixel. FPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetStride(FPDF_BITMAP bitmap); // Function: FPDFBitmap_Destroy // Destroy a bitmap and release all related buffers. // Parameters: // bitmap - Handle to the bitmap. Returned by FPDFBitmap_Create // or FPDFImageObj_GetBitmap. // Return value: // None. // Comments: // This function will not destroy any external buffers provided when // the bitmap was created. FPDF_EXPORT void FPDF_CALLCONV FPDFBitmap_Destroy(FPDF_BITMAP bitmap); // Function: FPDF_VIEWERREF_GetPrintScaling // Whether the PDF document prefers to be scaled or not. // Parameters: // document - Handle to the loaded document. // Return value: // None. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_VIEWERREF_GetPrintScaling(FPDF_DOCUMENT document); // Function: FPDF_VIEWERREF_GetNumCopies // Returns the number of copies to be printed. // Parameters: // document - Handle to the loaded document. // Return value: // The number of copies to be printed. FPDF_EXPORT int FPDF_CALLCONV FPDF_VIEWERREF_GetNumCopies(FPDF_DOCUMENT document); // Function: FPDF_VIEWERREF_GetPrintPageRange // Page numbers to initialize print dialog box when file is printed. // Parameters: // document - Handle to the loaded document. // Return value: // The print page range to be used for printing. FPDF_EXPORT FPDF_PAGERANGE FPDF_CALLCONV FPDF_VIEWERREF_GetPrintPageRange(FPDF_DOCUMENT document); // Experimental API. // Function: FPDF_VIEWERREF_GetPrintPageRangeCount // Returns the number of elements in a FPDF_PAGERANGE. // Parameters: // pagerange - Handle to the page range. // Return value: // The number of elements in the page range. Returns 0 on error. FPDF_EXPORT size_t FPDF_CALLCONV FPDF_VIEWERREF_GetPrintPageRangeCount(FPDF_PAGERANGE pagerange); // Experimental API. // Function: FPDF_VIEWERREF_GetPrintPageRangeElement // Returns an element from a FPDF_PAGERANGE. // Parameters: // pagerange - Handle to the page range. // index - Index of the element. // Return value: // The value of the element in the page range at a given index. // Returns -1 on error. FPDF_EXPORT int FPDF_CALLCONV FPDF_VIEWERREF_GetPrintPageRangeElement(FPDF_PAGERANGE pagerange, size_t index); // Function: FPDF_VIEWERREF_GetDuplex // Returns the paper handling option to be used when printing from // the print dialog. // Parameters: // document - Handle to the loaded document. // Return value: // The paper handling option to be used when printing. FPDF_EXPORT FPDF_DUPLEXTYPE FPDF_CALLCONV FPDF_VIEWERREF_GetDuplex(FPDF_DOCUMENT document); // Function: FPDF_VIEWERREF_GetName // Gets the contents for a viewer ref, with a given key. The value must // be of type "name". // Parameters: // document - Handle to the loaded document. // key - Name of the key in the viewer pref dictionary, // encoded in UTF-8. // buffer - Caller-allocate buffer to receive the key, or NULL // - to query the required length. // length - Length of the buffer. // Return value: // The number of bytes in the contents, including the NULL terminator. // Thus if the return value is 0, then that indicates an error, such // as when |document| is invalid. If |length| is less than the required // length, or |buffer| is NULL, |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_VIEWERREF_GetName(FPDF_DOCUMENT document, FPDF_BYTESTRING key, char* buffer, unsigned long length); // Function: FPDF_CountNamedDests // Get the count of named destinations in the PDF document. // Parameters: // document - Handle to a document // Return value: // The count of named destinations. FPDF_EXPORT FPDF_DWORD FPDF_CALLCONV FPDF_CountNamedDests(FPDF_DOCUMENT document); // Function: FPDF_GetNamedDestByName // Get a the destination handle for the given name. // Parameters: // document - Handle to the loaded document. // name - The name of a destination. // Return value: // The handle to the destination. FPDF_EXPORT FPDF_DEST FPDF_CALLCONV FPDF_GetNamedDestByName(FPDF_DOCUMENT document, FPDF_BYTESTRING name); // Function: FPDF_GetNamedDest // Get the named destination by index. // Parameters: // document - Handle to a document // index - The index of a named destination. // buffer - The buffer to store the destination name, // used as wchar_t*. // buflen [in/out] - Size of the buffer in bytes on input, // length of the result in bytes on output // or -1 if the buffer is too small. // Return value: // The destination handle for a given index, or NULL if there is no // named destination corresponding to |index|. // Comments: // Call this function twice to get the name of the named destination: // 1) First time pass in |buffer| as NULL and get buflen. // 2) Second time pass in allocated |buffer| and buflen to retrieve // |buffer|, which should be used as wchar_t*. // // If buflen is not sufficiently large, it will be set to -1 upon // return. FPDF_EXPORT FPDF_DEST FPDF_CALLCONV FPDF_GetNamedDest(FPDF_DOCUMENT document, int index, void* buffer, long* buflen); // Experimental API. // Function: FPDF_GetXFAPacketCount // Get the number of valid packets in the XFA entry. // Parameters: // document - Handle to the document. // Return value: // The number of valid packets, or -1 on error. FPDF_EXPORT int FPDF_CALLCONV FPDF_GetXFAPacketCount(FPDF_DOCUMENT document); // Experimental API. // Function: FPDF_GetXFAPacketName // Get the name of a packet in the XFA array. // Parameters: // document - Handle to the document. // index - Index number of the packet. 0 for the first packet. // buffer - Buffer for holding the name of the XFA packet. // buflen - Length of |buffer| in bytes. // Return value: // The length of the packet name in bytes, or 0 on error. // // |document| must be valid and |index| must be in the range [0, N), where N is // the value returned by FPDF_GetXFAPacketCount(). // |buffer| is only modified if it is non-NULL and |buflen| is greater than or // equal to the length of the packet name. The packet name includes a // terminating NUL character. |buffer| is unmodified on error. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetXFAPacketName( FPDF_DOCUMENT document, int index, void* buffer, unsigned long buflen); // Experimental API. // Function: FPDF_GetXFAPacketContent // Get the content of a packet in the XFA array. // Parameters: // document - Handle to the document. // index - Index number of the packet. 0 for the first packet. // buffer - Buffer for holding the content of the XFA packet. // buflen - Length of |buffer| in bytes. // out_buflen - Pointer to the variable that will receive the minimum // buffer size needed to contain the content of the XFA // packet. // Return value: // Whether the operation succeeded or not. // // |document| must be valid and |index| must be in the range [0, N), where N is // the value returned by FPDF_GetXFAPacketCount(). |out_buflen| must not be // NULL. When the aforementioned arguments are valid, the operation succeeds, // and |out_buflen| receives the content size. |buffer| is only modified if // |buffer| is non-null and long enough to contain the content. Callers must // check both the return value and the input |buflen| is no less than the // returned |out_buflen| before using the data in |buffer|. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_GetXFAPacketContent( FPDF_DOCUMENT document, int index, void* buffer, unsigned long buflen, unsigned long* out_buflen); #ifdef PDF_ENABLE_V8 // Function: FPDF_GetRecommendedV8Flags // Returns a space-separated string of command line flags that are // recommended to be passed into V8 via V8::SetFlagsFromString() // prior to initializing the PDFium library. // Parameters: // None. // Return value: // NUL-terminated string of the form "--flag1 --flag2". // The caller must not attempt to modify or free the result. FPDF_EXPORT const char* FPDF_CALLCONV FPDF_GetRecommendedV8Flags(); // Experimental API. // Function: FPDF_GetArrayBufferAllocatorSharedInstance() // Helper function for initializing V8 isolates that will // use PDFium's internal memory management. // Parameters: // None. // Return Value: // Pointer to a suitable v8::ArrayBuffer::Allocator, returned // as void for C compatibility. // Notes: // Use is optional, but allows external creation of isolates // matching the ones PDFium will make when none is provided // via |FPDF_LIBRARY_CONFIG::m_pIsolate|. // // Can only be called when the library is in an uninitialized or // destroyed state. FPDF_EXPORT void* FPDF_CALLCONV FPDF_GetArrayBufferAllocatorSharedInstance(); #endif // PDF_ENABLE_V8 #ifdef PDF_ENABLE_XFA // Function: FPDF_BStr_Init // Helper function to initialize a FPDF_BSTR. FPDF_EXPORT FPDF_RESULT FPDF_CALLCONV FPDF_BStr_Init(FPDF_BSTR* bstr); // Function: FPDF_BStr_Set // Helper function to copy string data into the FPDF_BSTR. FPDF_EXPORT FPDF_RESULT FPDF_CALLCONV FPDF_BStr_Set(FPDF_BSTR* bstr, const char* cstr, int length); // Function: FPDF_BStr_Clear // Helper function to clear a FPDF_BSTR. FPDF_EXPORT FPDF_RESULT FPDF_CALLCONV FPDF_BStr_Clear(FPDF_BSTR* bstr); #endif // PDF_ENABLE_XFA #ifdef __cplusplus } #endif #endif // PUBLIC_FPDFVIEW_H_ ================================================ FILE: external/pdfium/linux-x64/licenses/abseil.txt ================================================ Apache License Version 2.0, January 2004 https://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: external/pdfium/linux-x64/licenses/agg23.txt ================================================ //---------------------------------------------------------------------------- // Anti-Grain Geometry - Version 2.3 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) // // Permission to copy, use, modify, sell and distribute this software // is granted provided this copyright notice appears in all copies. // This software is provided "as is" without express or implied // warranty, and with no claim as to its suitability for any purpose. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- ================================================ FILE: external/pdfium/linux-x64/licenses/fast_float.txt ================================================ MIT License Copyright (c) 2021 The fast_float authors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: external/pdfium/linux-x64/licenses/freetype.txt ================================================ The FreeType Project LICENSE ---------------------------- 2006-Jan-27 Copyright 1996-2002, 2006 by David Turner, Robert Wilhelm, and Werner Lemberg Introduction ============ The FreeType Project is distributed in several archive packages; some of them may contain, in addition to the FreeType font engine, various tools and contributions which rely on, or relate to, the FreeType Project. This license applies to all files found in such packages, and which do not fall under their own explicit license. The license affects thus the FreeType font engine, the test programs, documentation and makefiles, at the very least. This license was inspired by the BSD, Artistic, and IJG (Independent JPEG Group) licenses, which all encourage inclusion and use of free software in commercial and freeware products alike. As a consequence, its main points are that: o We don't promise that this software works. However, we will be interested in any kind of bug reports. (`as is' distribution) o You can use this software for whatever you want, in parts or full form, without having to pay us. (`royalty-free' usage) o You may not pretend that you wrote this software. If you use it, or only parts of it, in a program, you must acknowledge somewhere in your documentation that you have used the FreeType code. (`credits') We specifically permit and encourage the inclusion of this software, with or without modifications, in commercial products. We disclaim all warranties covering The FreeType Project and assume no liability related to The FreeType Project. Finally, many people asked us for a preferred form for a credit/disclaimer to use in compliance with this license. We thus encourage you to use the following text: """ Portions of this software are copyright The FreeType Project (www.freetype.org). All rights reserved. """ Please replace with the value from the FreeType version you actually use. Legal Terms =========== 0. Definitions -------------- Throughout this license, the terms `package', `FreeType Project', and `FreeType archive' refer to the set of files originally distributed by the authors (David Turner, Robert Wilhelm, and Werner Lemberg) as the `FreeType Project', be they named as alpha, beta or final release. `You' refers to the licensee, or person using the project, where `using' is a generic term including compiling the project's source code as well as linking it to form a `program' or `executable'. This program is referred to as `a program using the FreeType engine'. This license applies to all files distributed in the original FreeType Project, including all source code, binaries and documentation, unless otherwise stated in the file in its original, unmodified form as distributed in the original archive. If you are unsure whether or not a particular file is covered by this license, you must contact us to verify this. The FreeType Project is copyright (C) 1996-2000 by David Turner, Robert Wilhelm, and Werner Lemberg. All rights reserved except as specified below. 1. No Warranty -------------- THE FREETYPE PROJECT IS PROVIDED `AS IS' WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL ANY OF THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY DAMAGES CAUSED BY THE USE OR THE INABILITY TO USE, OF THE FREETYPE PROJECT. 2. Redistribution ----------------- This license grants a worldwide, royalty-free, perpetual and irrevocable right and license to use, execute, perform, compile, display, copy, create derivative works of, distribute and sublicense the FreeType Project (in both source and object code forms) and derivative works thereof for any purpose; and to authorize others to exercise some or all of the rights granted herein, subject to the following conditions: o Redistribution of source code must retain this license file (`FTL.TXT') unaltered; any additions, deletions or changes to the original files must be clearly indicated in accompanying documentation. The copyright notices of the unaltered, original files must be preserved in all copies of source files. o Redistribution in binary form must provide a disclaimer that states that the software is based in part of the work of the FreeType Team, in the distribution documentation. We also encourage you to put an URL to the FreeType web page in your documentation, though this isn't mandatory. These conditions apply to any software derived from or based on the FreeType Project, not just the unmodified files. If you use our work, you must acknowledge us. However, no fee need be paid to us. 3. Advertising -------------- Neither the FreeType authors and contributors nor you shall use the name of the other for commercial, advertising, or promotional purposes without specific prior written permission. We suggest, but do not require, that you use one or more of the following phrases to refer to this software in your documentation or advertising materials: `FreeType Project', `FreeType Engine', `FreeType library', or `FreeType Distribution'. As you have not signed this license, you are not required to accept it. However, as the FreeType Project is copyrighted material, only this license, or another one contracted with the authors, grants you the right to use, distribute, and modify it. Therefore, by using, distributing, or modifying the FreeType Project, you indicate that you understand and accept all the terms of this license. 4. Contacts ----------- There are two mailing lists related to FreeType: o freetype@nongnu.org Discusses general use and applications of FreeType, as well as future and wanted additions to the library and distribution. If you are looking for support, start in this list if you haven't found anything to help you in the documentation. o freetype-devel@nongnu.org Discusses bugs, as well as engine internals, design issues, specific licenses, porting, etc. Our home page can be found at http://www.freetype.org --- end of FTL.TXT --- ================================================ FILE: external/pdfium/linux-x64/licenses/icu.txt ================================================ UNICODE LICENSE V3 COPYRIGHT AND PERMISSION NOTICE Copyright © 2016-2025 Unicode, Inc. NOTICE TO USER: Carefully read the following legal agreement. BY DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING DATA FILES, AND/OR SOFTWARE, YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE TERMS AND CONDITIONS OF THIS AGREEMENT. IF YOU DO NOT AGREE, DO NOT DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE THE DATA FILES OR SOFTWARE. Permission is hereby granted, free of charge, to any person obtaining a copy of data files and any associated documentation (the "Data Files") or software and any associated documentation (the "Software") to deal in the Data Files or Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, and/or sell copies of the Data Files or Software, and to permit persons to whom the Data Files or Software are furnished to do so, provided that either (a) this copyright and permission notice appear with all copies of the Data Files or Software, or (b) this copyright and permission notice appear in associated Documentation. THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE DATA FILES OR SOFTWARE. Except as contained in this notice, the name of a copyright holder shall not be used in advertising or otherwise to promote the sale, use or other dealings in these Data Files or Software without prior written authorization of the copyright holder. SPDX-License-Identifier: Unicode-3.0 ---------------------------------------------------------------------- Third-Party Software Licenses This section contains third-party software notices and/or additional terms for licensed third-party software components included within ICU libraries. ---------------------------------------------------------------------- ICU License - ICU 1.8.1 to ICU 57.1 COPYRIGHT AND PERMISSION NOTICE Copyright (c) 1995-2016 International Business Machines Corporation and others All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, provided that the above copyright notice(s) and this permission notice appear in all copies of the Software and that both the above copyright notice(s) and this permission notice appear in supporting documentation. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. Except as contained in this notice, the name of a copyright holder shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization of the copyright holder. All trademarks and registered trademarks mentioned herein are the property of their respective owners. ---------------------------------------------------------------------- Chinese/Japanese Word Break Dictionary Data (cjdict.txt) # The Google Chrome software developed by Google is licensed under # the BSD license. Other software included in this distribution is # provided under other licenses, as set forth below. # # The BSD License # http://opensource.org/licenses/bsd-license.php # Copyright (C) 2006-2008, Google Inc. # # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # Redistributions of source code must retain the above copyright notice, # this list of conditions and the following disclaimer. # Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided with # the distribution. # Neither the name of Google Inc. nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. # # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND # CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR # BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # # The word list in cjdict.txt are generated by combining three word lists # listed below with further processing for compound word breaking. The # frequency is generated with an iterative training against Google web # corpora. # # * Libtabe (Chinese) # - https://sourceforge.net/project/?group_id=1519 # - Its license terms and conditions are shown below. # # * IPADIC (Japanese) # - http://chasen.aist-nara.ac.jp/chasen/distribution.html # - Its license terms and conditions are shown below. # # ---------COPYING.libtabe ---- BEGIN-------------------- # # /* # * Copyright (c) 1999 TaBE Project. # * Copyright (c) 1999 Pai-Hsiang Hsiao. # * All rights reserved. # * # * Redistribution and use in source and binary forms, with or without # * modification, are permitted provided that the following conditions # * are met: # * # * . Redistributions of source code must retain the above copyright # * notice, this list of conditions and the following disclaimer. # * . Redistributions in binary form must reproduce the above copyright # * notice, this list of conditions and the following disclaimer in # * the documentation and/or other materials provided with the # * distribution. # * . Neither the name of the TaBE Project nor the names of its # * contributors may be used to endorse or promote products derived # * from this software without specific prior written permission. # * # * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # * REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES # * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR # * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, # * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED # * OF THE POSSIBILITY OF SUCH DAMAGE. # */ # # /* # * Copyright (c) 1999 Computer Systems and Communication Lab, # * Institute of Information Science, Academia # * Sinica. All rights reserved. # * # * Redistribution and use in source and binary forms, with or without # * modification, are permitted provided that the following conditions # * are met: # * # * . Redistributions of source code must retain the above copyright # * notice, this list of conditions and the following disclaimer. # * . Redistributions in binary form must reproduce the above copyright # * notice, this list of conditions and the following disclaimer in # * the documentation and/or other materials provided with the # * distribution. # * . Neither the name of the Computer Systems and Communication Lab # * nor the names of its contributors may be used to endorse or # * promote products derived from this software without specific # * prior written permission. # * # * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # * REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES # * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR # * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, # * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED # * OF THE POSSIBILITY OF SUCH DAMAGE. # */ # # Copyright 1996 Chih-Hao Tsai @ Beckman Institute, # University of Illinois # c-tsai4@uiuc.edu http://casper.beckman.uiuc.edu/~c-tsai4 # # ---------------COPYING.libtabe-----END-------------------------------- # # # ---------------COPYING.ipadic-----BEGIN------------------------------- # # Copyright 2000, 2001, 2002, 2003 Nara Institute of Science # and Technology. All Rights Reserved. # # Use, reproduction, and distribution of this software is permitted. # Any copy of this software, whether in its original form or modified, # must include both the above copyright notice and the following # paragraphs. # # Nara Institute of Science and Technology (NAIST), # the copyright holders, disclaims all warranties with regard to this # software, including all implied warranties of merchantability and # fitness, in no event shall NAIST be liable for # any special, indirect or consequential damages or any damages # whatsoever resulting from loss of use, data or profits, whether in an # action of contract, negligence or other tortuous action, arising out # of or in connection with the use or performance of this software. # # A large portion of the dictionary entries # originate from ICOT Free Software. The following conditions for ICOT # Free Software applies to the current dictionary as well. # # Each User may also freely distribute the Program, whether in its # original form or modified, to any third party or parties, PROVIDED # that the provisions of Section 3 ("NO WARRANTY") will ALWAYS appear # on, or be attached to, the Program, which is distributed substantially # in the same form as set out herein and that such intended # distribution, if actually made, will neither violate or otherwise # contravene any of the laws and regulations of the countries having # jurisdiction over the User or the intended distribution itself. # # NO WARRANTY # # The program was produced on an experimental basis in the course of the # research and development conducted during the project and is provided # to users as so produced on an experimental basis. Accordingly, the # program is provided without any warranty whatsoever, whether express, # implied, statutory or otherwise. The term "warranty" used herein # includes, but is not limited to, any warranty of the quality, # performance, merchantability and fitness for a particular purpose of # the program and the nonexistence of any infringement or violation of # any right of any third party. # # Each user of the program will agree and understand, and be deemed to # have agreed and understood, that there is no warranty whatsoever for # the program and, accordingly, the entire risk arising from or # otherwise connected with the program is assumed by the user. # # Therefore, neither ICOT, the copyright holder, or any other # organization that participated in or was otherwise related to the # development of the program and their respective officials, directors, # officers and other employees shall be held liable for any and all # damages, including, without limitation, general, special, incidental # and consequential damages, arising out of or otherwise in connection # with the use or inability to use the program or any product, material # or result produced or otherwise obtained by using the program, # regardless of whether they have been advised of, or otherwise had # knowledge of, the possibility of such damages at any time during the # project or thereafter. Each user will be deemed to have agreed to the # foregoing by his or her commencement of use of the program. The term # "use" as used herein includes, but is not limited to, the use, # modification, copying and distribution of the program and the # production of secondary products from the program. # # In the case where the program, whether in its original form or # modified, was distributed or delivered to or received by a user from # any person, organization or entity other than ICOT, unless it makes or # grants independently of ICOT any specific warranty to the user in # writing, such person, organization or entity, will also be exempted # from and not be held liable to the user for any such damages as noted # above as far as the program is concerned. # # ---------------COPYING.ipadic-----END---------------------------------- ---------------------------------------------------------------------- Lao Word Break Dictionary Data (laodict.txt) # Copyright (C) 2016 and later: Unicode, Inc. and others. # License & terms of use: http://www.unicode.org/copyright.html # Copyright (c) 2015 International Business Machines Corporation # and others. All Rights Reserved. # # Project: https://github.com/rober42539/lao-dictionary # Dictionary: https://github.com/rober42539/lao-dictionary/laodict.txt # License: https://github.com/rober42539/lao-dictionary/LICENSE.txt # (copied below) # # This file is derived from the above dictionary version of Nov 22, 2020 # ---------------------------------------------------------------------- # Copyright (C) 2013 Brian Eugene Wilson, Robert Martin Campbell. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # Redistributions of source code must retain the above copyright notice, this # list of conditions and the following disclaimer. Redistributions in binary # form must reproduce the above copyright notice, this list of conditions and # the following disclaimer in the documentation and/or other materials # provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, # INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED # OF THE POSSIBILITY OF SUCH DAMAGE. # -------------------------------------------------------------------------- ---------------------------------------------------------------------- Burmese Word Break Dictionary Data (burmesedict.txt) # Copyright (c) 2014 International Business Machines Corporation # and others. All Rights Reserved. # # This list is part of a project hosted at: # github.com/kanyawtech/myanmar-karen-word-lists # # -------------------------------------------------------------------------- # Copyright (c) 2013, LeRoy Benjamin Sharon # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: Redistributions of source code must retain the above # copyright notice, this list of conditions and the following # disclaimer. Redistributions in binary form must reproduce the # above copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # # Neither the name Myanmar Karen Word Lists, nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND # CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED # TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR # TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF # THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # -------------------------------------------------------------------------- ---------------------------------------------------------------------- Time Zone Database ICU uses the public domain data and code derived from Time Zone Database for its time zone support. The ownership of the TZ database is explained in BCP 175: Procedure for Maintaining the Time Zone Database section 7. # 7. Database Ownership # # The TZ database itself is not an IETF Contribution or an IETF # document. Rather it is a pre-existing and regularly updated work # that is in the public domain, and is intended to remain in the # public domain. Therefore, BCPs 78 [RFC5378] and 79 [RFC3979] do # not apply to the TZ Database or contributions that individuals make # to it. Should any claims be made and substantiated against the TZ # Database, the organization that is providing the IANA # Considerations defined in this RFC, under the memorandum of # understanding with the IETF, currently ICANN, may act in accordance # with all competent court orders. No ownership claims will be made # by ICANN or the IETF Trust on the database or the code. Any person # making a contribution to the database or code waives all rights to # future claims in that contribution or in the TZ Database. ---------------------------------------------------------------------- Google double-conversion Copyright 2006-2011, the V8 project authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Google Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- JSON parsing library (nlohmann/json) File: vendor/json/upstream/single_include/nlohmann/json.hpp (only for ICU4C) MIT License Copyright (c) 2013-2022 Niels Lohmann Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ---------------------------------------------------------------------- File: aclocal.m4 (only for ICU4C) Section: pkg.m4 - Macros to locate and utilise pkg-config. Copyright © 2004 Scott James Remnant . Copyright © 2012-2015 Dan Nicholson 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 2 of the License, or (at your option) 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. As a special exception to the GNU General Public License, if you distribute this file as part of a program that contains a configuration script generated by Autoconf, you may include it under the same distribution terms that you use for the rest of that program. (The condition for the exception is fulfilled because ICU4C includes a configuration script generated by Autoconf, namely the `configure` script.) ---------------------------------------------------------------------- File: config.guess (only for ICU4C) This file 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 (at your option) 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, see . As a special exception to the GNU General Public License, if you distribute this file as part of a program that contains a configuration script generated by Autoconf, you may include it under the same distribution terms that you use for the rest of that program. This Exception is an additional permission under section 7 of the GNU General Public License, version 3 ("GPLv3"). (The condition for the exception is fulfilled because ICU4C includes a configuration script generated by Autoconf, namely the `configure` script.) ---------------------------------------------------------------------- File: install-sh (only for ICU4C) Copyright 1991 by the Massachusetts Institute of Technology Permission to use, copy, modify, distribute, and sell this software and its documentation for any purpose is hereby granted without fee, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the name of M.I.T. not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. M.I.T. makes no representations about the suitability of this software for any purpose. It is provided "as is" without express or implied warranty. ================================================ FILE: external/pdfium/linux-x64/licenses/lcms.txt ================================================ //--------------------------------------------------------------------------------- // // Little Color Management System // Copyright (c) 1998-2023 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), // to deal in the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the Software // is furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO // THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // //--------------------------------------------------------------------------------- // // Version 2.15 // ================================================ FILE: external/pdfium/linux-x64/licenses/libjpeg_turbo.ijg ================================================ libjpeg-turbo note: This file has been modified by The libjpeg-turbo Project to include only information relevant to libjpeg-turbo, to wordsmith certain sections, and to remove impolitic language that existed in the libjpeg v8 README. It is included only for reference. Please see README.md for information specific to libjpeg-turbo. The Independent JPEG Group's JPEG software ========================================== This distribution contains a release of the Independent JPEG Group's free JPEG software. You are welcome to redistribute this software and to use it for any purpose, subject to the conditions under LEGAL ISSUES, below. This software is the work of Tom Lane, Guido Vollbeding, Philip Gladstone, Bill Allombert, Jim Boucher, Lee Crocker, Bob Friesenhahn, Ben Jackson, Julian Minguillon, Luis Ortiz, George Phillips, Davide Rossi, Ge' Weijers, and other members of the Independent JPEG Group. IJG is not affiliated with the ISO/IEC JTC1/SC29/WG1 standards committee (also known as JPEG, together with ITU-T SG16). DOCUMENTATION ROADMAP ===================== This file contains the following sections: OVERVIEW General description of JPEG and the IJG software. LEGAL ISSUES Copyright, lack of warranty, terms of distribution. REFERENCES Where to learn more about JPEG. ARCHIVE LOCATIONS Where to find newer versions of this software. FILE FORMAT WARS Software *not* to get. TO DO Plans for future IJG releases. Other documentation files in the distribution are: User documentation: doc/usage.txt Usage instructions for cjpeg, djpeg, jpegtran, rdjpgcom, and wrjpgcom. doc/*.1 Unix-style man pages for programs (same info as usage.txt). doc/wizard.txt Advanced usage instructions for JPEG wizards only. doc/change.log Version-to-version change highlights. Programmer and internal documentation: doc/libjpeg.txt How to use the JPEG library in your own programs. src/example.c Sample code for calling the JPEG library. doc/structure.txt Overview of the JPEG library's internal structure. doc/coderules.txt Coding style rules --- please read if you contribute code. Please read at least usage.txt. Some information can also be found in the JPEG FAQ (Frequently Asked Questions) article. See ARCHIVE LOCATIONS below to find out where to obtain the FAQ article. If you want to understand how the JPEG code works, we suggest reading one or more of the REFERENCES, then looking at the documentation files (in roughly the order listed) before diving into the code. OVERVIEW ======== This package contains C software to implement JPEG image encoding, decoding, and transcoding. JPEG (pronounced "jay-peg") is a standardized compression method for full-color and grayscale images. JPEG's strong suit is compressing photographic images or other types of images that have smooth color and brightness transitions between neighboring pixels. Images with sharp lines or other abrupt features may not compress well with JPEG, and a higher JPEG quality may have to be used to avoid visible compression artifacts with such images. JPEG is normally lossy, meaning that the output pixels are not necessarily identical to the input pixels. However, on photographic content and other "smooth" images, very good compression ratios can be obtained with no visible compression artifacts, and extremely high compression ratios are possible if you are willing to sacrifice image quality (by reducing the "quality" setting in the compressor.) This software implements JPEG baseline, extended-sequential, progressive, and lossless compression processes. Provision is made for supporting all variants of these processes, although some uncommon parameter settings aren't implemented yet. We have made no provision for supporting the hierarchical processes defined in the standard. We provide a set of library routines for reading and writing JPEG image files, plus two sample applications "cjpeg" and "djpeg", which use the library to perform conversion between JPEG and some other popular image file formats. The library is intended to be reused in other applications. In order to support file conversion and viewing software, we have included considerable functionality beyond the bare JPEG coding/decoding capability; for example, the color quantization modules are not strictly part of JPEG decoding, but they are essential for output to colormapped file formats. These extra functions can be compiled out of the library if not required for a particular application. We have also included "jpegtran", a utility for lossless transcoding between different JPEG processes, and "rdjpgcom" and "wrjpgcom", two simple applications for inserting and extracting textual comments in JFIF files. The emphasis in designing this software has been on achieving portability and flexibility, while also making it fast enough to be useful. In particular, the software is not intended to be read as a tutorial on JPEG. (See the REFERENCES section for introductory material.) Rather, it is intended to be reliable, portable, industrial-strength code. We do not claim to have achieved that goal in every aspect of the software, but we strive for it. We welcome the use of this software as a component of commercial products. No royalty is required, but we do ask for an acknowledgement in product documentation, as described under LEGAL ISSUES. LEGAL ISSUES ============ In plain English: 1. We don't promise that this software works. (But if you find any bugs, please let us know!) 2. You can use this software for whatever you want. You don't have to pay us. 3. You may not pretend that you wrote this software. If you use it in a program, you must acknowledge somewhere in your documentation that you've used the IJG code. In legalese: The authors make NO WARRANTY or representation, either express or implied, with respect to this software, its quality, accuracy, merchantability, or fitness for a particular purpose. This software is provided "AS IS", and you, its user, assume the entire risk as to its quality and accuracy. This software is copyright (C) 1991-2020, Thomas G. Lane, Guido Vollbeding. All Rights Reserved except as specified below. Permission is hereby granted to use, copy, modify, and distribute this software (or portions thereof) for any purpose, without fee, subject to these conditions: (1) If any part of the source code for this software is distributed, then this README file must be included, with this copyright and no-warranty notice unaltered; and any additions, deletions, or changes to the original files must be clearly indicated in accompanying documentation. (2) If only executable code is distributed, then the accompanying documentation must state that "this software is based in part on the work of the Independent JPEG Group". (3) Permission for use of this software is granted only if the user accepts full responsibility for any undesirable consequences; the authors accept NO LIABILITY for damages of any kind. These conditions apply to any software derived from or based on the IJG code, not just to the unmodified library. If you use our work, you ought to acknowledge us. Permission is NOT granted for the use of any IJG author's name or company name in advertising or publicity relating to this software or products derived from it. This software may be referred to only as "the Independent JPEG Group's software". We specifically permit and encourage the use of this software as the basis of commercial products, provided that all warranty or liability claims are assumed by the product vendor. REFERENCES ========== We recommend reading one or more of these references before trying to understand the innards of the JPEG software. The best short technical introduction to the JPEG compression algorithm is Wallace, Gregory K. "The JPEG Still Picture Compression Standard", Communications of the ACM, April 1991 (vol. 34 no. 4), pp. 30-44. (Adjacent articles in that issue discuss MPEG motion picture compression, applications of JPEG, and related topics.) If you don't have the CACM issue handy, a PDF file containing a revised version of Wallace's article is available at http://www.ijg.org/files/Wallace.JPEG.pdf. The file (actually a preprint for an article that appeared in IEEE Trans. Consumer Electronics) omits the sample images that appeared in CACM, but it includes corrections and some added material. Note: the Wallace article is copyright ACM and IEEE, and it may not be used for commercial purposes. A somewhat less technical, more leisurely introduction to JPEG can be found in "The Data Compression Book" by Mark Nelson and Jean-loup Gailly, published by M&T Books (New York), 2nd ed. 1996, ISBN 1-55851-434-1. This book provides good explanations and example C code for a multitude of compression methods including JPEG. It is an excellent source if you are comfortable reading C code but don't know much about data compression in general. The book's JPEG sample code is far from industrial-strength, but when you are ready to look at a full implementation, you've got one here... The best currently available description of JPEG is the textbook "JPEG Still Image Data Compression Standard" by William B. Pennebaker and Joan L. Mitchell, published by Van Nostrand Reinhold, 1993, ISBN 0-442-01272-1. Price US$59.95, 638 pp. The book includes the complete text of the ISO JPEG standards (DIS 10918-1 and draft DIS 10918-2). The original JPEG standard is divided into two parts, Part 1 being the actual specification, while Part 2 covers compliance testing methods. Part 1 is titled "Digital Compression and Coding of Continuous-tone Still Images, Part 1: Requirements and guidelines" and has document numbers ISO/IEC IS 10918-1, ITU-T T.81. Part 2 is titled "Digital Compression and Coding of Continuous-tone Still Images, Part 2: Compliance testing" and has document numbers ISO/IEC IS 10918-2, ITU-T T.83. The JPEG standard does not specify all details of an interchangeable file format. For the omitted details, we follow the "JFIF" conventions, revision 1.02. JFIF version 1 has been adopted as ISO/IEC 10918-5 (05/2013) and Recommendation ITU-T T.871 (05/2011): Information technology - Digital compression and coding of continuous-tone still images: JPEG File Interchange Format (JFIF). It is available as a free download in PDF file format from https://www.iso.org/standard/54989.html and http://www.itu.int/rec/T-REC-T.871. A PDF file of the older JFIF 1.02 specification is available at http://www.w3.org/Graphics/JPEG/jfif3.pdf. The TIFF 6.0 file format specification can be obtained from http://mirrors.ctan.org/graphics/tiff/TIFF6.ps.gz. The JPEG incorporation scheme found in the TIFF 6.0 spec of 3-June-92 has a number of serious problems. IJG does not recommend use of the TIFF 6.0 design (TIFF Compression tag 6). Instead, we recommend the JPEG design proposed by TIFF Technical Note #2 (Compression tag 7). Copies of this Note can be obtained from http://www.ijg.org/files/. It is expected that the next revision of the TIFF spec will replace the 6.0 JPEG design with the Note's design. Although IJG's own code does not support TIFF/JPEG, the free libtiff library uses our library to implement TIFF/JPEG per the Note. ARCHIVE LOCATIONS ================= The "official" archive site for this software is www.ijg.org. The most recent released version can always be found there in directory "files". The JPEG FAQ (Frequently Asked Questions) article is a source of some general information about JPEG. It is available at http://www.faqs.org/faqs/jpeg-faq. FILE FORMAT COMPATIBILITY ========================= This software implements ITU T.81 | ISO/IEC 10918 with some extensions from ITU T.871 | ISO/IEC 10918-5 (JPEG File Interchange Format-- see REFERENCES). Informally, the term "JPEG image" or "JPEG file" most often refers to JFIF or a subset thereof, but there are other formats containing the name "JPEG" that are incompatible with the original JPEG standard or with JFIF (for instance, JPEG 2000 and JPEG XR). This software therefore does not support these formats. Indeed, one of the original reasons for developing this free software was to help force convergence on a common, interoperable format standard for JPEG files. JFIF is a minimal or "low end" representation. TIFF/JPEG (TIFF revision 6.0 as modified by TIFF Technical Note #2) can be used for "high end" applications that need to record a lot of additional data about an image. TO DO ===== Please send bug reports, offers of help, etc. to jpeg-info@jpegclub.org. ================================================ FILE: external/pdfium/linux-x64/licenses/libjpeg_turbo.md ================================================ libjpeg-turbo Licenses ====================== libjpeg-turbo is covered by two compatible BSD-style open source licenses: - The IJG (Independent JPEG Group) License, which is listed in [README.ijg](README.ijg) This license applies to the libjpeg API library and associated programs, including any code inherited from libjpeg and any modifications to that code. Note that the libjpeg-turbo SIMD source code bears the [zlib License](https://opensource.org/licenses/Zlib), but in the context of the overall libjpeg API library, the terms of the zlib License are subsumed by the terms of the IJG License. - The Modified (3-clause) BSD License, which is listed below This license applies to the TurboJPEG API library and associated programs, as well as the build system. Note that the TurboJPEG API library wraps the libjpeg API library, so in the context of the overall TurboJPEG API library, both the terms of the IJG License and the terms of the Modified (3-clause) BSD License apply. Complying with the libjpeg-turbo Licenses ========================================= This section provides a roll-up of the libjpeg-turbo licensing terms, to the best of our understanding. This is not a license in and of itself. It is intended solely for clarification. 1. If you are distributing a modified version of the libjpeg-turbo source, then: 1. You cannot alter or remove any existing copyright or license notices from the source. **Origin** - Clause 1 of the IJG License - Clause 1 of the Modified BSD License - Clauses 1 and 3 of the zlib License 2. You must add your own copyright notice to the header of each source file you modified, so others can tell that you modified that file. (If there is not an existing copyright header in that file, then you can simply add a notice stating that you modified the file.) **Origin** - Clause 1 of the IJG License - Clause 2 of the zlib License 3. You must include the IJG README file, and you must not alter any of the copyright or license text in that file. **Origin** - Clause 1 of the IJG License 2. If you are distributing only libjpeg-turbo binaries without the source, or if you are distributing an application that statically links with libjpeg-turbo, then: 1. Your product documentation must include a message stating: This software is based in part on the work of the Independent JPEG Group. **Origin** - Clause 2 of the IJG license 2. If your binary distribution includes or uses the TurboJPEG API, then your product documentation must include the text of the Modified BSD License (see below.) **Origin** - Clause 2 of the Modified BSD License 3. You cannot use the name of the IJG or The libjpeg-turbo Project or the contributors thereof in advertising, publicity, etc. **Origin** - IJG License - Clause 3 of the Modified BSD License 4. The IJG and The libjpeg-turbo Project do not warrant libjpeg-turbo to be free of defects, nor do we accept any liability for undesirable consequences resulting from your use of the software. **Origin** - IJG License - Modified BSD License - zlib License The Modified (3-clause) BSD License =================================== Copyright (C)2009-2024 D. R. Commander. All Rights Reserved.
Copyright (C)2015 Viktor Szathmáry. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - Neither the name of the libjpeg-turbo Project nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Why Two Licenses? ================= The zlib License could have been used instead of the Modified (3-clause) BSD License, and since the IJG License effectively subsumes the distribution conditions of the zlib License, this would have effectively placed libjpeg-turbo binary distributions under the IJG License. However, the IJG License specifically refers to the Independent JPEG Group and does not extend attribution and endorsement protections to other entities. Thus, it was desirable to choose a license that granted us the same protections for new code that were granted to the IJG for code derived from their software. ================================================ FILE: external/pdfium/linux-x64/licenses/libopenjpeg.txt ================================================ /* * The copyright in this software is being made available under the 2-clauses * BSD License, included below. This software may be subject to other third * party and contributor rights, including patent rights, and no such rights * are granted under this license. * * Copyright (c) 2005, Herve Drolon, FreeImage Team * Copyright (c) 2008, 2011-2012, Centre National d'Etudes Spatiales (CNES), FR * Copyright (c) 2012, CS Systemes d'Information, France * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ ================================================ FILE: external/pdfium/linux-x64/licenses/libpng.txt ================================================ COPYRIGHT NOTICE, DISCLAIMER, and LICENSE ========================================= PNG Reference Library License version 2 --------------------------------------- * Copyright (c) 1995-2019 The PNG Reference Library Authors. * Copyright (c) 2018-2019 Cosmin Truta. * Copyright (c) 2000-2002, 2004, 2006-2018 Glenn Randers-Pehrson. * Copyright (c) 1996-1997 Andreas Dilger. * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. The software is supplied "as is", without warranty of any kind, express or implied, including, without limitation, the warranties of merchantability, fitness for a particular purpose, title, and non-infringement. In no event shall the Copyright owners, or anyone distributing the software, be liable for any damages or other liability, whether in contract, tort or otherwise, arising from, out of, or in connection with the software, or the use or other dealings in the software, even if advised of the possibility of such damage. Permission is hereby granted to use, copy, modify, and distribute this software, or portions hereof, for any purpose, without fee, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated, but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This Copyright notice may not be removed or altered from any source or altered source distribution. PNG Reference Library License version 1 (for libpng 0.5 through 1.6.35) ----------------------------------------------------------------------- libpng versions 1.0.7, July 1, 2000, through 1.6.35, July 15, 2018 are Copyright (c) 2000-2002, 2004, 2006-2018 Glenn Randers-Pehrson, are derived from libpng-1.0.6, and are distributed according to the same disclaimer and license as libpng-1.0.6 with the following individuals added to the list of Contributing Authors: Simon-Pierre Cadieux Eric S. Raymond Mans Rullgard Cosmin Truta Gilles Vollant James Yu Mandar Sahastrabuddhe Google Inc. Vadim Barkov and with the following additions to the disclaimer: There is no warranty against interference with your enjoyment of the library or against infringement. There is no warranty that our efforts or the library will fulfill any of your particular purposes or needs. This library is provided with all faults, and the entire risk of satisfactory quality, performance, accuracy, and effort is with the user. Some files in the "contrib" directory and some configure-generated files that are distributed with libpng have other copyright owners, and are released under other open source licenses. libpng versions 0.97, January 1998, through 1.0.6, March 20, 2000, are Copyright (c) 1998-2000 Glenn Randers-Pehrson, are derived from libpng-0.96, and are distributed according to the same disclaimer and license as libpng-0.96, with the following individuals added to the list of Contributing Authors: Tom Lane Glenn Randers-Pehrson Willem van Schaik libpng versions 0.89, June 1996, through 0.96, May 1997, are Copyright (c) 1996-1997 Andreas Dilger, are derived from libpng-0.88, and are distributed according to the same disclaimer and license as libpng-0.88, with the following individuals added to the list of Contributing Authors: John Bowler Kevin Bracey Sam Bushell Magnus Holmgren Greg Roelofs Tom Tanner Some files in the "scripts" directory have other copyright owners, but are released under this license. libpng versions 0.5, May 1995, through 0.88, January 1996, are Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. For the purposes of this copyright and license, "Contributing Authors" is defined as the following set of individuals: Andreas Dilger Dave Martindale Guy Eric Schalnat Paul Schmidt Tim Wegner The PNG Reference Library is supplied "AS IS". The Contributing Authors and Group 42, Inc. disclaim all warranties, expressed or implied, including, without limitation, the warranties of merchantability and of fitness for any purpose. The Contributing Authors and Group 42, Inc. assume no liability for direct, indirect, incidental, special, exemplary, or consequential damages, which may result from the use of the PNG Reference Library, even if advised of the possibility of such damage. Permission is hereby granted to use, copy, modify, and distribute this source code, or portions hereof, for any purpose, without fee, subject to the following restrictions: 1. The origin of this source code must not be misrepresented. 2. Altered versions must be plainly marked as such and must not be misrepresented as being the original source. 3. This Copyright notice may not be removed or altered from any source or altered source distribution. The Contributing Authors and Group 42, Inc. specifically permit, without fee, and encourage the use of this source code as a component to supporting the PNG file format in commercial products. If you use this source code in a product, acknowledgment is not required but would be appreciated. ================================================ FILE: external/pdfium/linux-x64/licenses/libtiff.txt ================================================ Copyright (c) 1988-1997 Sam Leffler Copyright (c) 1991-1997 Silicon Graphics, Inc. Permission to use, copy, modify, distribute, and sell this software and its documentation for any purpose is hereby granted without fee, provided that (i) the above copyright notices and this permission notice appear in all copies of the software and related documentation, and (ii) the names of Sam Leffler and Silicon Graphics may not be used in any advertising or publicity relating to the software without the specific, prior written permission of Sam Leffler and Silicon Graphics. THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ================================================ FILE: external/pdfium/linux-x64/licenses/llvm-libc.txt ================================================ ============================================================================== The LLVM Project is under the Apache License v2.0 with LLVM Exceptions: ============================================================================== Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ---- LLVM Exceptions to the Apache 2.0 License ---- As an exception, if, as a result of your compiling your source code, portions of this Software are embedded into an Object form of such source code, you may redistribute such embedded portions in such Object form without complying with the conditions of Sections 4(a), 4(b) and 4(d) of the License. In addition, if you combine or link compiled forms of this Software with software that is licensed under the GPLv2 ("Combined Software") and if a court of competent jurisdiction determines that the patent provision (Section 3), the indemnity provision (Section 9) or other Section of the License conflicts with the conditions of the GPLv2, you may retroactively and prospectively choose to deem waived or otherwise exclude such Section(s) of the License, but only in their entirety and only with respect to the Combined Software. ============================================================================== Software from third parties included in the LLVM Project: ============================================================================== The LLVM Project contains third party software which is under different license terms. All such code will be identified clearly using at least one of two mechanisms: 1) It will be in a separate directory tree with its own `LICENSE.txt` or `LICENSE` file at the top containing the specific license and restrictions which apply to that software, or 2) It will contain specific license and restriction terms at the top of every file. ============================================================================== Legacy LLVM License (https://llvm.org/docs/DeveloperPolicy.html#legacy): ============================================================================== University of Illinois/NCSA Open Source License Copyright (c) 2007-2019 University of Illinois at Urbana-Champaign. All rights reserved. Developed by: LLVM Team University of Illinois at Urbana-Champaign http://llvm.org Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal with the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimers. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimers in the documentation and/or other materials provided with the distribution. * Neither the names of the LLVM Team, University of Illinois at Urbana-Champaign, nor the names of its contributors may be used to endorse or promote products derived from this Software without specific prior written permission. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE. ================================================ FILE: external/pdfium/linux-x64/licenses/pdfium.txt ================================================ Copyright 2014 The PDFium Authors Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Google Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Apache License Version 2.0, January 2004 https://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: external/pdfium/linux-x64/licenses/simdutf.txt ================================================ Copyright 2021 The simdutf authors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: external/pdfium/linux-x64/licenses/zlib.txt ================================================ /* zlib.h -- interface of the 'zlib' general purpose compression library version 1.3.1, January 22nd, 2024 Copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. Jean-loup Gailly Mark Adler jloup@gzip.org madler@alumni.caltech.edu The data format used by the zlib library is described by RFCs (Request for Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950 (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format). */ ================================================ FILE: external/pdfium/macos-arm64/LICENSE ================================================ Copyright 2014-2025 Benoit Blanchon Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. This package also includes third-party software. See the licenses/ directory for their respective licenses. ================================================ FILE: external/pdfium/macos-arm64/PDFiumConfig.cmake ================================================ # PDFium Package Configuration for CMake # # To use PDFium in your CMake project: # # 1. set the environment variable PDFium_DIR to the folder containing this file. # 2. in your CMakeLists.txt, add # find_package(PDFium) # 3. then link your executable with PDFium # target_link_libraries(my_exe pdfium) include(FindPackageHandleStandardArgs) find_path(PDFium_INCLUDE_DIR NAMES "fpdfview.h" PATHS "${CMAKE_CURRENT_LIST_DIR}" PATH_SUFFIXES "include" ) set(PDFium_VERSION "147.0.7713.0") if(WIN32) find_file(PDFium_LIBRARY NAMES "pdfium.dll" PATHS "${CMAKE_CURRENT_LIST_DIR}" PATH_SUFFIXES "bin") find_file(PDFium_IMPLIB NAMES "pdfium.dll.lib" PATHS "${CMAKE_CURRENT_LIST_DIR}" PATH_SUFFIXES "lib") add_library(pdfium SHARED IMPORTED) set_target_properties(pdfium PROPERTIES IMPORTED_LOCATION "${PDFium_LIBRARY}" IMPORTED_IMPLIB "${PDFium_IMPLIB}" INTERFACE_INCLUDE_DIRECTORIES "${PDFium_INCLUDE_DIR};${PDFium_INCLUDE_DIR}/cpp" ) find_package_handle_standard_args(PDFium REQUIRED_VARS PDFium_LIBRARY PDFium_IMPLIB PDFium_INCLUDE_DIR VERSION_VAR PDFium_VERSION ) else() find_library(PDFium_LIBRARY NAMES "pdfium" PATHS "${CMAKE_CURRENT_LIST_DIR}" PATH_SUFFIXES "lib") add_library(pdfium SHARED IMPORTED) set_target_properties(pdfium PROPERTIES IMPORTED_LOCATION "${PDFium_LIBRARY}" INTERFACE_INCLUDE_DIRECTORIES "${PDFium_INCLUDE_DIR};${PDFium_INCLUDE_DIR}/cpp" ) find_package_handle_standard_args(PDFium REQUIRED_VARS PDFium_LIBRARY PDFium_INCLUDE_DIR VERSION_VAR PDFium_VERSION ) endif() ================================================ FILE: external/pdfium/macos-arm64/VERSION ================================================ MAJOR=147 MINOR=0 BUILD=7713 PATCH=0 ================================================ FILE: external/pdfium/macos-arm64/args.gn ================================================ clang_use_chrome_plugins = false is_component_build = false is_debug = false pdf_enable_v8 = false pdf_enable_xfa = false pdf_is_standalone = true pdf_use_partition_alloc = false target_cpu = "arm64" target_os = "mac" treat_warnings_as_errors = false ================================================ FILE: external/pdfium/macos-arm64/include/cpp/fpdf_deleters.h ================================================ // Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef PUBLIC_CPP_FPDF_DELETERS_H_ #define PUBLIC_CPP_FPDF_DELETERS_H_ #include "../fpdf_annot.h" #include "../fpdf_dataavail.h" #include "../fpdf_edit.h" #include "../fpdf_formfill.h" #include "../fpdf_javascript.h" #include "../fpdf_structtree.h" #include "../fpdf_text.h" #include "../fpdf_transformpage.h" #include "../fpdfview.h" // Custom deleters for using FPDF_* types with std::unique_ptr<>. struct FPDFAnnotationDeleter { inline void operator()(FPDF_ANNOTATION annot) { FPDFPage_CloseAnnot(annot); } }; struct FPDFAvailDeleter { inline void operator()(FPDF_AVAIL avail) { FPDFAvail_Destroy(avail); } }; struct FPDFBitmapDeleter { inline void operator()(FPDF_BITMAP bitmap) { FPDFBitmap_Destroy(bitmap); } }; struct FPDFClipPathDeleter { inline void operator()(FPDF_CLIPPATH clip_path) { FPDF_DestroyClipPath(clip_path); } }; struct FPDFDocumentDeleter { inline void operator()(FPDF_DOCUMENT doc) { FPDF_CloseDocument(doc); } }; struct FPDFFontDeleter { inline void operator()(FPDF_FONT font) { FPDFFont_Close(font); } }; struct FPDFFormHandleDeleter { inline void operator()(FPDF_FORMHANDLE form) { FPDFDOC_ExitFormFillEnvironment(form); } }; struct FPDFJavaScriptActionDeleter { inline void operator()(FPDF_JAVASCRIPT_ACTION javascript) { FPDFDoc_CloseJavaScriptAction(javascript); } }; struct FPDFPageDeleter { inline void operator()(FPDF_PAGE page) { FPDF_ClosePage(page); } }; struct FPDFPageLinkDeleter { inline void operator()(FPDF_PAGELINK pagelink) { FPDFLink_CloseWebLinks(pagelink); } }; struct FPDFPageObjectDeleter { inline void operator()(FPDF_PAGEOBJECT object) { FPDFPageObj_Destroy(object); } }; struct FPDFStructTreeDeleter { inline void operator()(FPDF_STRUCTTREE tree) { FPDF_StructTree_Close(tree); } }; struct FPDFTextFindDeleter { inline void operator()(FPDF_SCHHANDLE handle) { FPDFText_FindClose(handle); } }; struct FPDFTextPageDeleter { inline void operator()(FPDF_TEXTPAGE text) { FPDFText_ClosePage(text); } }; #endif // PUBLIC_CPP_FPDF_DELETERS_H_ ================================================ FILE: external/pdfium/macos-arm64/include/cpp/fpdf_scopers.h ================================================ // Copyright 2018 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef PUBLIC_CPP_FPDF_SCOPERS_H_ #define PUBLIC_CPP_FPDF_SCOPERS_H_ #include #include #include "fpdf_deleters.h" // Versions of FPDF types that clean up the object at scope exit. using ScopedFPDFAnnotation = std::unique_ptr::type, FPDFAnnotationDeleter>; using ScopedFPDFAvail = std::unique_ptr::type, FPDFAvailDeleter>; using ScopedFPDFBitmap = std::unique_ptr::type, FPDFBitmapDeleter>; using ScopedFPDFClipPath = std::unique_ptr::type, FPDFClipPathDeleter>; using ScopedFPDFDocument = std::unique_ptr::type, FPDFDocumentDeleter>; using ScopedFPDFFont = std::unique_ptr::type, FPDFFontDeleter>; using ScopedFPDFFormHandle = std::unique_ptr::type, FPDFFormHandleDeleter>; using ScopedFPDFJavaScriptAction = std::unique_ptr::type, FPDFJavaScriptActionDeleter>; using ScopedFPDFPage = std::unique_ptr::type, FPDFPageDeleter>; using ScopedFPDFPageLink = std::unique_ptr::type, FPDFPageLinkDeleter>; using ScopedFPDFPageObject = std::unique_ptr::type, FPDFPageObjectDeleter>; using ScopedFPDFStructTree = std::unique_ptr::type, FPDFStructTreeDeleter>; using ScopedFPDFTextFind = std::unique_ptr::type, FPDFTextFindDeleter>; using ScopedFPDFTextPage = std::unique_ptr::type, FPDFTextPageDeleter>; #endif // PUBLIC_CPP_FPDF_SCOPERS_H_ ================================================ FILE: external/pdfium/macos-arm64/include/fpdf_annot.h ================================================ // Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef PUBLIC_FPDF_ANNOT_H_ #define PUBLIC_FPDF_ANNOT_H_ #include // NOLINTNEXTLINE(build/include) #include "fpdfview.h" // NOLINTNEXTLINE(build/include) #include "fpdf_formfill.h" #ifdef __cplusplus extern "C" { #endif // __cplusplus #define FPDF_ANNOT_UNKNOWN 0 #define FPDF_ANNOT_TEXT 1 #define FPDF_ANNOT_LINK 2 #define FPDF_ANNOT_FREETEXT 3 #define FPDF_ANNOT_LINE 4 #define FPDF_ANNOT_SQUARE 5 #define FPDF_ANNOT_CIRCLE 6 #define FPDF_ANNOT_POLYGON 7 #define FPDF_ANNOT_POLYLINE 8 #define FPDF_ANNOT_HIGHLIGHT 9 #define FPDF_ANNOT_UNDERLINE 10 #define FPDF_ANNOT_SQUIGGLY 11 #define FPDF_ANNOT_STRIKEOUT 12 #define FPDF_ANNOT_STAMP 13 #define FPDF_ANNOT_CARET 14 #define FPDF_ANNOT_INK 15 #define FPDF_ANNOT_POPUP 16 #define FPDF_ANNOT_FILEATTACHMENT 17 #define FPDF_ANNOT_SOUND 18 #define FPDF_ANNOT_MOVIE 19 #define FPDF_ANNOT_WIDGET 20 #define FPDF_ANNOT_SCREEN 21 #define FPDF_ANNOT_PRINTERMARK 22 #define FPDF_ANNOT_TRAPNET 23 #define FPDF_ANNOT_WATERMARK 24 #define FPDF_ANNOT_THREED 25 #define FPDF_ANNOT_RICHMEDIA 26 #define FPDF_ANNOT_XFAWIDGET 27 #define FPDF_ANNOT_REDACT 28 // Refer to PDF Reference (6th edition) table 8.16 for all annotation flags. #define FPDF_ANNOT_FLAG_NONE 0 #define FPDF_ANNOT_FLAG_INVISIBLE (1 << 0) #define FPDF_ANNOT_FLAG_HIDDEN (1 << 1) #define FPDF_ANNOT_FLAG_PRINT (1 << 2) #define FPDF_ANNOT_FLAG_NOZOOM (1 << 3) #define FPDF_ANNOT_FLAG_NOROTATE (1 << 4) #define FPDF_ANNOT_FLAG_NOVIEW (1 << 5) #define FPDF_ANNOT_FLAG_READONLY (1 << 6) #define FPDF_ANNOT_FLAG_LOCKED (1 << 7) #define FPDF_ANNOT_FLAG_TOGGLENOVIEW (1 << 8) #define FPDF_ANNOT_APPEARANCEMODE_NORMAL 0 #define FPDF_ANNOT_APPEARANCEMODE_ROLLOVER 1 #define FPDF_ANNOT_APPEARANCEMODE_DOWN 2 #define FPDF_ANNOT_APPEARANCEMODE_COUNT 3 // Refer to PDF Reference version 1.7 table 8.70 for field flags common to all // interactive form field types. #define FPDF_FORMFLAG_NONE 0 #define FPDF_FORMFLAG_READONLY (1 << 0) #define FPDF_FORMFLAG_REQUIRED (1 << 1) #define FPDF_FORMFLAG_NOEXPORT (1 << 2) // Refer to PDF Reference version 1.7 table 8.77 for field flags specific to // interactive form text fields. #define FPDF_FORMFLAG_TEXT_MULTILINE (1 << 12) #define FPDF_FORMFLAG_TEXT_PASSWORD (1 << 13) // Refer to PDF Reference version 1.7 table 8.79 for field flags specific to // interactive form choice fields. #define FPDF_FORMFLAG_CHOICE_COMBO (1 << 17) #define FPDF_FORMFLAG_CHOICE_EDIT (1 << 18) #define FPDF_FORMFLAG_CHOICE_MULTI_SELECT (1 << 21) // Additional actions type of form field: // K, on key stroke, JavaScript action. // F, on format, JavaScript action. // V, on validate, JavaScript action. // C, on calculate, JavaScript action. #define FPDF_ANNOT_AACTION_KEY_STROKE 12 #define FPDF_ANNOT_AACTION_FORMAT 13 #define FPDF_ANNOT_AACTION_VALIDATE 14 #define FPDF_ANNOT_AACTION_CALCULATE 15 typedef enum FPDFANNOT_COLORTYPE { FPDFANNOT_COLORTYPE_Color = 0, FPDFANNOT_COLORTYPE_InteriorColor } FPDFANNOT_COLORTYPE; // Experimental API. // Check if an annotation subtype is currently supported for creation. // Currently supported subtypes: // - circle // - fileattachment // - freetext // - highlight // - ink // - link // - popup // - square, // - squiggly // - stamp // - strikeout // - text // - underline // // subtype - the subtype to be checked. // // Returns true if this subtype supported. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_IsSupportedSubtype(FPDF_ANNOTATION_SUBTYPE subtype); // Experimental API. // Create an annotation in |page| of the subtype |subtype|. If the specified // subtype is illegal or unsupported, then a new annotation will not be created. // Must call FPDFPage_CloseAnnot() when the annotation returned by this // function is no longer needed. // // page - handle to a page. // subtype - the subtype of the new annotation. // // Returns a handle to the new annotation object, or NULL on failure. FPDF_EXPORT FPDF_ANNOTATION FPDF_CALLCONV FPDFPage_CreateAnnot(FPDF_PAGE page, FPDF_ANNOTATION_SUBTYPE subtype); // Experimental API. // Get the number of annotations in |page|. // // page - handle to a page. // // Returns the number of annotations in |page|. FPDF_EXPORT int FPDF_CALLCONV FPDFPage_GetAnnotCount(FPDF_PAGE page); // Experimental API. // Get annotation in |page| at |index|. Must call FPDFPage_CloseAnnot() when the // annotation returned by this function is no longer needed. // // page - handle to a page. // index - the index of the annotation. // // Returns a handle to the annotation object, or NULL on failure. FPDF_EXPORT FPDF_ANNOTATION FPDF_CALLCONV FPDFPage_GetAnnot(FPDF_PAGE page, int index); // Experimental API. // Get the index of |annot| in |page|. This is the opposite of // FPDFPage_GetAnnot(). // // page - handle to the page that the annotation is on. // annot - handle to an annotation. // // Returns the index of |annot|, or -1 on failure. FPDF_EXPORT int FPDF_CALLCONV FPDFPage_GetAnnotIndex(FPDF_PAGE page, FPDF_ANNOTATION annot); // Experimental API. // Close an annotation. Must be called when the annotation returned by // FPDFPage_CreateAnnot() or FPDFPage_GetAnnot() is no longer needed. This // function does not remove the annotation from the document. // // annot - handle to an annotation. FPDF_EXPORT void FPDF_CALLCONV FPDFPage_CloseAnnot(FPDF_ANNOTATION annot); // Experimental API. // Remove the annotation in |page| at |index|. // // page - handle to a page. // index - the index of the annotation. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_RemoveAnnot(FPDF_PAGE page, int index); // Experimental API. // Get the subtype of an annotation. // // annot - handle to an annotation. // // Returns the annotation subtype. FPDF_EXPORT FPDF_ANNOTATION_SUBTYPE FPDF_CALLCONV FPDFAnnot_GetSubtype(FPDF_ANNOTATION annot); // Experimental API. // Check if an annotation subtype is currently supported for object extraction, // update, and removal. // Currently supported subtypes: ink and stamp. // // subtype - the subtype to be checked. // // Returns true if this subtype supported. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_IsObjectSupportedSubtype(FPDF_ANNOTATION_SUBTYPE subtype); // Experimental API. // Update |obj| in |annot|. |obj| must be in |annot| already and must have // been retrieved by FPDFAnnot_GetObject(). Currently, only ink and stamp // annotations are supported by this API. Also note that only path, image, and // text objects have APIs for modification; see FPDFPath_*(), FPDFText_*(), and // FPDFImageObj_*(). // // annot - handle to an annotation. // obj - handle to the object that |annot| needs to update. // // Return true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_UpdateObject(FPDF_ANNOTATION annot, FPDF_PAGEOBJECT obj); // Experimental API. // Add a new InkStroke, represented by an array of points, to the InkList of // |annot|. The API creates an InkList if one doesn't already exist in |annot|. // This API works only for ink annotations. Please refer to ISO 32000-1:2008 // spec, section 12.5.6.13. // // annot - handle to an annotation. // points - pointer to a FS_POINTF array representing input points. // point_count - number of elements in |points| array. This should not exceed // the maximum value that can be represented by an int32_t). // // Returns the 0-based index at which the new InkStroke is added in the InkList // of the |annot|. Returns -1 on failure. FPDF_EXPORT int FPDF_CALLCONV FPDFAnnot_AddInkStroke(FPDF_ANNOTATION annot, const FS_POINTF* points, size_t point_count); // Experimental API. // Removes an InkList in |annot|. // This API works only for ink annotations. // // annot - handle to an annotation. // // Return true on successful removal of /InkList entry from context of the // non-null ink |annot|. Returns false on failure. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_RemoveInkList(FPDF_ANNOTATION annot); // Experimental API. // Add |obj| to |annot|. |obj| must have been created by // FPDFPageObj_CreateNew{Path|Rect}() or FPDFPageObj_New{Text|Image}Obj(), and // will be owned by |annot|. Note that an |obj| cannot belong to more than one // |annot|. Currently, only ink and stamp annotations are supported by this API. // Also note that only path, image, and text objects have APIs for creation. // // annot - handle to an annotation. // obj - handle to the object that is to be added to |annot|. // // Return true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_AppendObject(FPDF_ANNOTATION annot, FPDF_PAGEOBJECT obj); // Experimental API. // Get the total number of objects in |annot|, including path objects, text // objects, external objects, image objects, and shading objects. // // annot - handle to an annotation. // // Returns the number of objects in |annot|. FPDF_EXPORT int FPDF_CALLCONV FPDFAnnot_GetObjectCount(FPDF_ANNOTATION annot); // Experimental API. // Get the object in |annot| at |index|. // // annot - handle to an annotation. // index - the index of the object. // // Return a handle to the object, or NULL on failure. FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV FPDFAnnot_GetObject(FPDF_ANNOTATION annot, int index); // Experimental API. // Remove the object in |annot| at |index|. // // annot - handle to an annotation. // index - the index of the object to be removed. // // Return true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_RemoveObject(FPDF_ANNOTATION annot, int index); // Experimental API. // Set the color of an annotation. Fails when called on annotations with // appearance streams already defined; instead use // FPDFPageObj_Set{Stroke|Fill}Color(). // // annot - handle to an annotation. // type - type of the color to be set. // R, G, B - buffer to hold the RGB value of the color. Ranges from 0 to 255. // A - buffer to hold the opacity. Ranges from 0 to 255. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetColor(FPDF_ANNOTATION annot, FPDFANNOT_COLORTYPE type, unsigned int R, unsigned int G, unsigned int B, unsigned int A); // Experimental API. // Get the color of an annotation. If no color is specified, default to yellow // for highlight annotation, black for all else. Fails when called on // annotations with appearance streams already defined; instead use // FPDFPageObj_Get{Stroke|Fill}Color(). // // annot - handle to an annotation. // type - type of the color requested. // R, G, B - buffer to hold the RGB value of the color. Ranges from 0 to 255. // A - buffer to hold the opacity. Ranges from 0 to 255. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_GetColor(FPDF_ANNOTATION annot, FPDFANNOT_COLORTYPE type, unsigned int* R, unsigned int* G, unsigned int* B, unsigned int* A); // Experimental API. // Check if the annotation is of a type that has attachment points // (i.e. quadpoints). Quadpoints are the vertices of the rectangle that // encompasses the texts affected by the annotation. They provide the // coordinates in the page where the annotation is attached. Only text markup // annotations (i.e. highlight, strikeout, squiggly, and underline) and link // annotations have quadpoints. // // annot - handle to an annotation. // // Returns true if the annotation is of a type that has quadpoints, false // otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_HasAttachmentPoints(FPDF_ANNOTATION annot); // Experimental API. // Replace the attachment points (i.e. quadpoints) set of an annotation at // |quad_index|. This index needs to be within the result of // FPDFAnnot_CountAttachmentPoints(). // If the annotation's appearance stream is defined and this annotation is of a // type with quadpoints, then update the bounding box too if the new quadpoints // define a bigger one. // // annot - handle to an annotation. // quad_index - index of the set of quadpoints. // quad_points - the quadpoints to be set. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetAttachmentPoints(FPDF_ANNOTATION annot, size_t quad_index, const FS_QUADPOINTSF* quad_points); // Experimental API. // Append to the list of attachment points (i.e. quadpoints) of an annotation. // If the annotation's appearance stream is defined and this annotation is of a // type with quadpoints, then update the bounding box too if the new quadpoints // define a bigger one. // // annot - handle to an annotation. // quad_points - the quadpoints to be set. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_AppendAttachmentPoints(FPDF_ANNOTATION annot, const FS_QUADPOINTSF* quad_points); // Experimental API. // Get the number of sets of quadpoints of an annotation. // // annot - handle to an annotation. // // Returns the number of sets of quadpoints, or 0 on failure. FPDF_EXPORT size_t FPDF_CALLCONV FPDFAnnot_CountAttachmentPoints(FPDF_ANNOTATION annot); // Experimental API. // Get the attachment points (i.e. quadpoints) of an annotation. // // annot - handle to an annotation. // quad_index - index of the set of quadpoints. // quad_points - receives the quadpoints; must not be NULL. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_GetAttachmentPoints(FPDF_ANNOTATION annot, size_t quad_index, FS_QUADPOINTSF* quad_points); // Experimental API. // Set the annotation rectangle defining the location of the annotation. If the // annotation's appearance stream is defined and this annotation is of a type // without quadpoints, then update the bounding box too if the new rectangle // defines a bigger one. // // annot - handle to an annotation. // rect - the annotation rectangle to be set. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetRect(FPDF_ANNOTATION annot, const FS_RECTF* rect); // Experimental API. // Get the annotation rectangle defining the location of the annotation. // // annot - handle to an annotation. // rect - receives the rectangle; must not be NULL. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_GetRect(FPDF_ANNOTATION annot, FS_RECTF* rect); // Experimental API. // Get the vertices of a polygon or polyline annotation. |buffer| is an array of // points of the annotation. If |length| is less than the returned length, or // |annot| or |buffer| is NULL, |buffer| will not be modified. // // annot - handle to an annotation, as returned by e.g. FPDFPage_GetAnnot() // buffer - buffer for holding the points. // length - length of the buffer in points. // // Returns the number of points if the annotation is of type polygon or // polyline, 0 otherwise. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFAnnot_GetVertices(FPDF_ANNOTATION annot, FS_POINTF* buffer, unsigned long length); // Experimental API. // Get the number of paths in the ink list of an ink annotation. // // annot - handle to an annotation, as returned by e.g. FPDFPage_GetAnnot() // // Returns the number of paths in the ink list if the annotation is of type ink, // 0 otherwise. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFAnnot_GetInkListCount(FPDF_ANNOTATION annot); // Experimental API. // Get a path in the ink list of an ink annotation. |buffer| is an array of // points of the path. If |length| is less than the returned length, or |annot| // or |buffer| is NULL, |buffer| will not be modified. // // annot - handle to an annotation, as returned by e.g. FPDFPage_GetAnnot() // path_index - index of the path // buffer - buffer for holding the points. // length - length of the buffer in points. // // Returns the number of points of the path if the annotation is of type ink, 0 // otherwise. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFAnnot_GetInkListPath(FPDF_ANNOTATION annot, unsigned long path_index, FS_POINTF* buffer, unsigned long length); // Experimental API. // Get the starting and ending coordinates of a line annotation. // // annot - handle to an annotation, as returned by e.g. FPDFPage_GetAnnot() // start - starting point // end - ending point // // Returns true if the annotation is of type line, |start| and |end| are not // NULL, false otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_GetLine(FPDF_ANNOTATION annot, FS_POINTF* start, FS_POINTF* end); // Experimental API. // Set the characteristics of the annotation's border (rounded rectangle). // // annot - handle to an annotation // horizontal_radius - horizontal corner radius, in default user space units // vertical_radius - vertical corner radius, in default user space units // border_width - border width, in default user space units // // Returns true if setting the border for |annot| succeeds, false otherwise. // // If |annot| contains an appearance stream that overrides the border values, // then the appearance stream will be removed on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetBorder(FPDF_ANNOTATION annot, float horizontal_radius, float vertical_radius, float border_width); // Experimental API. // Get the characteristics of the annotation's border (rounded rectangle). // // annot - handle to an annotation // horizontal_radius - horizontal corner radius, in default user space units // vertical_radius - vertical corner radius, in default user space units // border_width - border width, in default user space units // // Returns true if |horizontal_radius|, |vertical_radius| and |border_width| are // not NULL, false otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_GetBorder(FPDF_ANNOTATION annot, float* horizontal_radius, float* vertical_radius, float* border_width); // Experimental API. // Get the JavaScript of an event of the annotation's additional actions. // |buffer| is only modified if |buflen| is large enough to hold the whole // JavaScript string. If |buflen| is smaller, the total size of the JavaScript // is still returned, but nothing is copied. If there is no JavaScript for // |event| in |annot|, an empty string is written to |buf| and 2 is returned, // denoting the size of the null terminator in the buffer. On other errors, // nothing is written to |buffer| and 0 is returned. // // hHandle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment(). // annot - handle to an interactive form annotation. // event - event type, one of the FPDF_ANNOT_AACTION_* values. // buffer - buffer for holding the value string, encoded in UTF-16LE. // buflen - length of the buffer in bytes. // // Returns the length of the string value in bytes, including the 2-byte // null terminator. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFAnnot_GetFormAdditionalActionJavaScript(FPDF_FORMHANDLE hHandle, FPDF_ANNOTATION annot, int event, FPDF_WCHAR* buffer, unsigned long buflen); // Experimental API. // Check if |annot|'s dictionary has |key| as a key. // // annot - handle to an annotation. // key - the key to look for, encoded in UTF-8. // // Returns true if |key| exists. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_HasKey(FPDF_ANNOTATION annot, FPDF_BYTESTRING key); // Experimental API. // Get the type of the value corresponding to |key| in |annot|'s dictionary. // // annot - handle to an annotation. // key - the key to look for, encoded in UTF-8. // // Returns the type of the dictionary value. FPDF_EXPORT FPDF_OBJECT_TYPE FPDF_CALLCONV FPDFAnnot_GetValueType(FPDF_ANNOTATION annot, FPDF_BYTESTRING key); // Experimental API. // Set the string value corresponding to |key| in |annot|'s dictionary, // overwriting the existing value if any. The value type would be // FPDF_OBJECT_STRING after this function call succeeds. // // annot - handle to an annotation. // key - the key to the dictionary entry to be set, encoded in UTF-8. // value - the string value to be set, encoded in UTF-16LE. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetStringValue(FPDF_ANNOTATION annot, FPDF_BYTESTRING key, FPDF_WIDESTRING value); // Experimental API. // Get the string value corresponding to |key| in |annot|'s dictionary. |buffer| // is only modified if |buflen| is longer than the length of contents. Note that // if |key| does not exist in the dictionary or if |key|'s corresponding value // in the dictionary is not a string (i.e. the value is not of type // FPDF_OBJECT_STRING or FPDF_OBJECT_NAME), then an empty string would be copied // to |buffer| and the return value would be 2. On other errors, nothing would // be added to |buffer| and the return value would be 0. // // annot - handle to an annotation. // key - the key to the requested dictionary entry, encoded in UTF-8. // buffer - buffer for holding the value string, encoded in UTF-16LE. // buflen - length of the buffer in bytes. // // Returns the length of the string value in bytes. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFAnnot_GetStringValue(FPDF_ANNOTATION annot, FPDF_BYTESTRING key, FPDF_WCHAR* buffer, unsigned long buflen); // Experimental API. // Get the float value corresponding to |key| in |annot|'s dictionary. Writes // value to |value| and returns True if |key| exists in the dictionary and // |key|'s corresponding value is a number (FPDF_OBJECT_NUMBER), False // otherwise. // // annot - handle to an annotation. // key - the key to the requested dictionary entry, encoded in UTF-8. // value - receives the value, must not be NULL. // // Returns True if value found, False otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_GetNumberValue(FPDF_ANNOTATION annot, FPDF_BYTESTRING key, float* value); // Experimental API. // Set the AP (appearance string) in |annot|'s dictionary for a given // |appearanceMode|. // // annot - handle to an annotation. // appearanceMode - the appearance mode (normal, rollover or down) for which // to get the AP. // value - the string value to be set, encoded in UTF-16LE. If // nullptr is passed, the AP is cleared for that mode. If the // mode is Normal, APs for all modes are cleared. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetAP(FPDF_ANNOTATION annot, FPDF_ANNOT_APPEARANCEMODE appearanceMode, FPDF_WIDESTRING value); // Experimental API. // Get the AP (appearance string) from |annot|'s dictionary for a given // |appearanceMode|. // |buffer| is only modified if |buflen| is large enough to hold the whole AP // string. If |buflen| is smaller, the total size of the AP is still returned, // but nothing is copied. // If there is no appearance stream for |annot| in |appearanceMode|, an empty // string is written to |buf| and 2 is returned. // On other errors, nothing is written to |buffer| and 0 is returned. // // annot - handle to an annotation. // appearanceMode - the appearance mode (normal, rollover or down) for which // to get the AP. // buffer - buffer for holding the value string, encoded in UTF-16LE. // buflen - length of the buffer in bytes. // // Returns the length of the string value in bytes. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFAnnot_GetAP(FPDF_ANNOTATION annot, FPDF_ANNOT_APPEARANCEMODE appearanceMode, FPDF_WCHAR* buffer, unsigned long buflen); // Experimental API. // Get the annotation corresponding to |key| in |annot|'s dictionary. Common // keys for linking annotations include "IRT" and "Popup". Must call // FPDFPage_CloseAnnot() when the annotation returned by this function is no // longer needed. // // annot - handle to an annotation. // key - the key to the requested dictionary entry, encoded in UTF-8. // // Returns a handle to the linked annotation object, or NULL on failure. FPDF_EXPORT FPDF_ANNOTATION FPDF_CALLCONV FPDFAnnot_GetLinkedAnnot(FPDF_ANNOTATION annot, FPDF_BYTESTRING key); // Experimental API. // Get the annotation flags of |annot|. // // annot - handle to an annotation. // // Returns the annotation flags. FPDF_EXPORT int FPDF_CALLCONV FPDFAnnot_GetFlags(FPDF_ANNOTATION annot); // Experimental API. // Set the |annot|'s flags to be of the value |flags|. // // annot - handle to an annotation. // flags - the flag values to be set. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetFlags(FPDF_ANNOTATION annot, int flags); // Experimental API. // Get the annotation flags of |annot|. // // hHandle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment(). // annot - handle to an interactive form annotation. // // Returns the annotation flags specific to interactive forms. FPDF_EXPORT int FPDF_CALLCONV FPDFAnnot_GetFormFieldFlags(FPDF_FORMHANDLE handle, FPDF_ANNOTATION annot); // Experimental API. // Sets the form field flags for an interactive form annotation. // // handle - the handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment(). // annot - handle to an interactive form annotation. // flags - the form field flags to be set. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetFormFieldFlags(FPDF_FORMHANDLE handle, FPDF_ANNOTATION annot, int flags); // Experimental API. // Retrieves an interactive form annotation whose rectangle contains a given // point on a page. Must call FPDFPage_CloseAnnot() when the annotation returned // is no longer needed. // // // hHandle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment(). // page - handle to the page, returned by FPDF_LoadPage function. // point - position in PDF "user space". // // Returns the interactive form annotation whose rectangle contains the given // coordinates on the page. If there is no such annotation, return NULL. FPDF_EXPORT FPDF_ANNOTATION FPDF_CALLCONV FPDFAnnot_GetFormFieldAtPoint(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, const FS_POINTF* point); // Experimental API. // Gets the name of |annot|, which is an interactive form annotation. // |buffer| is only modified if |buflen| is longer than the length of contents. // In case of error, nothing will be added to |buffer| and the return value will // be 0. Note that return value of empty string is 2 for "\0\0". // // hHandle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment(). // annot - handle to an interactive form annotation. // buffer - buffer for holding the name string, encoded in UTF-16LE. // buflen - length of the buffer in bytes. // // Returns the length of the string value in bytes. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFAnnot_GetFormFieldName(FPDF_FORMHANDLE hHandle, FPDF_ANNOTATION annot, FPDF_WCHAR* buffer, unsigned long buflen); // Experimental API. // Gets the alternate name of |annot|, which is an interactive form annotation. // |buffer| is only modified if |buflen| is longer than the length of contents. // In case of error, nothing will be added to |buffer| and the return value will // be 0. Note that return value of empty string is 2 for "\0\0". // // hHandle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment(). // annot - handle to an interactive form annotation. // buffer - buffer for holding the alternate name string, encoded in // UTF-16LE. // buflen - length of the buffer in bytes. // // Returns the length of the string value in bytes. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFAnnot_GetFormFieldAlternateName(FPDF_FORMHANDLE hHandle, FPDF_ANNOTATION annot, FPDF_WCHAR* buffer, unsigned long buflen); // Experimental API. // Gets the form field type of |annot|, which is an interactive form annotation. // // hHandle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment(). // annot - handle to an interactive form annotation. // // Returns the type of the form field (one of the FPDF_FORMFIELD_* values) on // success. Returns -1 on error. // See field types in fpdf_formfill.h. FPDF_EXPORT int FPDF_CALLCONV FPDFAnnot_GetFormFieldType(FPDF_FORMHANDLE hHandle, FPDF_ANNOTATION annot); // Experimental API. // Gets the value of |annot|, which is an interactive form annotation. // |buffer| is only modified if |buflen| is longer than the length of contents. // In case of error, nothing will be added to |buffer| and the return value will // be 0. Note that return value of empty string is 2 for "\0\0". // // hHandle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment(). // annot - handle to an interactive form annotation. // buffer - buffer for holding the value string, encoded in UTF-16LE. // buflen - length of the buffer in bytes. // // Returns the length of the string value in bytes. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFAnnot_GetFormFieldValue(FPDF_FORMHANDLE hHandle, FPDF_ANNOTATION annot, FPDF_WCHAR* buffer, unsigned long buflen); // Experimental API. // Get the number of options in the |annot|'s "Opt" dictionary. Intended for // use with listbox and combobox widget annotations. // // hHandle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment. // annot - handle to an annotation. // // Returns the number of options in "Opt" dictionary on success. Return value // will be -1 if annotation does not have an "Opt" dictionary or other error. FPDF_EXPORT int FPDF_CALLCONV FPDFAnnot_GetOptionCount(FPDF_FORMHANDLE hHandle, FPDF_ANNOTATION annot); // Experimental API. // Get the string value for the label of the option at |index| in |annot|'s // "Opt" dictionary. Intended for use with listbox and combobox widget // annotations. |buffer| is only modified if |buflen| is longer than the length // of contents. If index is out of range or in case of other error, nothing // will be added to |buffer| and the return value will be 0. Note that // return value of empty string is 2 for "\0\0". // // hHandle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment. // annot - handle to an annotation. // index - numeric index of the option in the "Opt" array // buffer - buffer for holding the value string, encoded in UTF-16LE. // buflen - length of the buffer in bytes. // // Returns the length of the string value in bytes. // If |annot| does not have an "Opt" array, |index| is out of range or if any // other error occurs, returns 0. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFAnnot_GetOptionLabel(FPDF_FORMHANDLE hHandle, FPDF_ANNOTATION annot, int index, FPDF_WCHAR* buffer, unsigned long buflen); // Experimental API. // Determine whether or not the option at |index| in |annot|'s "Opt" dictionary // is selected. Intended for use with listbox and combobox widget annotations. // // handle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment. // annot - handle to an annotation. // index - numeric index of the option in the "Opt" array. // // Returns true if the option at |index| in |annot|'s "Opt" dictionary is // selected, false otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_IsOptionSelected(FPDF_FORMHANDLE handle, FPDF_ANNOTATION annot, int index); // Experimental API. // Get the float value of the font size for an |annot| with variable text. // If 0, the font is to be auto-sized: its size is computed as a function of // the height of the annotation rectangle. // // hHandle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment. // annot - handle to an annotation. // value - Required. Float which will be set to font size on success. // // Returns true if the font size was set in |value|, false on error or if // |value| not provided. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_GetFontSize(FPDF_FORMHANDLE hHandle, FPDF_ANNOTATION annot, float* value); // Experimental API. // Set the text color of an annotation. // // handle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment. // annot - handle to an annotation. // R - the red component for the text color. // G - the green component for the text color. // B - the blue component for the text color. // // Returns true if successful. // // Currently supported subtypes: freetext. // The range for the color components is 0 to 255. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetFontColor(FPDF_FORMHANDLE handle, FPDF_ANNOTATION annot, unsigned int R, unsigned int G, unsigned int B); // Experimental API. // Get the RGB value of the font color for an |annot| with variable text. // // hHandle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment. // annot - handle to an annotation. // R, G, B - buffer to hold the RGB value of the color. Ranges from 0 to 255. // // Returns true if the font color was set, false on error or if the font // color was not provided. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_GetFontColor(FPDF_FORMHANDLE hHandle, FPDF_ANNOTATION annot, unsigned int* R, unsigned int* G, unsigned int* B); // Experimental API. // Determine if |annot| is a form widget that is checked. Intended for use with // checkbox and radio button widgets. // // hHandle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment. // annot - handle to an annotation. // // Returns true if |annot| is a form widget and is checked, false otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_IsChecked(FPDF_FORMHANDLE hHandle, FPDF_ANNOTATION annot); // Experimental API. // Set the list of focusable annotation subtypes. Annotations of subtype // FPDF_ANNOT_WIDGET are by default focusable. New subtypes set using this API // will override the existing subtypes. // // hHandle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment. // subtypes - list of annotation subtype which can be tabbed over. // count - total number of annotation subtype in list. // Returns true if list of annotation subtype is set successfully, false // otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetFocusableSubtypes(FPDF_FORMHANDLE hHandle, const FPDF_ANNOTATION_SUBTYPE* subtypes, size_t count); // Experimental API. // Get the count of focusable annotation subtypes as set by host // for a |hHandle|. // // hHandle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment. // Returns the count of focusable annotation subtypes or -1 on error. // Note : Annotations of type FPDF_ANNOT_WIDGET are by default focusable. FPDF_EXPORT int FPDF_CALLCONV FPDFAnnot_GetFocusableSubtypesCount(FPDF_FORMHANDLE hHandle); // Experimental API. // Get the list of focusable annotation subtype as set by host. // // hHandle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment. // subtypes - receives the list of annotation subtype which can be tabbed // over. Caller must have allocated |subtypes| more than or // equal to the count obtained from // FPDFAnnot_GetFocusableSubtypesCount() API. // count - size of |subtypes|. // Returns true on success and set list of annotation subtype to |subtypes|, // false otherwise. // Note : Annotations of type FPDF_ANNOT_WIDGET are by default focusable. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_GetFocusableSubtypes(FPDF_FORMHANDLE hHandle, FPDF_ANNOTATION_SUBTYPE* subtypes, size_t count); // Experimental API. // Gets FPDF_LINK object for |annot|. Intended to use for link annotations. // // annot - handle to an annotation. // // Returns FPDF_LINK from the FPDF_ANNOTATION and NULL on failure, // if the input annot is NULL or input annot's subtype is not link. FPDF_EXPORT FPDF_LINK FPDF_CALLCONV FPDFAnnot_GetLink(FPDF_ANNOTATION annot); // Experimental API. // Gets the count of annotations in the |annot|'s control group. // A group of interactive form annotations is collectively called a form // control group. Here, |annot|, an interactive form annotation, should be // either a radio button or a checkbox. // // hHandle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment. // annot - handle to an annotation. // // Returns number of controls in its control group or -1 on error. FPDF_EXPORT int FPDF_CALLCONV FPDFAnnot_GetFormControlCount(FPDF_FORMHANDLE hHandle, FPDF_ANNOTATION annot); // Experimental API. // Gets the index of |annot| in |annot|'s control group. // A group of interactive form annotations is collectively called a form // control group. Here, |annot|, an interactive form annotation, should be // either a radio button or a checkbox. // // hHandle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment. // annot - handle to an annotation. // // Returns index of a given |annot| in its control group or -1 on error. FPDF_EXPORT int FPDF_CALLCONV FPDFAnnot_GetFormControlIndex(FPDF_FORMHANDLE hHandle, FPDF_ANNOTATION annot); // Experimental API. // Gets the export value of |annot| which is an interactive form annotation. // Intended for use with radio button and checkbox widget annotations. // |buffer| is only modified if |buflen| is longer than the length of contents. // In case of error, nothing will be added to |buffer| and the return value // will be 0. Note that return value of empty string is 2 for "\0\0". // // hHandle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment(). // annot - handle to an interactive form annotation. // buffer - buffer for holding the value string, encoded in UTF-16LE. // buflen - length of the buffer in bytes. // // Returns the length of the string value in bytes. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFAnnot_GetFormFieldExportValue(FPDF_FORMHANDLE hHandle, FPDF_ANNOTATION annot, FPDF_WCHAR* buffer, unsigned long buflen); // Experimental API. // Add a URI action to |annot|, overwriting the existing action, if any. // // annot - handle to a link annotation. // uri - the URI to be set, encoded in 7-bit ASCII. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetURI(FPDF_ANNOTATION annot, const char* uri); // Experimental API. // Get the attachment from |annot|. // // annot - handle to a file annotation. // // Returns the handle to the attachment object, or NULL on failure. FPDF_EXPORT FPDF_ATTACHMENT FPDF_CALLCONV FPDFAnnot_GetFileAttachment(FPDF_ANNOTATION annot); // Experimental API. // Add an embedded file with |name| to |annot|. // // annot - handle to a file annotation. // name - name of the new attachment. // // Returns a handle to the new attachment object, or NULL on failure. FPDF_EXPORT FPDF_ATTACHMENT FPDF_CALLCONV FPDFAnnot_AddFileAttachment(FPDF_ANNOTATION annot, FPDF_WIDESTRING name); #ifdef __cplusplus } // extern "C" #endif // __cplusplus #endif // PUBLIC_FPDF_ANNOT_H_ ================================================ FILE: external/pdfium/macos-arm64/include/fpdf_attachment.h ================================================ // Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef PUBLIC_FPDF_ATTACHMENT_H_ #define PUBLIC_FPDF_ATTACHMENT_H_ // NOLINTNEXTLINE(build/include) #include "fpdfview.h" #ifdef __cplusplus extern "C" { #endif // __cplusplus // Experimental API. // Get the number of embedded files in |document|. // // document - handle to a document. // // Returns the number of embedded files in |document|. FPDF_EXPORT int FPDF_CALLCONV FPDFDoc_GetAttachmentCount(FPDF_DOCUMENT document); // Experimental API. // Add an embedded file with |name| in |document|. If |name| is empty, or if // |name| is the name of a existing embedded file in |document|, or if // |document|'s embedded file name tree is too deep (i.e. |document| has too // many embedded files already), then a new attachment will not be added. // // document - handle to a document. // name - name of the new attachment. // // Returns a handle to the new attachment object, or NULL on failure. FPDF_EXPORT FPDF_ATTACHMENT FPDF_CALLCONV FPDFDoc_AddAttachment(FPDF_DOCUMENT document, FPDF_WIDESTRING name); // Experimental API. // Get the embedded attachment at |index| in |document|. Note that the returned // attachment handle is only valid while |document| is open. // // document - handle to a document. // index - the index of the requested embedded file. // // Returns the handle to the attachment object, or NULL on failure. FPDF_EXPORT FPDF_ATTACHMENT FPDF_CALLCONV FPDFDoc_GetAttachment(FPDF_DOCUMENT document, int index); // Experimental API. // Delete the embedded attachment at |index| in |document|. Note that this does // not remove the attachment data from the PDF file; it simply removes the // file's entry in the embedded files name tree so that it does not appear in // the attachment list. This behavior may change in the future. // // document - handle to a document. // index - the index of the embedded file to be deleted. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFDoc_DeleteAttachment(FPDF_DOCUMENT document, int index); // Experimental API. // Get the name of the |attachment| file. |buffer| is only modified if |buflen| // is longer than the length of the file name. On errors, |buffer| is unmodified // and the returned length is 0. // // attachment - handle to an attachment. // buffer - buffer for holding the file name, encoded in UTF-16LE. // buflen - length of the buffer in bytes. // // Returns the length of the file name in bytes. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFAttachment_GetName(FPDF_ATTACHMENT attachment, FPDF_WCHAR* buffer, unsigned long buflen); // Experimental API. // Check if the params dictionary of |attachment| has |key| as a key. // // attachment - handle to an attachment. // key - the key to look for, encoded in UTF-8. // // Returns true if |key| exists. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAttachment_HasKey(FPDF_ATTACHMENT attachment, FPDF_BYTESTRING key); // Experimental API. // Get the type of the value corresponding to |key| in the params dictionary of // the embedded |attachment|. // // attachment - handle to an attachment. // key - the key to look for, encoded in UTF-8. // // Returns the type of the dictionary value. FPDF_EXPORT FPDF_OBJECT_TYPE FPDF_CALLCONV FPDFAttachment_GetValueType(FPDF_ATTACHMENT attachment, FPDF_BYTESTRING key); // Experimental API. // Set the string value corresponding to |key| in the params dictionary of the // embedded file |attachment|, overwriting the existing value if any. The value // type should be FPDF_OBJECT_STRING after this function call succeeds. // // attachment - handle to an attachment. // key - the key to the dictionary entry, encoded in UTF-8. // value - the string value to be set, encoded in UTF-16LE. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAttachment_SetStringValue(FPDF_ATTACHMENT attachment, FPDF_BYTESTRING key, FPDF_WIDESTRING value); // Experimental API. // Get the string value corresponding to |key| in the params dictionary of the // embedded file |attachment|. |buffer| is only modified if |buflen| is longer // than the length of the string value. Note that if |key| does not exist in the // dictionary or if |key|'s corresponding value in the dictionary is not a // string (i.e. the value is not of type FPDF_OBJECT_STRING or // FPDF_OBJECT_NAME), then an empty string would be copied to |buffer| and the // return value would be 2. On other errors, nothing would be added to |buffer| // and the return value would be 0. // // attachment - handle to an attachment. // key - the key to the requested string value, encoded in UTF-8. // buffer - buffer for holding the string value encoded in UTF-16LE. // buflen - length of the buffer in bytes. // // Returns the length of the dictionary value string in bytes. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFAttachment_GetStringValue(FPDF_ATTACHMENT attachment, FPDF_BYTESTRING key, FPDF_WCHAR* buffer, unsigned long buflen); // Experimental API. // Set the file data of |attachment|, overwriting the existing file data if any. // The creation date and checksum will be updated, while all other dictionary // entries will be deleted. Note that only contents with |len| smaller than // INT_MAX is supported. // // attachment - handle to an attachment. // contents - buffer holding the file data to write to |attachment|. // len - length of file data in bytes. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAttachment_SetFile(FPDF_ATTACHMENT attachment, FPDF_DOCUMENT document, const void* contents, unsigned long len); // Experimental API. // Get the file data of |attachment|. // When the attachment file data is readable, true is returned, and |out_buflen| // is updated to indicate the file data size. |buffer| is only modified if // |buflen| is non-null and long enough to contain the entire file data. Callers // must check both the return value and the input |buflen| is no less than the // returned |out_buflen| before using the data. // // Otherwise, when the attachment file data is unreadable or when |out_buflen| // is null, false is returned and |buffer| and |out_buflen| remain unmodified. // // attachment - handle to an attachment. // buffer - buffer for holding the file data from |attachment|. // buflen - length of the buffer in bytes. // out_buflen - pointer to the variable that will receive the minimum buffer // size to contain the file data of |attachment|. // // Returns true on success, false otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAttachment_GetFile(FPDF_ATTACHMENT attachment, void* buffer, unsigned long buflen, unsigned long* out_buflen); // Experimental API. // Get the MIME type (Subtype) of the embedded file |attachment|. |buffer| is // only modified if |buflen| is longer than the length of the MIME type string. // If the Subtype is not found or if there is no file stream, an empty string // would be copied to |buffer| and the return value would be 2. On other errors, // nothing would be added to |buffer| and the return value would be 0. // // attachment - handle to an attachment. // buffer - buffer for holding the MIME type string encoded in UTF-16LE. // buflen - length of the buffer in bytes. // // Returns the length of the MIME type string in bytes. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFAttachment_GetSubtype(FPDF_ATTACHMENT attachment, FPDF_WCHAR* buffer, unsigned long buflen); #ifdef __cplusplus } // extern "C" #endif // __cplusplus #endif // PUBLIC_FPDF_ATTACHMENT_H_ ================================================ FILE: external/pdfium/macos-arm64/include/fpdf_catalog.h ================================================ // Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef PUBLIC_FPDF_CATALOG_H_ #define PUBLIC_FPDF_CATALOG_H_ // NOLINTNEXTLINE(build/include) #include "fpdfview.h" #ifdef __cplusplus extern "C" { #endif // __cplusplus // Experimental API. // // Determine if |document| represents a tagged PDF. // // For the definition of tagged PDF, See (see 10.7 "Tagged PDF" in PDF // Reference 1.7). // // document - handle to a document. // // Returns |true| iff |document| is a tagged PDF. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFCatalog_IsTagged(FPDF_DOCUMENT document); // Experimental API. // Gets the language of |document| from the catalog's /Lang entry. // // document - handle to a document. // buffer - a buffer for the language string. May be NULL. // buflen - the length of the buffer, in bytes. May be 0. // // Returns the number of bytes in the language string, including the // trailing NUL character. The number of bytes is returned regardless of the // |buffer| and |buflen| parameters. // // Regardless of the platform, the |buffer| is always in UTF-16LE // encoding. The string is terminated by a UTF16 NUL character. If // |buflen| is less than the required length, or |buffer| is NULL, // |buffer| will not be modified. // // If |document| has no /Lang entry, an empty string is written to |buffer| and // 2 is returned. On error, nothing is written to |buffer| and 0 is returned. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFCatalog_GetLanguage(FPDF_DOCUMENT document, FPDF_WCHAR* buffer, unsigned long buflen); // Experimental API. // Sets the language of |document| to |language|. // // document - handle to a document. // language - the language to set to. // // Returns TRUE on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFCatalog_SetLanguage(FPDF_DOCUMENT document, FPDF_WIDESTRING language); #ifdef __cplusplus } // extern "C" #endif // __cplusplus #endif // PUBLIC_FPDF_CATALOG_H_ ================================================ FILE: external/pdfium/macos-arm64/include/fpdf_dataavail.h ================================================ // Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #ifndef PUBLIC_FPDF_DATAAVAIL_H_ #define PUBLIC_FPDF_DATAAVAIL_H_ #include // NOLINTNEXTLINE(build/include) #include "fpdfview.h" #define PDF_LINEARIZATION_UNKNOWN -1 #define PDF_NOT_LINEARIZED 0 #define PDF_LINEARIZED 1 #define PDF_DATA_ERROR -1 #define PDF_DATA_NOTAVAIL 0 #define PDF_DATA_AVAIL 1 #define PDF_FORM_ERROR -1 #define PDF_FORM_NOTAVAIL 0 #define PDF_FORM_AVAIL 1 #define PDF_FORM_NOTEXIST 2 #ifdef __cplusplus extern "C" { #endif // __cplusplus // Interface for checking whether sections of the file are available. typedef struct _FX_FILEAVAIL { // Version number of the interface. Must be 1. int version; // Reports if the specified data section is currently available. A section is // available if all bytes in the section are available. // // Interface Version: 1 // Implementation Required: Yes // // pThis - pointer to the interface structure. // offset - the offset of the data section in the file. // size - the size of the data section. // // Returns true if the specified data section at |offset| of |size| // is available. FPDF_BOOL (*IsDataAvail)(struct _FX_FILEAVAIL* pThis, size_t offset, size_t size); } FX_FILEAVAIL; // Create a document availability provider. // // file_avail - pointer to file availability interface. // file - pointer to a file access interface. // // Returns a handle to the document availability provider, or NULL on error. // // FPDFAvail_Destroy() must be called when done with the availability provider. FPDF_EXPORT FPDF_AVAIL FPDF_CALLCONV FPDFAvail_Create(FX_FILEAVAIL* file_avail, FPDF_FILEACCESS* file); // Destroy the |avail| document availability provider. // // avail - handle to document availability provider to be destroyed. FPDF_EXPORT void FPDF_CALLCONV FPDFAvail_Destroy(FPDF_AVAIL avail); // Download hints interface. Used to receive hints for further downloading. typedef struct _FX_DOWNLOADHINTS { // Version number of the interface. Must be 1. int version; // Add a section to be downloaded. // // Interface Version: 1 // Implementation Required: Yes // // pThis - pointer to the interface structure. // offset - the offset of the hint reported to be downloaded. // size - the size of the hint reported to be downloaded. // // The |offset| and |size| of the section may not be unique. Part of the // section might be already available. The download manager must deal with // overlapping sections. void (*AddSegment)(struct _FX_DOWNLOADHINTS* pThis, size_t offset, size_t size); } FX_DOWNLOADHINTS; // Checks if the document is ready for loading, if not, gets download hints. // // avail - handle to document availability provider. // hints - pointer to a download hints interface. // // Returns one of: // PDF_DATA_ERROR: A common error is returned. Data availability unknown. // PDF_DATA_NOTAVAIL: Data not yet available. // PDF_DATA_AVAIL: Data available. // // Applications should call this function whenever new data arrives, and process // all the generated download hints, if any, until the function returns // |PDF_DATA_ERROR| or |PDF_DATA_AVAIL|. // if hints is nullptr, the function just check current document availability. // // Once all data is available, call FPDFAvail_GetDocument() to get a document // handle. FPDF_EXPORT int FPDF_CALLCONV FPDFAvail_IsDocAvail(FPDF_AVAIL avail, FX_DOWNLOADHINTS* hints); // Get document from the availability provider. // // avail - handle to document availability provider. // password - password for decrypting the PDF file. Optional. // // Returns a handle to the document. // // When FPDFAvail_IsDocAvail() returns TRUE, call FPDFAvail_GetDocument() to // retrieve the document handle. // See the comments for FPDF_LoadDocument() regarding the encoding for // |password|. FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV FPDFAvail_GetDocument(FPDF_AVAIL avail, FPDF_BYTESTRING password); // Get the page number for the first available page in a linearized PDF. // // doc - document handle. // // Returns the zero-based index for the first available page. // // For most linearized PDFs, the first available page will be the first page, // however, some PDFs might make another page the first available page. // For non-linearized PDFs, this function will always return zero. FPDF_EXPORT int FPDF_CALLCONV FPDFAvail_GetFirstPageNum(FPDF_DOCUMENT doc); // Check if |page_index| is ready for loading, if not, get the // |FX_DOWNLOADHINTS|. // // avail - handle to document availability provider. // page_index - index number of the page. Zero for the first page. // hints - pointer to a download hints interface. Populated if // |page_index| is not available. // // Returns one of: // PDF_DATA_ERROR: A common error is returned. Data availability unknown. // PDF_DATA_NOTAVAIL: Data not yet available. // PDF_DATA_AVAIL: Data available. // // This function can be called only after FPDFAvail_GetDocument() is called. // Applications should call this function whenever new data arrives and process // all the generated download |hints|, if any, until this function returns // |PDF_DATA_ERROR| or |PDF_DATA_AVAIL|. Applications can then perform page // loading. // if hints is nullptr, the function just check current availability of // specified page. FPDF_EXPORT int FPDF_CALLCONV FPDFAvail_IsPageAvail(FPDF_AVAIL avail, int page_index, FX_DOWNLOADHINTS* hints); // Check if form data is ready for initialization, if not, get the // |FX_DOWNLOADHINTS|. // // avail - handle to document availability provider. // hints - pointer to a download hints interface. Populated if form is not // ready for initialization. // // Returns one of: // PDF_FORM_ERROR: A common eror, in general incorrect parameters. // PDF_FORM_NOTAVAIL: Data not available. // PDF_FORM_AVAIL: Data available. // PDF_FORM_NOTEXIST: No form data. // // This function can be called only after FPDFAvail_GetDocument() is called. // The application should call this function whenever new data arrives and // process all the generated download |hints|, if any, until the function // |PDF_FORM_ERROR|, |PDF_FORM_AVAIL| or |PDF_FORM_NOTEXIST|. // if hints is nullptr, the function just check current form availability. // // Applications can then perform page loading. It is recommend to call // FPDFDOC_InitFormFillEnvironment() when |PDF_FORM_AVAIL| is returned. FPDF_EXPORT int FPDF_CALLCONV FPDFAvail_IsFormAvail(FPDF_AVAIL avail, FX_DOWNLOADHINTS* hints); // Check whether a document is a linearized PDF. // // avail - handle to document availability provider. // // Returns one of: // PDF_LINEARIZED // PDF_NOT_LINEARIZED // PDF_LINEARIZATION_UNKNOWN // // FPDFAvail_IsLinearized() will return |PDF_LINEARIZED| or |PDF_NOT_LINEARIZED| // when we have 1k of data. If the files size less than 1k, it returns // |PDF_LINEARIZATION_UNKNOWN| as there is insufficient information to determine // if the PDF is linearlized. FPDF_EXPORT int FPDF_CALLCONV FPDFAvail_IsLinearized(FPDF_AVAIL avail); #ifdef __cplusplus } // extern "C" #endif // __cplusplus #endif // PUBLIC_FPDF_DATAAVAIL_H_ ================================================ FILE: external/pdfium/macos-arm64/include/fpdf_doc.h ================================================ // Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #ifndef PUBLIC_FPDF_DOC_H_ #define PUBLIC_FPDF_DOC_H_ // NOLINTNEXTLINE(build/include) #include "fpdfview.h" #ifdef __cplusplus extern "C" { #endif // __cplusplus // Unsupported action type. #define PDFACTION_UNSUPPORTED 0 // Go to a destination within current document. #define PDFACTION_GOTO 1 // Go to a destination within another document. #define PDFACTION_REMOTEGOTO 2 // URI, including web pages and other Internet resources. #define PDFACTION_URI 3 // Launch an application or open a file. #define PDFACTION_LAUNCH 4 // Go to a destination in an embedded file. #define PDFACTION_EMBEDDEDGOTO 5 // View destination fit types. See pdfmark reference v9, page 48. #define PDFDEST_VIEW_UNKNOWN_MODE 0 #define PDFDEST_VIEW_XYZ 1 #define PDFDEST_VIEW_FIT 2 #define PDFDEST_VIEW_FITH 3 #define PDFDEST_VIEW_FITV 4 #define PDFDEST_VIEW_FITR 5 #define PDFDEST_VIEW_FITB 6 #define PDFDEST_VIEW_FITBH 7 #define PDFDEST_VIEW_FITBV 8 // The file identifier entry type. See section 14.4 "File Identifiers" of the // ISO 32000-1:2008 spec. typedef enum { FILEIDTYPE_PERMANENT = 0, FILEIDTYPE_CHANGING = 1 } FPDF_FILEIDTYPE; // Get the first child of |bookmark|, or the first top-level bookmark item. // // document - handle to the document. // bookmark - handle to the current bookmark. Pass NULL for the first top // level item. // // Returns a handle to the first child of |bookmark| or the first top-level // bookmark item. NULL if no child or top-level bookmark found. // Note that another name for the bookmarks is the document outline, as // described in ISO 32000-1:2008, section 12.3.3. FPDF_EXPORT FPDF_BOOKMARK FPDF_CALLCONV FPDFBookmark_GetFirstChild(FPDF_DOCUMENT document, FPDF_BOOKMARK bookmark); // Get the next sibling of |bookmark|. // // document - handle to the document. // bookmark - handle to the current bookmark. // // Returns a handle to the next sibling of |bookmark|, or NULL if this is the // last bookmark at this level. // // Note that the caller is responsible for handling circular bookmark // references, as may arise from malformed documents. FPDF_EXPORT FPDF_BOOKMARK FPDF_CALLCONV FPDFBookmark_GetNextSibling(FPDF_DOCUMENT document, FPDF_BOOKMARK bookmark); // Get the title of |bookmark|. // // bookmark - handle to the bookmark. // buffer - buffer for the title. May be NULL. // buflen - the length of the buffer in bytes. May be 0. // // Returns the number of bytes in the title, including the terminating NUL // character. The number of bytes is returned regardless of the |buffer| and // |buflen| parameters. // // Regardless of the platform, the |buffer| is always in UTF-16LE encoding. The // string is terminated by a UTF16 NUL character. If |buflen| is less than the // required length, or |buffer| is NULL, |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFBookmark_GetTitle(FPDF_BOOKMARK bookmark, void* buffer, unsigned long buflen); // Experimental API. // Get the number of chlidren of |bookmark|. // // bookmark - handle to the bookmark. // // Returns a signed integer that represents the number of sub-items the given // bookmark has. If the value is positive, child items shall be shown by default // (open state). If the value is negative, child items shall be hidden by // default (closed state). Please refer to PDF 32000-1:2008, Table 153. // Returns 0 if the bookmark has no children or is invalid. FPDF_EXPORT int FPDF_CALLCONV FPDFBookmark_GetCount(FPDF_BOOKMARK bookmark); // Find the bookmark with |title| in |document|. // // document - handle to the document. // title - the UTF-16LE encoded Unicode title for which to search. // // Returns the handle to the bookmark, or NULL if |title| can't be found. // // FPDFBookmark_Find() will always return the first bookmark found even if // multiple bookmarks have the same |title|. FPDF_EXPORT FPDF_BOOKMARK FPDF_CALLCONV FPDFBookmark_Find(FPDF_DOCUMENT document, FPDF_WIDESTRING title); // Get the destination associated with |bookmark|. // // document - handle to the document. // bookmark - handle to the bookmark. // // Returns the handle to the destination data, or NULL if no destination is // associated with |bookmark|. FPDF_EXPORT FPDF_DEST FPDF_CALLCONV FPDFBookmark_GetDest(FPDF_DOCUMENT document, FPDF_BOOKMARK bookmark); // Get the action associated with |bookmark|. // // bookmark - handle to the bookmark. // // Returns the handle to the action data, or NULL if no action is associated // with |bookmark|. // If this function returns a valid handle, it is valid as long as |bookmark| is // valid. // If this function returns NULL, FPDFBookmark_GetDest() should be called to get // the |bookmark| destination data. FPDF_EXPORT FPDF_ACTION FPDF_CALLCONV FPDFBookmark_GetAction(FPDF_BOOKMARK bookmark); // Get the type of |action|. // // action - handle to the action. // // Returns one of: // PDFACTION_UNSUPPORTED // PDFACTION_GOTO // PDFACTION_REMOTEGOTO // PDFACTION_URI // PDFACTION_LAUNCH FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFAction_GetType(FPDF_ACTION action); // Get the destination of |action|. // // document - handle to the document. // action - handle to the action. |action| must be a |PDFACTION_GOTO| or // |PDFACTION_REMOTEGOTO|. // // Returns a handle to the destination data, or NULL on error, typically // because the arguments were bad or the action was of the wrong type. // // In the case of |PDFACTION_REMOTEGOTO|, you must first call // FPDFAction_GetFilePath(), then load the document at that path, then pass // the document handle from that document as |document| to FPDFAction_GetDest(). FPDF_EXPORT FPDF_DEST FPDF_CALLCONV FPDFAction_GetDest(FPDF_DOCUMENT document, FPDF_ACTION action); // Get the file path of |action|. // // action - handle to the action. |action| must be a |PDFACTION_LAUNCH| or // |PDFACTION_REMOTEGOTO|. // buffer - a buffer for output the path string. May be NULL. // buflen - the length of the buffer, in bytes. May be 0. // // Returns the number of bytes in the file path, including the trailing NUL // character, or 0 on error, typically because the arguments were bad or the // action was of the wrong type. // // Regardless of the platform, the |buffer| is always in UTF-8 encoding. // If |buflen| is less than the returned length, or |buffer| is NULL, |buffer| // will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFAction_GetFilePath(FPDF_ACTION action, void* buffer, unsigned long buflen); // Get the URI path of |action|. // // document - handle to the document. // action - handle to the action. Must be a |PDFACTION_URI|. // buffer - a buffer for the path string. May be NULL. // buflen - the length of the buffer, in bytes. May be 0. // // Returns the number of bytes in the URI path, including the trailing NUL // character, or 0 on error, typically because the arguments were bad or the // action was of the wrong type. // // The |buffer| may contain badly encoded data. The caller should validate the // output. e.g. Check to see if it is UTF-8. // // If |buflen| is less than the returned length, or |buffer| is NULL, |buffer| // will not be modified. // // Historically, the documentation for this API claimed |buffer| is always // encoded in 7-bit ASCII, but did not actually enforce it. // https://pdfium.googlesource.com/pdfium.git/+/d609e84cee2e14a18333247485af91df48a40592 // added that enforcement, but that did not work well for real world PDFs that // used UTF-8. As of this writing, this API reverted back to its original // behavior prior to commit d609e84cee. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFAction_GetURIPath(FPDF_DOCUMENT document, FPDF_ACTION action, void* buffer, unsigned long buflen); // Get the page index of |dest|. // // document - handle to the document. // dest - handle to the destination. // // Returns the 0-based page index containing |dest|. Returns -1 on error. FPDF_EXPORT int FPDF_CALLCONV FPDFDest_GetDestPageIndex(FPDF_DOCUMENT document, FPDF_DEST dest); // Experimental API. // Get the view (fit type) specified by |dest|. // // dest - handle to the destination. // pNumParams - receives the number of view parameters, which is at most 4. // pParams - buffer to write the view parameters. Must be at least 4 // FS_FLOATs long. // Returns one of the PDFDEST_VIEW_* constants, PDFDEST_VIEW_UNKNOWN_MODE if // |dest| does not specify a view. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFDest_GetView(FPDF_DEST dest, unsigned long* pNumParams, FS_FLOAT* pParams); // Get the (x, y, zoom) location of |dest| in the destination page, if the // destination is in [page /XYZ x y zoom] syntax. // // dest - handle to the destination. // hasXVal - out parameter; true if the x value is not null // hasYVal - out parameter; true if the y value is not null // hasZoomVal - out parameter; true if the zoom value is not null // x - out parameter; the x coordinate, in page coordinates. // y - out parameter; the y coordinate, in page coordinates. // zoom - out parameter; the zoom value. // Returns TRUE on successfully reading the /XYZ value. // // Note the [x, y, zoom] values are only set if the corresponding hasXVal, // hasYVal or hasZoomVal flags are true. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFDest_GetLocationInPage(FPDF_DEST dest, FPDF_BOOL* hasXVal, FPDF_BOOL* hasYVal, FPDF_BOOL* hasZoomVal, FS_FLOAT* x, FS_FLOAT* y, FS_FLOAT* zoom); // Find a link at point (|x|,|y|) on |page|. // // page - handle to the document page. // x - the x coordinate, in the page coordinate system. // y - the y coordinate, in the page coordinate system. // // Returns a handle to the link, or NULL if no link found at the given point. // // You can convert coordinates from screen coordinates to page coordinates using // FPDF_DeviceToPage(). FPDF_EXPORT FPDF_LINK FPDF_CALLCONV FPDFLink_GetLinkAtPoint(FPDF_PAGE page, double x, double y); // Find the Z-order of link at point (|x|,|y|) on |page|. // // page - handle to the document page. // x - the x coordinate, in the page coordinate system. // y - the y coordinate, in the page coordinate system. // // Returns the Z-order of the link, or -1 if no link found at the given point. // Larger Z-order numbers are closer to the front. // // You can convert coordinates from screen coordinates to page coordinates using // FPDF_DeviceToPage(). FPDF_EXPORT int FPDF_CALLCONV FPDFLink_GetLinkZOrderAtPoint(FPDF_PAGE page, double x, double y); // Get destination info for |link|. // // document - handle to the document. // link - handle to the link. // // Returns a handle to the destination, or NULL if there is no destination // associated with the link. In this case, you should call FPDFLink_GetAction() // to retrieve the action associated with |link|. FPDF_EXPORT FPDF_DEST FPDF_CALLCONV FPDFLink_GetDest(FPDF_DOCUMENT document, FPDF_LINK link); // Get action info for |link|. // // link - handle to the link. // // Returns a handle to the action associated to |link|, or NULL if no action. // If this function returns a valid handle, it is valid as long as |link| is // valid. FPDF_EXPORT FPDF_ACTION FPDF_CALLCONV FPDFLink_GetAction(FPDF_LINK link); // Enumerates all the link annotations in |page|. // // page - handle to the page. // start_pos - the start position, should initially be 0 and is updated with // the next start position on return. // link_annot - the link handle for |startPos|. // // Returns TRUE on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFLink_Enumerate(FPDF_PAGE page, int* start_pos, FPDF_LINK* link_annot); // Experimental API. // Gets FPDF_ANNOTATION object for |link_annot|. // // page - handle to the page in which FPDF_LINK object is present. // link_annot - handle to link annotation. // // Returns FPDF_ANNOTATION from the FPDF_LINK and NULL on failure, // if the input link annot or page is NULL. FPDF_EXPORT FPDF_ANNOTATION FPDF_CALLCONV FPDFLink_GetAnnot(FPDF_PAGE page, FPDF_LINK link_annot); // Get the rectangle for |link_annot|. // // link_annot - handle to the link annotation. // rect - the annotation rectangle. // // Returns true on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFLink_GetAnnotRect(FPDF_LINK link_annot, FS_RECTF* rect); // Get the count of quadrilateral points to the |link_annot|. // // link_annot - handle to the link annotation. // // Returns the count of quadrilateral points. FPDF_EXPORT int FPDF_CALLCONV FPDFLink_CountQuadPoints(FPDF_LINK link_annot); // Get the quadrilateral points for the specified |quad_index| in |link_annot|. // // link_annot - handle to the link annotation. // quad_index - the specified quad point index. // quad_points - receives the quadrilateral points. // // Returns true on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFLink_GetQuadPoints(FPDF_LINK link_annot, int quad_index, FS_QUADPOINTSF* quad_points); // Experimental API // Gets an additional-action from |page|. // // page - handle to the page, as returned by FPDF_LoadPage(). // aa_type - the type of the page object's addtional-action, defined // in public/fpdf_formfill.h // // Returns the handle to the action data, or NULL if there is no // additional-action of type |aa_type|. // If this function returns a valid handle, it is valid as long as |page| is // valid. FPDF_EXPORT FPDF_ACTION FPDF_CALLCONV FPDF_GetPageAAction(FPDF_PAGE page, int aa_type); // Experimental API. // Get the file identifer defined in the trailer of |document|. // // document - handle to the document. // id_type - the file identifier type to retrieve. // buffer - a buffer for the file identifier. May be NULL. // buflen - the length of the buffer, in bytes. May be 0. // // Returns the number of bytes in the file identifier, including the NUL // terminator. // // The |buffer| is always a byte string. The |buffer| is followed by a NUL // terminator. If |buflen| is less than the returned length, or |buffer| is // NULL, |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetFileIdentifier(FPDF_DOCUMENT document, FPDF_FILEIDTYPE id_type, void* buffer, unsigned long buflen); // Get meta-data |tag| content from |document|. // // document - handle to the document. // tag - the tag to retrieve. The tag can be one of: // Title, Author, Subject, Keywords, Creator, Producer, // CreationDate, or ModDate. // For detailed explanations of these tags and their respective // values, please refer to PDF Reference 1.6, section 10.2.1, // 'Document Information Dictionary'. // buffer - a buffer for the tag. May be NULL. // buflen - the length of the buffer, in bytes. May be 0. // // Returns the number of bytes in the tag, including trailing zeros. // // The |buffer| is always encoded in UTF-16LE. The |buffer| is followed by two // bytes of zeros indicating the end of the string. If |buflen| is less than // the returned length, or |buffer| is NULL, |buffer| will not be modified. // // For linearized files, FPDFAvail_IsFormAvail must be called before this, and // it must have returned PDF_FORM_AVAIL or PDF_FORM_NOTEXIST. Before that, there // is no guarantee the metadata has been loaded. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetMetaText(FPDF_DOCUMENT document, FPDF_BYTESTRING tag, void* buffer, unsigned long buflen); // Get the page label for |page_index| from |document|. // // document - handle to the document. // page_index - the 0-based index of the page. // buffer - a buffer for the page label. May be NULL. // buflen - the length of the buffer, in bytes. May be 0. // // Returns the number of bytes in the page label, including trailing zeros. // // The |buffer| is always encoded in UTF-16LE. The |buffer| is followed by two // bytes of zeros indicating the end of the string. If |buflen| is less than // the returned length, or |buffer| is NULL, |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetPageLabel(FPDF_DOCUMENT document, int page_index, void* buffer, unsigned long buflen); #ifdef __cplusplus } // extern "C" #endif // __cplusplus #endif // PUBLIC_FPDF_DOC_H_ ================================================ FILE: external/pdfium/macos-arm64/include/fpdf_edit.h ================================================ // Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #ifndef PUBLIC_FPDF_EDIT_H_ #define PUBLIC_FPDF_EDIT_H_ #include // NOLINTNEXTLINE(build/include_directory) #include "fpdfview.h" #define FPDF_ARGB(a, r, g, b) \ ((uint32_t)(((uint32_t)(b)&0xff) | (((uint32_t)(g)&0xff) << 8) | \ (((uint32_t)(r)&0xff) << 16) | (((uint32_t)(a)&0xff) << 24))) #define FPDF_GetBValue(argb) ((uint8_t)(argb)) #define FPDF_GetGValue(argb) ((uint8_t)(((uint16_t)(argb)) >> 8)) #define FPDF_GetRValue(argb) ((uint8_t)((argb) >> 16)) #define FPDF_GetAValue(argb) ((uint8_t)((argb) >> 24)) // Refer to PDF Reference version 1.7 table 4.12 for all color space families. #define FPDF_COLORSPACE_UNKNOWN 0 #define FPDF_COLORSPACE_DEVICEGRAY 1 #define FPDF_COLORSPACE_DEVICERGB 2 #define FPDF_COLORSPACE_DEVICECMYK 3 #define FPDF_COLORSPACE_CALGRAY 4 #define FPDF_COLORSPACE_CALRGB 5 #define FPDF_COLORSPACE_LAB 6 #define FPDF_COLORSPACE_ICCBASED 7 #define FPDF_COLORSPACE_SEPARATION 8 #define FPDF_COLORSPACE_DEVICEN 9 #define FPDF_COLORSPACE_INDEXED 10 #define FPDF_COLORSPACE_PATTERN 11 // The page object constants. #define FPDF_PAGEOBJ_UNKNOWN 0 #define FPDF_PAGEOBJ_TEXT 1 #define FPDF_PAGEOBJ_PATH 2 #define FPDF_PAGEOBJ_IMAGE 3 #define FPDF_PAGEOBJ_SHADING 4 #define FPDF_PAGEOBJ_FORM 5 // The path segment constants. #define FPDF_SEGMENT_UNKNOWN -1 #define FPDF_SEGMENT_LINETO 0 #define FPDF_SEGMENT_BEZIERTO 1 #define FPDF_SEGMENT_MOVETO 2 #define FPDF_FILLMODE_NONE 0 #define FPDF_FILLMODE_ALTERNATE 1 #define FPDF_FILLMODE_WINDING 2 #define FPDF_FONT_TYPE1 1 #define FPDF_FONT_TRUETYPE 2 #define FPDF_LINECAP_BUTT 0 #define FPDF_LINECAP_ROUND 1 #define FPDF_LINECAP_PROJECTING_SQUARE 2 #define FPDF_LINEJOIN_MITER 0 #define FPDF_LINEJOIN_ROUND 1 #define FPDF_LINEJOIN_BEVEL 2 // See FPDF_SetPrintMode() for descriptions. #define FPDF_PRINTMODE_EMF 0 #define FPDF_PRINTMODE_TEXTONLY 1 #define FPDF_PRINTMODE_POSTSCRIPT2 2 #define FPDF_PRINTMODE_POSTSCRIPT3 3 #define FPDF_PRINTMODE_POSTSCRIPT2_PASSTHROUGH 4 #define FPDF_PRINTMODE_POSTSCRIPT3_PASSTHROUGH 5 #define FPDF_PRINTMODE_EMF_IMAGE_MASKS 6 #define FPDF_PRINTMODE_POSTSCRIPT3_TYPE42 7 #define FPDF_PRINTMODE_POSTSCRIPT3_TYPE42_PASSTHROUGH 8 typedef struct FPDF_IMAGEOBJ_METADATA { // The image width in pixels. unsigned int width; // The image height in pixels. unsigned int height; // The image's horizontal pixel-per-inch. float horizontal_dpi; // The image's vertical pixel-per-inch. float vertical_dpi; // The number of bits used to represent each pixel. unsigned int bits_per_pixel; // The image's colorspace. See above for the list of FPDF_COLORSPACE_*. int colorspace; // The image's marked content ID. Useful for pairing with associated alt-text. // A value of -1 indicates no ID. int marked_content_id; } FPDF_IMAGEOBJ_METADATA; #ifdef __cplusplus extern "C" { #endif // __cplusplus // Create a new PDF document. // // Returns a handle to a new document, or NULL on failure. FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV FPDF_CreateNewDocument(); // Create a new PDF page. // // document - handle to document. // page_index - suggested 0-based index of the page to create. If it is larger // than document's current last index(L), the created page index // is the next available index -- L+1. // width - the page width in points. // height - the page height in points. // // Returns the handle to the new page or NULL on failure. // // The page should be closed with FPDF_ClosePage() when finished as // with any other page in the document. FPDF_EXPORT FPDF_PAGE FPDF_CALLCONV FPDFPage_New(FPDF_DOCUMENT document, int page_index, double width, double height); // Delete the page at |page_index|. // // document - handle to document. // page_index - the index of the page to delete. FPDF_EXPORT void FPDF_CALLCONV FPDFPage_Delete(FPDF_DOCUMENT document, int page_index); // Experimental API. // Move the given pages to a new index position. // // page_indices - the ordered list of pages to move. No duplicates allowed. // page_indices_len - the number of elements in |page_indices| // dest_page_index - the new index position to which the pages in // |page_indices| are moved. // // Returns TRUE on success. If it returns FALSE, the document may be left in an // indeterminate state. // // Example: The PDF document starts out with pages [A, B, C, D], with indices // [0, 1, 2, 3]. // // > Move(doc, [3, 2], 2, 1); // returns true // > // The document has pages [A, D, C, B]. // > // > Move(doc, [0, 4, 3], 3, 1); // returns false // > // Returned false because index 4 is out of range. // > // > Move(doc, [0, 3, 1], 3, 2); // returns false // > // Returned false because index 2 is out of range for 3 page indices. // > // > Move(doc, [2, 2], 2, 0); // returns false // > // Returned false because [2, 2] contains duplicates. // FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_MovePages(FPDF_DOCUMENT document, const int* page_indices, unsigned long page_indices_len, int dest_page_index); // Get the rotation of |page|. // // page - handle to a page // // Returns one of the following indicating the page rotation: // 0 - No rotation. // 1 - Rotated 90 degrees clockwise. // 2 - Rotated 180 degrees clockwise. // 3 - Rotated 270 degrees clockwise. FPDF_EXPORT int FPDF_CALLCONV FPDFPage_GetRotation(FPDF_PAGE page); // Set rotation for |page|. // // page - handle to a page. // rotate - the rotation value, one of: // 0 - No rotation. // 1 - Rotated 90 degrees clockwise. // 2 - Rotated 180 degrees clockwise. // 3 - Rotated 270 degrees clockwise. FPDF_EXPORT void FPDF_CALLCONV FPDFPage_SetRotation(FPDF_PAGE page, int rotate); // Insert |page_object| into |page|. // // page - handle to a page // page_object - handle to a page object. The |page_object| will be // automatically freed. FPDF_EXPORT void FPDF_CALLCONV FPDFPage_InsertObject(FPDF_PAGE page, FPDF_PAGEOBJECT page_object); // Insert |page_object| into |page| at the specified |index|. // // page - handle to a page // page_object - handle to a page object as previously obtained by // FPDFPageObj_CreateNew{Path|Rect}() or // FPDFPageObj_New{Text|Image}Obj(). Ownership of the object // is transferred back to PDFium. // index - the index position to insert the object at. If index equals // the current object count, the object will be appended to the // end. If index is greater than the object count, the function // will fail and return false. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_InsertObjectAtIndex(FPDF_PAGE page, FPDF_PAGEOBJECT page_object, size_t index); // Experimental API. // Remove |page_object| from |page|. // // page - handle to a page // page_object - handle to a page object to be removed. // // Returns TRUE on success. // // Ownership is transferred to the caller. Call FPDFPageObj_Destroy() to free // it. // Note that when removing a |page_object| of type FPDF_PAGEOBJ_TEXT, all // FPDF_TEXTPAGE handles for |page| are no longer valid. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_RemoveObject(FPDF_PAGE page, FPDF_PAGEOBJECT page_object); // Get number of page objects inside |page|. // // page - handle to a page. // // Returns the number of objects in |page|. FPDF_EXPORT int FPDF_CALLCONV FPDFPage_CountObjects(FPDF_PAGE page); // Get object in |page| at |index|. // // page - handle to a page. // index - the index of a page object. // // Returns the handle to the page object, or NULL on failed. FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV FPDFPage_GetObject(FPDF_PAGE page, int index); // Checks if |page| contains transparency. // // page - handle to a page. // // Returns TRUE if |page| contains transparency. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_HasTransparency(FPDF_PAGE page); // Generate the content of |page|. // // page - handle to a page. // // Returns TRUE on success. // // Before you save the page to a file, or reload the page, you must call // |FPDFPage_GenerateContent| or any changes to |page| will be lost. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_GenerateContent(FPDF_PAGE page); // Destroy |page_object| by releasing its resources. |page_object| must have // been created by FPDFPageObj_CreateNew{Path|Rect}() or // FPDFPageObj_New{Text|Image}Obj(). This function must be called on // newly-created objects if they are not added to a page through // FPDFPage_InsertObject() or to an annotation through FPDFAnnot_AppendObject(). // // page_object - handle to a page object. FPDF_EXPORT void FPDF_CALLCONV FPDFPageObj_Destroy(FPDF_PAGEOBJECT page_object); // Checks if |page_object| contains transparency. // // page_object - handle to a page object. // // Returns TRUE if |page_object| contains transparency. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_HasTransparency(FPDF_PAGEOBJECT page_object); // Get type of |page_object|. // // page_object - handle to a page object. // // Returns one of the FPDF_PAGEOBJ_* values on success, FPDF_PAGEOBJ_UNKNOWN on // error. FPDF_EXPORT int FPDF_CALLCONV FPDFPageObj_GetType(FPDF_PAGEOBJECT page_object); // Experimental API. // Gets active state for |page_object| within page. // // page_object - handle to a page object. // active - pointer to variable that will receive if the page object is // active. This is a required parameter. Not filled if FALSE // is returned. // // For page objects where |active| is filled with FALSE, the |page_object| is // treated as if it wasn't in the document even though it is still held // internally. // // Returns TRUE if the operation succeeded, FALSE if it failed. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_GetIsActive(FPDF_PAGEOBJECT page_object, FPDF_BOOL* active); // Experimental API. // Sets if |page_object| is active within page. // // page_object - handle to a page object. // active - a boolean specifying if the object is active. // // Returns TRUE on success. // // Page objects all start in the active state by default, and remain in that // state unless this function is called. // // When |active| is false, this makes the |page_object| be treated as if it // wasn't in the document even though it is still held internally. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_SetIsActive(FPDF_PAGEOBJECT page_object, FPDF_BOOL active); // Transform |page_object| by the given matrix. // // page_object - handle to a page object. // a - matrix value. // b - matrix value. // c - matrix value. // d - matrix value. // e - matrix value. // f - matrix value. // // The matrix is composed as: // |a c e| // |b d f| // and can be used to scale, rotate, shear and translate the |page_object|. FPDF_EXPORT void FPDF_CALLCONV FPDFPageObj_Transform(FPDF_PAGEOBJECT page_object, double a, double b, double c, double d, double e, double f); // Experimental API. // Transform |page_object| by the given matrix. // // page_object - handle to a page object. // matrix - the transform matrix. // // Returns TRUE on success. // // This can be used to scale, rotate, shear and translate the |page_object|. // It is an improved version of FPDFPageObj_Transform() that does not do // unnecessary double to float conversions, and only uses 1 parameter for the // matrix. It also returns whether the operation succeeded or not. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_TransformF(FPDF_PAGEOBJECT page_object, const FS_MATRIX* matrix); // Experimental API. // Get the transform matrix of a page object. // // page_object - handle to a page object. // matrix - pointer to struct to receive the matrix value. // // The matrix is composed as: // |a c e| // |b d f| // and used to scale, rotate, shear and translate the page object. // // For page objects outside form objects, the matrix values are relative to the // page that contains it. // For page objects inside form objects, the matrix values are relative to the // form that contains it. // // Returns TRUE on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_GetMatrix(FPDF_PAGEOBJECT page_object, FS_MATRIX* matrix); // Experimental API. // Set the transform matrix of a page object. // // page_object - handle to a page object. // matrix - pointer to struct with the matrix value. // // The matrix is composed as: // |a c e| // |b d f| // and can be used to scale, rotate, shear and translate the page object. // // Returns TRUE on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_SetMatrix(FPDF_PAGEOBJECT page_object, const FS_MATRIX* matrix); // Transform all annotations in |page|. // // page - handle to a page. // a - matrix value. // b - matrix value. // c - matrix value. // d - matrix value. // e - matrix value. // f - matrix value. // // The matrix is composed as: // |a c e| // |b d f| // and can be used to scale, rotate, shear and translate the |page| annotations. FPDF_EXPORT void FPDF_CALLCONV FPDFPage_TransformAnnots(FPDF_PAGE page, double a, double b, double c, double d, double e, double f); // Create a new image object. // // document - handle to a document. // // Returns a handle to a new image object. FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV FPDFPageObj_NewImageObj(FPDF_DOCUMENT document); // Experimental API. // Get the marked content ID for the object. // // page_object - handle to a page object. // // Returns the page object's marked content ID, or -1 on error. FPDF_EXPORT int FPDF_CALLCONV FPDFPageObj_GetMarkedContentID(FPDF_PAGEOBJECT page_object); // Experimental API. // Get number of content marks in |page_object|. // // page_object - handle to a page object. // // Returns the number of content marks in |page_object|, or -1 in case of // failure. FPDF_EXPORT int FPDF_CALLCONV FPDFPageObj_CountMarks(FPDF_PAGEOBJECT page_object); // Experimental API. // Get content mark in |page_object| at |index|. // // page_object - handle to a page object. // index - the index of a page object. // // Returns the handle to the content mark, or NULL on failure. The handle is // still owned by the library, and it should not be freed directly. It becomes // invalid if the page object is destroyed, either directly or indirectly by // unloading the page. FPDF_EXPORT FPDF_PAGEOBJECTMARK FPDF_CALLCONV FPDFPageObj_GetMark(FPDF_PAGEOBJECT page_object, unsigned long index); // Experimental API. // Add a new content mark to a |page_object|. // // page_object - handle to a page object. // name - the name (tag) of the mark. // // Returns the handle to the content mark, or NULL on failure. The handle is // still owned by the library, and it should not be freed directly. It becomes // invalid if the page object is destroyed, either directly or indirectly by // unloading the page. FPDF_EXPORT FPDF_PAGEOBJECTMARK FPDF_CALLCONV FPDFPageObj_AddMark(FPDF_PAGEOBJECT page_object, FPDF_BYTESTRING name); // Experimental API. // Removes a content |mark| from a |page_object|. // The mark handle will be invalid after the removal. // // page_object - handle to a page object. // mark - handle to a content mark in that object to remove. // // Returns TRUE if the operation succeeded, FALSE if it failed. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_RemoveMark(FPDF_PAGEOBJECT page_object, FPDF_PAGEOBJECTMARK mark); // Experimental API. // Get the name of a content mark. // // mark - handle to a content mark. // buffer - buffer for holding the returned name in UTF-16LE. This is only // modified if |buflen| is large enough to store the name. // Optional, pass null to just retrieve the size of the buffer // needed. // buflen - length of the buffer in bytes. // out_buflen - pointer to variable that will receive the minimum buffer size // in bytes to contain the name. This is a required parameter. // Not filled if FALSE is returned. // // Returns TRUE if the operation succeeded, FALSE if it failed. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObjMark_GetName(FPDF_PAGEOBJECTMARK mark, FPDF_WCHAR* buffer, unsigned long buflen, unsigned long* out_buflen); // Experimental API. // Get the number of key/value pair parameters in |mark|. // // mark - handle to a content mark. // // Returns the number of key/value pair parameters |mark|, or -1 in case of // failure. FPDF_EXPORT int FPDF_CALLCONV FPDFPageObjMark_CountParams(FPDF_PAGEOBJECTMARK mark); // Experimental API. // Get the key of a property in a content mark. // // mark - handle to a content mark. // index - index of the property. // buffer - buffer for holding the returned key in UTF-16LE. This is only // modified if |buflen| is large enough to store the key. // Optional, pass null to just retrieve the size of the buffer // needed. // buflen - length of the buffer in bytes. // out_buflen - pointer to variable that will receive the minimum buffer size // in bytes to contain the name. This is a required parameter. // Not filled if FALSE is returned. // // Returns TRUE if the operation was successful, FALSE otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObjMark_GetParamKey(FPDF_PAGEOBJECTMARK mark, unsigned long index, FPDF_WCHAR* buffer, unsigned long buflen, unsigned long* out_buflen); // Experimental API. // Get the type of the value of a property in a content mark by key. // // mark - handle to a content mark. // key - string key of the property. // // Returns the type of the value, or FPDF_OBJECT_UNKNOWN in case of failure. FPDF_EXPORT FPDF_OBJECT_TYPE FPDF_CALLCONV FPDFPageObjMark_GetParamValueType(FPDF_PAGEOBJECTMARK mark, FPDF_BYTESTRING key); // Experimental API. // Get the value of a number property in a content mark by key as int. // FPDFPageObjMark_GetParamValueType() should have returned FPDF_OBJECT_NUMBER // for this property. // // mark - handle to a content mark. // key - string key of the property. // out_value - pointer to variable that will receive the value. Not filled if // false is returned. // // Returns TRUE if the key maps to a number value, FALSE otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObjMark_GetParamIntValue(FPDF_PAGEOBJECTMARK mark, FPDF_BYTESTRING key, int* out_value); // Experimental API. // Get the value of a number property in a content mark by key as float. // FPDFPageObjMark_GetParamValueType() should have returned FPDF_OBJECT_NUMBER // for this property. // // mark - handle to a content mark. // key - string key of the property. // out_value - pointer to variable that will receive the value. Not filled if // false is returned. // // Returns TRUE if the key maps to a number value, FALSE otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObjMark_GetParamFloatValue(FPDF_PAGEOBJECTMARK mark, FPDF_BYTESTRING key, float* out_value); // Experimental API. // Get the value of a string property in a content mark by key. // // mark - handle to a content mark. // key - string key of the property. // buffer - buffer for holding the returned value in UTF-16LE. This is // only modified if |buflen| is large enough to store the value. // Optional, pass null to just retrieve the size of the buffer // needed. // buflen - length of the buffer in bytes. // out_buflen - pointer to variable that will receive the minimum buffer size // in bytes to contain the name. This is a required parameter. // Not filled if FALSE is returned. // // Returns TRUE if the key maps to a string/blob value, FALSE otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObjMark_GetParamStringValue(FPDF_PAGEOBJECTMARK mark, FPDF_BYTESTRING key, FPDF_WCHAR* buffer, unsigned long buflen, unsigned long* out_buflen); // Experimental API. // Get the value of a blob property in a content mark by key. // // mark - handle to a content mark. // key - string key of the property. // buffer - buffer for holding the returned value. This is only modified // if |buflen| is large enough to store the value. // Optional, pass null to just retrieve the size of the buffer // needed. // buflen - length of the buffer in bytes. // out_buflen - pointer to variable that will receive the minimum buffer size // in bytes to contain the name. This is a required parameter. // Not filled if FALSE is returned. // // Returns TRUE if the key maps to a string/blob value, FALSE otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObjMark_GetParamBlobValue(FPDF_PAGEOBJECTMARK mark, FPDF_BYTESTRING key, unsigned char* buffer, unsigned long buflen, unsigned long* out_buflen); // Experimental API. // Set the value of an int property in a content mark by key. If a parameter // with key |key| exists, its value is set to |value|. Otherwise, it is added as // a new parameter. // // document - handle to the document. // page_object - handle to the page object with the mark. // mark - handle to a content mark. // key - string key of the property. // value - int value to set. // // Returns TRUE if the operation succeeded, FALSE otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObjMark_SetIntParam(FPDF_DOCUMENT document, FPDF_PAGEOBJECT page_object, FPDF_PAGEOBJECTMARK mark, FPDF_BYTESTRING key, int value); // Experimental API. // Set the value of a float property in a content mark by key. If a parameter // with key |key| exists, its value is set to |value|. Otherwise, it is added as // a new parameter. // // document - handle to the document. // page_object - handle to the page object with the mark. // mark - handle to a content mark. // key - string key of the property. // value - float value to set. // // Returns TRUE if the operation succeeded, FALSE otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObjMark_SetFloatParam(FPDF_DOCUMENT document, FPDF_PAGEOBJECT page_object, FPDF_PAGEOBJECTMARK mark, FPDF_BYTESTRING key, float value); // Experimental API. // Set the value of a string property in a content mark by key. If a parameter // with key |key| exists, its value is set to |value|. Otherwise, it is added as // a new parameter. // // document - handle to the document. // page_object - handle to the page object with the mark. // mark - handle to a content mark. // key - string key of the property. // value - string value to set. // // Returns TRUE if the operation succeeded, FALSE otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObjMark_SetStringParam(FPDF_DOCUMENT document, FPDF_PAGEOBJECT page_object, FPDF_PAGEOBJECTMARK mark, FPDF_BYTESTRING key, FPDF_BYTESTRING value); // Experimental API. // Set the value of a blob property in a content mark by key. If a parameter // with key |key| exists, its value is set to |value|. Otherwise, it is added as // a new parameter. // // document - handle to the document. // page_object - handle to the page object with the mark. // mark - handle to a content mark. // key - string key of the property. // value - pointer to blob value to set. // value_len - size in bytes of |value|. // // Returns TRUE if the operation succeeded, FALSE otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObjMark_SetBlobParam(FPDF_DOCUMENT document, FPDF_PAGEOBJECT page_object, FPDF_PAGEOBJECTMARK mark, FPDF_BYTESTRING key, const unsigned char* value, unsigned long value_len); // Experimental API. // Removes a property from a content mark by key. // // page_object - handle to the page object with the mark. // mark - handle to a content mark. // key - string key of the property. // // Returns TRUE if the operation succeeded, FALSE otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObjMark_RemoveParam(FPDF_PAGEOBJECT page_object, FPDF_PAGEOBJECTMARK mark, FPDF_BYTESTRING key); // Load an image from a JPEG image file and then set it into |image_object|. // // pages - pointer to the start of all loaded pages, may be NULL. // count - number of |pages|, may be 0. // image_object - handle to an image object. // file_access - file access handler which specifies the JPEG image file. // // Returns TRUE on success. // // The image object might already have an associated image, which is shared and // cached by the loaded pages. In that case, we need to clear the cached image // for all the loaded pages. Pass |pages| and page count (|count|) to this API // to clear the image cache. If the image is not previously shared, or NULL is a // valid |pages| value. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFImageObj_LoadJpegFile(FPDF_PAGE* pages, int count, FPDF_PAGEOBJECT image_object, FPDF_FILEACCESS* file_access); // Load an image from a JPEG image file and then set it into |image_object|. // // pages - pointer to the start of all loaded pages, may be NULL. // count - number of |pages|, may be 0. // image_object - handle to an image object. // file_access - file access handler which specifies the JPEG image file. // // Returns TRUE on success. // // The image object might already have an associated image, which is shared and // cached by the loaded pages. In that case, we need to clear the cached image // for all the loaded pages. Pass |pages| and page count (|count|) to this API // to clear the image cache. If the image is not previously shared, or NULL is a // valid |pages| value. This function loads the JPEG image inline, so the image // content is copied to the file. This allows |file_access| and its associated // data to be deleted after this function returns. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFImageObj_LoadJpegFileInline(FPDF_PAGE* pages, int count, FPDF_PAGEOBJECT image_object, FPDF_FILEACCESS* file_access); // TODO(thestig): Start deprecating this once FPDFPageObj_SetMatrix() is stable. // // Set the transform matrix of |image_object|. // // image_object - handle to an image object. // a - matrix value. // b - matrix value. // c - matrix value. // d - matrix value. // e - matrix value. // f - matrix value. // // The matrix is composed as: // |a c e| // |b d f| // and can be used to scale, rotate, shear and translate the |image_object|. // // Returns TRUE on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFImageObj_SetMatrix(FPDF_PAGEOBJECT image_object, double a, double b, double c, double d, double e, double f); // Set |bitmap| to |image_object|. // // pages - pointer to the start of all loaded pages, may be NULL. // count - number of |pages|, may be 0. // image_object - handle to an image object. // bitmap - handle of the bitmap. // // Returns TRUE on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFImageObj_SetBitmap(FPDF_PAGE* pages, int count, FPDF_PAGEOBJECT image_object, FPDF_BITMAP bitmap); // Get a bitmap rasterization of |image_object|. FPDFImageObj_GetBitmap() only // operates on |image_object| and does not take the associated image mask into // account. It also ignores the matrix for |image_object|. // The returned bitmap will be owned by the caller, and FPDFBitmap_Destroy() // must be called on the returned bitmap when it is no longer needed. // // image_object - handle to an image object. // // Returns the bitmap. FPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV FPDFImageObj_GetBitmap(FPDF_PAGEOBJECT image_object); // Experimental API. // Get a bitmap rasterization of |image_object| that takes the image mask and // image matrix into account. To render correctly, the caller must provide the // |document| associated with |image_object|. If there is a |page| associated // with |image_object|, the caller should provide that as well. // The returned bitmap will be owned by the caller, and FPDFBitmap_Destroy() // must be called on the returned bitmap when it is no longer needed. // // document - handle to a document associated with |image_object|. // page - handle to an optional page associated with |image_object|. // image_object - handle to an image object. // // Returns the bitmap or NULL on failure. FPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV FPDFImageObj_GetRenderedBitmap(FPDF_DOCUMENT document, FPDF_PAGE page, FPDF_PAGEOBJECT image_object); // Get the decoded image data of |image_object|. The decoded data is the // uncompressed image data, i.e. the raw image data after having all filters // applied. |buffer| is only modified if |buflen| is longer than the length of // the decoded image data. // // image_object - handle to an image object. // buffer - buffer for holding the decoded image data. // buflen - length of the buffer in bytes. // // Returns the length of the decoded image data. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFImageObj_GetImageDataDecoded(FPDF_PAGEOBJECT image_object, void* buffer, unsigned long buflen); // Get the raw image data of |image_object|. The raw data is the image data as // stored in the PDF without applying any filters. |buffer| is only modified if // |buflen| is longer than the length of the raw image data. // // image_object - handle to an image object. // buffer - buffer for holding the raw image data. // buflen - length of the buffer in bytes. // // Returns the length of the raw image data. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFImageObj_GetImageDataRaw(FPDF_PAGEOBJECT image_object, void* buffer, unsigned long buflen); // Get the number of filters (i.e. decoders) of the image in |image_object|. // // image_object - handle to an image object. // // Returns the number of |image_object|'s filters. FPDF_EXPORT int FPDF_CALLCONV FPDFImageObj_GetImageFilterCount(FPDF_PAGEOBJECT image_object); // Get the filter at |index| of |image_object|'s list of filters. Note that the // filters need to be applied in order, i.e. the first filter should be applied // first, then the second, etc. |buffer| is only modified if |buflen| is longer // than the length of the filter string. // // image_object - handle to an image object. // index - the index of the filter requested. // buffer - buffer for holding filter string, encoded in UTF-8. // buflen - length of the buffer. // // Returns the length of the filter string. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFImageObj_GetImageFilter(FPDF_PAGEOBJECT image_object, int index, void* buffer, unsigned long buflen); // Get the image metadata of |image_object|, including dimension, DPI, bits per // pixel, and colorspace. If the |image_object| is not an image object or if it // does not have an image, then the return value will be false. Otherwise, // failure to retrieve any specific parameter would result in its value being 0. // // image_object - handle to an image object. // page - handle to the page that |image_object| is on. Required for // retrieving the image's bits per pixel and colorspace. // metadata - receives the image metadata; must not be NULL. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFImageObj_GetImageMetadata(FPDF_PAGEOBJECT image_object, FPDF_PAGE page, FPDF_IMAGEOBJ_METADATA* metadata); // Experimental API. // Get the image size in pixels. Faster method to get only image size. // // image_object - handle to an image object. // width - receives the image width in pixels; must not be NULL. // height - receives the image height in pixels; must not be NULL. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFImageObj_GetImagePixelSize(FPDF_PAGEOBJECT image_object, unsigned int* width, unsigned int* height); // Experimental API. // Get ICC profile decoded data of |image_object|. If the |image_object| is not // an image object or if it does not have an image, then the return value will // be false. It also returns false if the |image_object| has no ICC profile. // |buffer| is only modified if ICC profile exists and |buflen| is longer than // the length of the ICC profile decoded data. // // image_object - handle to an image object; must not be NULL. // page - handle to the page containing |image_object|; must not be // NULL. Required for retrieving the image's colorspace. // buffer - Buffer to receive ICC profile data; may be NULL if querying // required size via |out_buflen|. // buflen - Length of the buffer in bytes. Ignored if |buffer| is NULL. // out_buflen - Pointer to receive the ICC profile data size in bytes; must // not be NULL. Will be set if this API returns true. // // Returns true if |out_buflen| is not null and an ICC profile exists for the // given |image_object|. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFImageObj_GetIccProfileDataDecoded(FPDF_PAGEOBJECT image_object, FPDF_PAGE page, uint8_t* buffer, size_t buflen, size_t* out_buflen); // Create a new path object at an initial position. // // x - initial horizontal position. // y - initial vertical position. // // Returns a handle to a new path object. FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV FPDFPageObj_CreateNewPath(float x, float y); // Create a closed path consisting of a rectangle. // // x - horizontal position for the left boundary of the rectangle. // y - vertical position for the bottom boundary of the rectangle. // w - width of the rectangle. // h - height of the rectangle. // // Returns a handle to the new path object. FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV FPDFPageObj_CreateNewRect(float x, float y, float w, float h); // Get the bounding box of |page_object|. // // page_object - handle to a page object. // left - pointer where the left coordinate will be stored // bottom - pointer where the bottom coordinate will be stored // right - pointer where the right coordinate will be stored // top - pointer where the top coordinate will be stored // // On success, returns TRUE and fills in the 4 coordinates. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_GetBounds(FPDF_PAGEOBJECT page_object, float* left, float* bottom, float* right, float* top); // Experimental API. // Get the quad points that bounds |page_object|. // // page_object - handle to a page object. // quad_points - pointer where the quadrilateral points will be stored. // // On success, returns TRUE and fills in |quad_points|. // // Similar to FPDFPageObj_GetBounds(), this returns the bounds of a page // object. When the object is rotated by a non-multiple of 90 degrees, this API // returns a tighter bound that cannot be represented with just the 4 sides of // a rectangle. // // Currently only works the following |page_object| types: FPDF_PAGEOBJ_TEXT and // FPDF_PAGEOBJ_IMAGE. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_GetRotatedBounds(FPDF_PAGEOBJECT page_object, FS_QUADPOINTSF* quad_points); // Set the blend mode of |page_object|. // // page_object - handle to a page object. // blend_mode - string containing the blend mode. // // Blend mode can be one of following: Color, ColorBurn, ColorDodge, Darken, // Difference, Exclusion, HardLight, Hue, Lighten, Luminosity, Multiply, Normal, // Overlay, Saturation, Screen, SoftLight FPDF_EXPORT void FPDF_CALLCONV FPDFPageObj_SetBlendMode(FPDF_PAGEOBJECT page_object, FPDF_BYTESTRING blend_mode); // Set the stroke RGBA of a page object. Range of values: 0 - 255. // // page_object - the handle to the page object. // R - the red component for the object's stroke color. // G - the green component for the object's stroke color. // B - the blue component for the object's stroke color. // A - the stroke alpha for the object. // // Returns TRUE on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_SetStrokeColor(FPDF_PAGEOBJECT page_object, unsigned int R, unsigned int G, unsigned int B, unsigned int A); // Get the stroke RGBA of a page object. Range of values: 0 - 255. // // page_object - the handle to the page object. // R - the red component of the path stroke color. // G - the green component of the object's stroke color. // B - the blue component of the object's stroke color. // A - the stroke alpha of the object. // // Returns TRUE on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_GetStrokeColor(FPDF_PAGEOBJECT page_object, unsigned int* R, unsigned int* G, unsigned int* B, unsigned int* A); // Set the stroke width of a page object. // // path - the handle to the page object. // width - the width of the stroke. // // Returns TRUE on success FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_SetStrokeWidth(FPDF_PAGEOBJECT page_object, float width); // Get the stroke width of a page object. // // path - the handle to the page object. // width - the width of the stroke. // // Returns TRUE on success FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_GetStrokeWidth(FPDF_PAGEOBJECT page_object, float* width); // Get the line join of |page_object|. // // page_object - handle to a page object. // // Returns the line join, or -1 on failure. // Line join can be one of following: FPDF_LINEJOIN_MITER, FPDF_LINEJOIN_ROUND, // FPDF_LINEJOIN_BEVEL FPDF_EXPORT int FPDF_CALLCONV FPDFPageObj_GetLineJoin(FPDF_PAGEOBJECT page_object); // Set the line join of |page_object|. // // page_object - handle to a page object. // line_join - line join // // Line join can be one of following: FPDF_LINEJOIN_MITER, FPDF_LINEJOIN_ROUND, // FPDF_LINEJOIN_BEVEL FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_SetLineJoin(FPDF_PAGEOBJECT page_object, int line_join); // Get the line cap of |page_object|. // // page_object - handle to a page object. // // Returns the line cap, or -1 on failure. // Line cap can be one of following: FPDF_LINECAP_BUTT, FPDF_LINECAP_ROUND, // FPDF_LINECAP_PROJECTING_SQUARE FPDF_EXPORT int FPDF_CALLCONV FPDFPageObj_GetLineCap(FPDF_PAGEOBJECT page_object); // Set the line cap of |page_object|. // // page_object - handle to a page object. // line_cap - line cap // // Line cap can be one of following: FPDF_LINECAP_BUTT, FPDF_LINECAP_ROUND, // FPDF_LINECAP_PROJECTING_SQUARE FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_SetLineCap(FPDF_PAGEOBJECT page_object, int line_cap); // Set the fill RGBA of a page object. Range of values: 0 - 255. // // page_object - the handle to the page object. // R - the red component for the object's fill color. // G - the green component for the object's fill color. // B - the blue component for the object's fill color. // A - the fill alpha for the object. // // Returns TRUE on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_SetFillColor(FPDF_PAGEOBJECT page_object, unsigned int R, unsigned int G, unsigned int B, unsigned int A); // Get the fill RGBA of a page object. Range of values: 0 - 255. // // page_object - the handle to the page object. // R - the red component of the object's fill color. // G - the green component of the object's fill color. // B - the blue component of the object's fill color. // A - the fill alpha of the object. // // Returns TRUE on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_GetFillColor(FPDF_PAGEOBJECT page_object, unsigned int* R, unsigned int* G, unsigned int* B, unsigned int* A); // Experimental API. // Get the line dash |phase| of |page_object|. // // page_object - handle to a page object. // phase - pointer where the dashing phase will be stored. // // Returns TRUE on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_GetDashPhase(FPDF_PAGEOBJECT page_object, float* phase); // Experimental API. // Set the line dash phase of |page_object|. // // page_object - handle to a page object. // phase - line dash phase. // // Returns TRUE on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_SetDashPhase(FPDF_PAGEOBJECT page_object, float phase); // Experimental API. // Get the line dash array of |page_object|. // // page_object - handle to a page object. // // Returns the line dash array size or -1 on failure. FPDF_EXPORT int FPDF_CALLCONV FPDFPageObj_GetDashCount(FPDF_PAGEOBJECT page_object); // Experimental API. // Get the line dash array of |page_object|. // // page_object - handle to a page object. // dash_array - pointer where the dashing array will be stored. // dash_count - number of elements in |dash_array|. // // Returns TRUE on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_GetDashArray(FPDF_PAGEOBJECT page_object, float* dash_array, size_t dash_count); // Experimental API. // Set the line dash array of |page_object|. // // page_object - handle to a page object. // dash_array - the dash array. // dash_count - number of elements in |dash_array|. // phase - the line dash phase. // // Returns TRUE on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_SetDashArray(FPDF_PAGEOBJECT page_object, const float* dash_array, size_t dash_count, float phase); // Get number of segments inside |path|. // // path - handle to a path. // // A segment is a command, created by e.g. FPDFPath_MoveTo(), // FPDFPath_LineTo() or FPDFPath_BezierTo(). // // Returns the number of objects in |path| or -1 on failure. FPDF_EXPORT int FPDF_CALLCONV FPDFPath_CountSegments(FPDF_PAGEOBJECT path); // Get segment in |path| at |index|. // // path - handle to a path. // index - the index of a segment. // // Returns the handle to the segment, or NULL on faiure. FPDF_EXPORT FPDF_PATHSEGMENT FPDF_CALLCONV FPDFPath_GetPathSegment(FPDF_PAGEOBJECT path, int index); // Get coordinates of |segment|. // // segment - handle to a segment. // x - the horizontal position of the segment. // y - the vertical position of the segment. // // Returns TRUE on success, otherwise |x| and |y| is not set. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPathSegment_GetPoint(FPDF_PATHSEGMENT segment, float* x, float* y); // Get type of |segment|. // // segment - handle to a segment. // // Returns one of the FPDF_SEGMENT_* values on success, // FPDF_SEGMENT_UNKNOWN on error. FPDF_EXPORT int FPDF_CALLCONV FPDFPathSegment_GetType(FPDF_PATHSEGMENT segment); // Gets if the |segment| closes the current subpath of a given path. // // segment - handle to a segment. // // Returns close flag for non-NULL segment, FALSE otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPathSegment_GetClose(FPDF_PATHSEGMENT segment); // Move a path's current point. // // path - the handle to the path object. // x - the horizontal position of the new current point. // y - the vertical position of the new current point. // // Note that no line will be created between the previous current point and the // new one. // // Returns TRUE on success FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_MoveTo(FPDF_PAGEOBJECT path, float x, float y); // Add a line between the current point and a new point in the path. // // path - the handle to the path object. // x - the horizontal position of the new point. // y - the vertical position of the new point. // // The path's current point is changed to (x, y). // // Returns TRUE on success FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_LineTo(FPDF_PAGEOBJECT path, float x, float y); // Add a cubic Bezier curve to the given path, starting at the current point. // // path - the handle to the path object. // x1 - the horizontal position of the first Bezier control point. // y1 - the vertical position of the first Bezier control point. // x2 - the horizontal position of the second Bezier control point. // y2 - the vertical position of the second Bezier control point. // x3 - the horizontal position of the ending point of the Bezier curve. // y3 - the vertical position of the ending point of the Bezier curve. // // Returns TRUE on success FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_BezierTo(FPDF_PAGEOBJECT path, float x1, float y1, float x2, float y2, float x3, float y3); // Close the current subpath of a given path. // // path - the handle to the path object. // // This will add a line between the current point and the initial point of the // subpath, thus terminating the current subpath. // // Returns TRUE on success FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_Close(FPDF_PAGEOBJECT path); // Set the drawing mode of a path. // // path - the handle to the path object. // fillmode - the filling mode to be set: one of the FPDF_FILLMODE_* flags. // stroke - a boolean specifying if the path should be stroked or not. // // Returns TRUE on success FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_SetDrawMode(FPDF_PAGEOBJECT path, int fillmode, FPDF_BOOL stroke); // Get the drawing mode of a path. // // path - the handle to the path object. // fillmode - the filling mode of the path: one of the FPDF_FILLMODE_* flags. // stroke - a boolean specifying if the path is stroked or not. // // Returns TRUE on success FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_GetDrawMode(FPDF_PAGEOBJECT path, int* fillmode, FPDF_BOOL* stroke); // Create a new text object using one of the standard PDF fonts. // // document - handle to the document. // font - string containing the font name, without spaces. // font_size - the font size for the new text object. // // Returns a handle to a new text object, or NULL on failure FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV FPDFPageObj_NewTextObj(FPDF_DOCUMENT document, FPDF_BYTESTRING font, float font_size); // Set the text for a text object. If it had text, it will be replaced. // // text_object - handle to the text object. // text - the UTF-16LE encoded string containing the text to be added. // // Returns TRUE on success FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFText_SetText(FPDF_PAGEOBJECT text_object, FPDF_WIDESTRING text); // Experimental API. // Set the text using charcodes for a text object. If it had text, it will be // replaced. // // text_object - handle to the text object. // charcodes - pointer to an array of charcodes to be added. // count - number of elements in |charcodes|. // // Returns TRUE on success FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFText_SetCharcodes(FPDF_PAGEOBJECT text_object, const uint32_t* charcodes, size_t count); // Returns a font object loaded from a stream of data. The font is loaded // into the document. Various font data structures, such as the ToUnicode data, // are auto-generated based on the inputs. // // document - handle to the document. // data - the stream of font data, which will be copied by the font object. // size - the size of the font data, in bytes. // font_type - FPDF_FONT_TYPE1 or FPDF_FONT_TRUETYPE depending on the font type. // cid - a boolean specifying if the font is a CID font or not. // // The loaded font can be closed using FPDFFont_Close(). // // Returns NULL on failure FPDF_EXPORT FPDF_FONT FPDF_CALLCONV FPDFText_LoadFont(FPDF_DOCUMENT document, const uint8_t* data, uint32_t size, int font_type, FPDF_BOOL cid); // Experimental API. // Loads one of the standard 14 fonts per PDF spec 1.7 page 416. The preferred // way of using font style is using a dash to separate the name from the style, // for example 'Helvetica-BoldItalic'. // // document - handle to the document. // font - string containing the font name, without spaces. // // The loaded font can be closed using FPDFFont_Close(). // // Returns NULL on failure. FPDF_EXPORT FPDF_FONT FPDF_CALLCONV FPDFText_LoadStandardFont(FPDF_DOCUMENT document, FPDF_BYTESTRING font); // Experimental API. // Returns a font object loaded from a stream of data for a type 2 CID font. The // font is loaded into the document. Unlike FPDFText_LoadFont(), the ToUnicode // data and the CIDToGIDMap data are caller provided, instead of auto-generated. // // document - handle to the document. // font_data - the stream of font data, which will be copied by // the font object. // font_data_size - the size of the font data, in bytes. // to_unicode_cmap - the ToUnicode data. // cid_to_gid_map_data - the stream of CIDToGIDMap data. // cid_to_gid_map_data_size - the size of the CIDToGIDMap data, in bytes. // // The loaded font can be closed using FPDFFont_Close(). // // Returns NULL on failure. FPDF_EXPORT FPDF_FONT FPDF_CALLCONV FPDFText_LoadCidType2Font(FPDF_DOCUMENT document, const uint8_t* font_data, uint32_t font_data_size, FPDF_BYTESTRING to_unicode_cmap, const uint8_t* cid_to_gid_map_data, uint32_t cid_to_gid_map_data_size); // Get the font size of a text object. // // text - handle to a text. // size - pointer to the font size of the text object, measured in points // (about 1/72 inch) // // Returns TRUE on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFTextObj_GetFontSize(FPDF_PAGEOBJECT text, float* size); // Close a loaded PDF font. // // font - Handle to the loaded font. FPDF_EXPORT void FPDF_CALLCONV FPDFFont_Close(FPDF_FONT font); // Create a new text object using a loaded font. // // document - handle to the document. // font - handle to the font object. // font_size - the font size for the new text object. // // Returns a handle to a new text object, or NULL on failure FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV FPDFPageObj_CreateTextObj(FPDF_DOCUMENT document, FPDF_FONT font, float font_size); // Get the text rendering mode of a text object. // // text - the handle to the text object. // // Returns one of the known FPDF_TEXT_RENDERMODE enum values on success, // FPDF_TEXTRENDERMODE_UNKNOWN on error. FPDF_EXPORT FPDF_TEXT_RENDERMODE FPDF_CALLCONV FPDFTextObj_GetTextRenderMode(FPDF_PAGEOBJECT text); // Experimental API. // Set the text rendering mode of a text object. // // text - the handle to the text object. // render_mode - the FPDF_TEXT_RENDERMODE enum value to be set (cannot set to // FPDF_TEXTRENDERMODE_UNKNOWN). // // Returns TRUE on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFTextObj_SetTextRenderMode(FPDF_PAGEOBJECT text, FPDF_TEXT_RENDERMODE render_mode); // Get the text of a text object. // // text_object - the handle to the text object. // text_page - the handle to the text page. // buffer - the address of a buffer that receives the text. // length - the size, in bytes, of |buffer|. // // Returns the number of bytes in the text (including the trailing NUL // character) on success, 0 on error. // // Regardless of the platform, the |buffer| is always in UTF-16LE encoding. // If |length| is less than the returned length, or |buffer| is NULL, |buffer| // will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFTextObj_GetText(FPDF_PAGEOBJECT text_object, FPDF_TEXTPAGE text_page, FPDF_WCHAR* buffer, unsigned long length); // Experimental API. // Get a bitmap rasterization of |text_object|. To render correctly, the caller // must provide the |document| associated with |text_object|. If there is a // |page| associated with |text_object|, the caller should provide that as well. // The returned bitmap will be owned by the caller, and FPDFBitmap_Destroy() // must be called on the returned bitmap when it is no longer needed. // // document - handle to a document associated with |text_object|. // page - handle to an optional page associated with |text_object|. // text_object - handle to a text object. // scale - the scaling factor, which must be greater than 0. // // Returns the bitmap or NULL on failure. FPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV FPDFTextObj_GetRenderedBitmap(FPDF_DOCUMENT document, FPDF_PAGE page, FPDF_PAGEOBJECT text_object, float scale); // Experimental API. // Get the font of a text object. // // text - the handle to the text object. // // Returns a handle to the font object held by |text| which retains ownership. FPDF_EXPORT FPDF_FONT FPDF_CALLCONV FPDFTextObj_GetFont(FPDF_PAGEOBJECT text); // Experimental API. // Get the base name of a font. // // font - the handle to the font object. // buffer - the address of a buffer that receives the base font name. // length - the size, in bytes, of |buffer|. // // Returns the number of bytes in the base name (including the trailing NUL // character) on success, 0 on error. The base name is typically the font's // PostScript name. See descriptions of "BaseFont" in ISO 32000-1:2008 spec. // // Regardless of the platform, the |buffer| is always in UTF-8 encoding. // If |length| is less than the returned length, or |buffer| is NULL, |buffer| // will not be modified. FPDF_EXPORT size_t FPDF_CALLCONV FPDFFont_GetBaseFontName(FPDF_FONT font, char* buffer, size_t length); // Experimental API. // Get the family name of a font. // // font - the handle to the font object. // buffer - the address of a buffer that receives the font name. // length - the size, in bytes, of |buffer|. // // Returns the number of bytes in the family name (including the trailing NUL // character) on success, 0 on error. // // Regardless of the platform, the |buffer| is always in UTF-8 encoding. // If |length| is less than the returned length, or |buffer| is NULL, |buffer| // will not be modified. FPDF_EXPORT size_t FPDF_CALLCONV FPDFFont_GetFamilyName(FPDF_FONT font, char* buffer, size_t length); // Experimental API. // Get the decoded data from the |font| object. // // font - The handle to the font object. (Required) // buffer - The address of a buffer that receives the font data. // buflen - Length of the buffer. // out_buflen - Pointer to variable that will receive the minimum buffer size // to contain the font data. Not filled if the return value is // FALSE. (Required) // // Returns TRUE on success. In which case, |out_buflen| will be filled, and // |buffer| will be filled if it is large enough. Returns FALSE if any of the // required parameters are null. // // The decoded data is the uncompressed font data. i.e. the raw font data after // having all stream filters applied, when the data is embedded. // // If the font is not embedded, then this API will instead return the data for // the substitution font it is using. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFFont_GetFontData(FPDF_FONT font, uint8_t* buffer, size_t buflen, size_t* out_buflen); // Experimental API. // Get whether |font| is embedded or not. // // font - the handle to the font object. // // Returns 1 if the font is embedded, 0 if it not, and -1 on failure. FPDF_EXPORT int FPDF_CALLCONV FPDFFont_GetIsEmbedded(FPDF_FONT font); // Experimental API. // Get the descriptor flags of a font. // // font - the handle to the font object. // // Returns the bit flags specifying various characteristics of the font as // defined in ISO 32000-1:2008, table 123, -1 on failure. FPDF_EXPORT int FPDF_CALLCONV FPDFFont_GetFlags(FPDF_FONT font); // Experimental API. // Get the font weight of a font. // // font - the handle to the font object. // // Returns the font weight, -1 on failure. // Typical values are 400 (normal) and 700 (bold). FPDF_EXPORT int FPDF_CALLCONV FPDFFont_GetWeight(FPDF_FONT font); // Experimental API. // Get the italic angle of a font. // // font - the handle to the font object. // angle - pointer where the italic angle will be stored // // The italic angle of a |font| is defined as degrees counterclockwise // from vertical. For a font that slopes to the right, this will be negative. // // Returns TRUE on success; |angle| unmodified on failure. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFFont_GetItalicAngle(FPDF_FONT font, int* angle); // Experimental API. // Get ascent distance of a font. // // font - the handle to the font object. // font_size - the size of the |font|. // ascent - pointer where the font ascent will be stored // // Ascent is the maximum distance in points above the baseline reached by the // glyphs of the |font|. One point is 1/72 inch (around 0.3528 mm). // // Returns TRUE on success; |ascent| unmodified on failure. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFFont_GetAscent(FPDF_FONT font, float font_size, float* ascent); // Experimental API. // Get descent distance of a font. // // font - the handle to the font object. // font_size - the size of the |font|. // descent - pointer where the font descent will be stored // // Descent is the maximum distance in points below the baseline reached by the // glyphs of the |font|. One point is 1/72 inch (around 0.3528 mm). // // Returns TRUE on success; |descent| unmodified on failure. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFFont_GetDescent(FPDF_FONT font, float font_size, float* descent); // Experimental API. // Get the width of a glyph in a font. // // font - the handle to the font object. // glyph - the glyph. // font_size - the size of the font. // width - pointer where the glyph width will be stored // // Glyph width is the distance from the end of the prior glyph to the next // glyph. This will be the vertical distance for vertical writing. // // Returns TRUE on success; |width| unmodified on failure. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFFont_GetGlyphWidth(FPDF_FONT font, uint32_t glyph, float font_size, float* width); // Experimental API. // Get the glyphpath describing how to draw a font glyph. // // font - the handle to the font object. // glyph - the glyph being drawn. // font_size - the size of the font. // // Returns the handle to the segment, or NULL on faiure. FPDF_EXPORT FPDF_GLYPHPATH FPDF_CALLCONV FPDFFont_GetGlyphPath(FPDF_FONT font, uint32_t glyph, float font_size); // Experimental API. // Get number of segments inside glyphpath. // // glyphpath - handle to a glyph path. // // Returns the number of objects in |glyphpath| or -1 on failure. FPDF_EXPORT int FPDF_CALLCONV FPDFGlyphPath_CountGlyphSegments(FPDF_GLYPHPATH glyphpath); // Experimental API. // Get segment in glyphpath at index. // // glyphpath - handle to a glyph path. // index - the index of a segment. // // Returns the handle to the segment, or NULL on faiure. FPDF_EXPORT FPDF_PATHSEGMENT FPDF_CALLCONV FPDFGlyphPath_GetGlyphPathSegment(FPDF_GLYPHPATH glyphpath, int index); // Get number of page objects inside |form_object|. // // form_object - handle to a form object. // // Returns the number of objects in |form_object| on success, -1 on error. FPDF_EXPORT int FPDF_CALLCONV FPDFFormObj_CountObjects(FPDF_PAGEOBJECT form_object); // Get page object in |form_object| at |index|. // // form_object - handle to a form object. // index - the 0-based index of a page object. // // Returns the handle to the page object, or NULL on error. FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV FPDFFormObj_GetObject(FPDF_PAGEOBJECT form_object, unsigned long index); // Experimental API. // // Remove |page_object| from |form_object|. // // form_object - handle to a form object. // page_object - handle to a page object to be removed from the form. // // Returns TRUE on success. // // Ownership of the removed |page_object| is transferred to the caller. // Call FPDFPageObj_Destroy() on the removed page_object to free it. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFFormObj_RemoveObject(FPDF_PAGEOBJECT form_object, FPDF_PAGEOBJECT page_object); #ifdef __cplusplus } // extern "C" #endif // __cplusplus #endif // PUBLIC_FPDF_EDIT_H_ ================================================ FILE: external/pdfium/macos-arm64/include/fpdf_ext.h ================================================ // Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #ifndef PUBLIC_FPDF_EXT_H_ #define PUBLIC_FPDF_EXT_H_ #include // NOLINTNEXTLINE(build/include) #include "fpdfview.h" #ifdef __cplusplus extern "C" { #endif // __cplusplus // Unsupported XFA form. #define FPDF_UNSP_DOC_XFAFORM 1 // Unsupported portable collection. #define FPDF_UNSP_DOC_PORTABLECOLLECTION 2 // Unsupported attachment. #define FPDF_UNSP_DOC_ATTACHMENT 3 // Unsupported security. #define FPDF_UNSP_DOC_SECURITY 4 // Unsupported shared review. #define FPDF_UNSP_DOC_SHAREDREVIEW 5 // Unsupported shared form, acrobat. #define FPDF_UNSP_DOC_SHAREDFORM_ACROBAT 6 // Unsupported shared form, filesystem. #define FPDF_UNSP_DOC_SHAREDFORM_FILESYSTEM 7 // Unsupported shared form, email. #define FPDF_UNSP_DOC_SHAREDFORM_EMAIL 8 // Unsupported 3D annotation. #define FPDF_UNSP_ANNOT_3DANNOT 11 // Unsupported movie annotation. #define FPDF_UNSP_ANNOT_MOVIE 12 // Unsupported sound annotation. #define FPDF_UNSP_ANNOT_SOUND 13 // Unsupported screen media annotation. #define FPDF_UNSP_ANNOT_SCREEN_MEDIA 14 // Unsupported screen rich media annotation. #define FPDF_UNSP_ANNOT_SCREEN_RICHMEDIA 15 // Unsupported attachment annotation. #define FPDF_UNSP_ANNOT_ATTACHMENT 16 // Unsupported signature annotation. #define FPDF_UNSP_ANNOT_SIG 17 // Interface for unsupported feature notifications. typedef struct _UNSUPPORT_INFO { // Version number of the interface. Must be 1. int version; // Unsupported object notification function. // Interface Version: 1 // Implementation Required: Yes // // pThis - pointer to the interface structure. // nType - the type of unsupported object. One of the |FPDF_UNSP_*| entries. void (*FSDK_UnSupport_Handler)(struct _UNSUPPORT_INFO* pThis, int nType); } UNSUPPORT_INFO; // Setup an unsupported object handler. // // unsp_info - Pointer to an UNSUPPORT_INFO structure. // // Returns TRUE on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FSDK_SetUnSpObjProcessHandler(UNSUPPORT_INFO* unsp_info); // Set replacement function for calls to time(). // // This API is intended to be used only for testing, thus may cause PDFium to // behave poorly in production environments. // // func - Function pointer to alternate implementation of time(), or // NULL to restore to actual time() call itself. FPDF_EXPORT void FPDF_CALLCONV FSDK_SetTimeFunction(time_t (*func)()); // Set replacement function for calls to localtime(). // // This API is intended to be used only for testing, thus may cause PDFium to // behave poorly in production environments. // // func - Function pointer to alternate implementation of localtime(), or // NULL to restore to actual localtime() call itself. FPDF_EXPORT void FPDF_CALLCONV FSDK_SetLocaltimeFunction(struct tm* (*func)(const time_t*)); // Unknown page mode. #define PAGEMODE_UNKNOWN -1 // Document outline, and thumbnails hidden. #define PAGEMODE_USENONE 0 // Document outline visible. #define PAGEMODE_USEOUTLINES 1 // Thumbnail images visible. #define PAGEMODE_USETHUMBS 2 // Full-screen mode, no menu bar, window controls, or other decorations visible. #define PAGEMODE_FULLSCREEN 3 // Optional content group panel visible. #define PAGEMODE_USEOC 4 // Attachments panel visible. #define PAGEMODE_USEATTACHMENTS 5 // Get the document's PageMode. // // doc - Handle to document. // // Returns one of the |PAGEMODE_*| flags defined above. // // The page mode defines how the document should be initially displayed. FPDF_EXPORT int FPDF_CALLCONV FPDFDoc_GetPageMode(FPDF_DOCUMENT document); #ifdef __cplusplus } // extern "C" #endif // __cplusplus #endif // PUBLIC_FPDF_EXT_H_ ================================================ FILE: external/pdfium/macos-arm64/include/fpdf_flatten.h ================================================ // Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #ifndef PUBLIC_FPDF_FLATTEN_H_ #define PUBLIC_FPDF_FLATTEN_H_ // NOLINTNEXTLINE(build/include) #include "fpdfview.h" // Flatten operation failed. #define FLATTEN_FAIL 0 // Flatten operation succeed. #define FLATTEN_SUCCESS 1 // Nothing to be flattened. #define FLATTEN_NOTHINGTODO 2 // Flatten for normal display. #define FLAT_NORMALDISPLAY 0 // Flatten for print. #define FLAT_PRINT 1 #ifdef __cplusplus extern "C" { #endif // __cplusplus // Flatten annotations and form fields into the page contents. // // page - handle to the page. // nFlag - One of the |FLAT_*| values denoting the page usage. // // Returns one of the |FLATTEN_*| values. // // Currently, all failures return |FLATTEN_FAIL| with no indication of the // cause. FPDF_EXPORT int FPDF_CALLCONV FPDFPage_Flatten(FPDF_PAGE page, int nFlag); #ifdef __cplusplus } // extern "C" #endif // __cplusplus #endif // PUBLIC_FPDF_FLATTEN_H_ ================================================ FILE: external/pdfium/macos-arm64/include/fpdf_formfill.h ================================================ // Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #ifndef PUBLIC_FPDF_FORMFILL_H_ #define PUBLIC_FPDF_FORMFILL_H_ // clang-format off // NOLINTNEXTLINE(build/include_directory) #include "fpdfview.h" // These values are return values for a public API, so should not be changed // other than the count when adding new values. #define FORMTYPE_NONE 0 // Document contains no forms #define FORMTYPE_ACRO_FORM 1 // Forms are specified using AcroForm spec #define FORMTYPE_XFA_FULL 2 // Forms are specified using entire XFA spec #define FORMTYPE_XFA_FOREGROUND 3 // Forms are specified using the XFAF subset // of XFA spec #define FORMTYPE_COUNT 4 // The number of form types #define JSPLATFORM_ALERT_BUTTON_OK 0 // OK button #define JSPLATFORM_ALERT_BUTTON_OKCANCEL 1 // OK & Cancel buttons #define JSPLATFORM_ALERT_BUTTON_YESNO 2 // Yes & No buttons #define JSPLATFORM_ALERT_BUTTON_YESNOCANCEL 3 // Yes, No & Cancel buttons #define JSPLATFORM_ALERT_BUTTON_DEFAULT JSPLATFORM_ALERT_BUTTON_OK #define JSPLATFORM_ALERT_ICON_ERROR 0 // Error #define JSPLATFORM_ALERT_ICON_WARNING 1 // Warning #define JSPLATFORM_ALERT_ICON_QUESTION 2 // Question #define JSPLATFORM_ALERT_ICON_STATUS 3 // Status #define JSPLATFORM_ALERT_ICON_ASTERISK 4 // Asterisk #define JSPLATFORM_ALERT_ICON_DEFAULT JSPLATFORM_ALERT_ICON_ERROR #define JSPLATFORM_ALERT_RETURN_OK 1 // OK #define JSPLATFORM_ALERT_RETURN_CANCEL 2 // Cancel #define JSPLATFORM_ALERT_RETURN_NO 3 // No #define JSPLATFORM_ALERT_RETURN_YES 4 // Yes #define JSPLATFORM_BEEP_ERROR 0 // Error #define JSPLATFORM_BEEP_WARNING 1 // Warning #define JSPLATFORM_BEEP_QUESTION 2 // Question #define JSPLATFORM_BEEP_STATUS 3 // Status #define JSPLATFORM_BEEP_DEFAULT 4 // Default // Exported Functions #ifdef __cplusplus extern "C" { #endif typedef struct _IPDF_JsPlatform { // Version number of the interface. Currently must be 2. int version; // Version 1. // Method: app_alert // Pop up a dialog to show warning or hint. // Interface Version: // 1 // Implementation Required: // yes // Parameters: // pThis - Pointer to the interface structure itself. // Msg - A string containing the message to be displayed. // Title - The title of the dialog. // Type - The type of button group, one of the // JSPLATFORM_ALERT_BUTTON_* values above. // nIcon - The type of the icon, one of the // JSPLATFORM_ALERT_ICON_* above. // Return Value: // Option selected by user in dialogue, one of the // JSPLATFORM_ALERT_RETURN_* values above. int (*app_alert)(struct _IPDF_JsPlatform* pThis, FPDF_WIDESTRING Msg, FPDF_WIDESTRING Title, int Type, int Icon); // Method: app_beep // Causes the system to play a sound. // Interface Version: // 1 // Implementation Required: // yes // Parameters: // pThis - Pointer to the interface structure itself // nType - The sound type, see JSPLATFORM_BEEP_TYPE_* // above. // Return Value: // None void (*app_beep)(struct _IPDF_JsPlatform* pThis, int nType); // Method: app_response // Displays a dialog box containing a question and an entry field for // the user to reply to the question. // Interface Version: // 1 // Implementation Required: // yes // Parameters: // pThis - Pointer to the interface structure itself // Question - The question to be posed to the user. // Title - The title of the dialog box. // Default - A default value for the answer to the question. If // not specified, no default value is presented. // cLabel - A short string to appear in front of and on the // same line as the edit text field. // bPassword - If true, indicates that the user's response should // be shown as asterisks (*) or bullets (?) to mask // the response, which might be sensitive information. // response - A string buffer allocated by PDFium, to receive the // user's response. // length - The length of the buffer in bytes. Currently, it is // always 2048. // Return Value: // Number of bytes the complete user input would actually require, not // including trailing zeros, regardless of the value of the length // parameter or the presence of the response buffer. // Comments: // No matter on what platform, the response buffer should be always // written using UTF-16LE encoding. If a response buffer is // present and the size of the user input exceeds the capacity of the // buffer as specified by the length parameter, only the // first "length" bytes of the user input are to be written to the // buffer. int (*app_response)(struct _IPDF_JsPlatform* pThis, FPDF_WIDESTRING Question, FPDF_WIDESTRING Title, FPDF_WIDESTRING Default, FPDF_WIDESTRING cLabel, FPDF_BOOL bPassword, void* response, int length); // Method: Doc_getFilePath // Get the file path of the current document. // Interface Version: // 1 // Implementation Required: // yes // Parameters: // pThis - Pointer to the interface structure itself // filePath - The string buffer to receive the file path. Can // be NULL. // length - The length of the buffer, number of bytes. Can // be 0. // Return Value: // Number of bytes the filePath consumes, including trailing zeros. // Comments: // The filePath should always be provided in the local encoding. // The return value always indicated number of bytes required for // the buffer, even when there is no buffer specified, or the buffer // size is less than required. In this case, the buffer will not // be modified. int (*Doc_getFilePath)(struct _IPDF_JsPlatform* pThis, void* filePath, int length); // Method: Doc_mail // Mails the data buffer as an attachment to all recipients, with or // without user interaction. // Interface Version: // 1 // Implementation Required: // yes // Parameters: // pThis - Pointer to the interface structure itself // mailData - Pointer to the data buffer to be sent. Can be NULL. // length - The size,in bytes, of the buffer pointed by // mailData parameter. Can be 0. // bUI - If true, the rest of the parameters are used in a // compose-new-message window that is displayed to the // user. If false, the cTo parameter is required and // all others are optional. // To - A semicolon-delimited list of recipients for the // message. // Subject - The subject of the message. The length limit is // 64 KB. // CC - A semicolon-delimited list of CC recipients for // the message. // BCC - A semicolon-delimited list of BCC recipients for // the message. // Msg - The content of the message. The length limit is // 64 KB. // Return Value: // None. // Comments: // If the parameter mailData is NULL or length is 0, the current // document will be mailed as an attachment to all recipients. void (*Doc_mail)(struct _IPDF_JsPlatform* pThis, void* mailData, int length, FPDF_BOOL bUI, FPDF_WIDESTRING To, FPDF_WIDESTRING Subject, FPDF_WIDESTRING CC, FPDF_WIDESTRING BCC, FPDF_WIDESTRING Msg); // Method: Doc_print // Prints all or a specific number of pages of the document. // Interface Version: // 1 // Implementation Required: // yes // Parameters: // pThis - Pointer to the interface structure itself. // bUI - If true, will cause a UI to be presented to the // user to obtain printing information and confirm // the action. // nStart - A 0-based index that defines the start of an // inclusive range of pages. // nEnd - A 0-based index that defines the end of an // inclusive page range. // bSilent - If true, suppresses the cancel dialog box while // the document is printing. The default is false. // bShrinkToFit - If true, the page is shrunk (if necessary) to // fit within the imageable area of the printed page. // bPrintAsImage - If true, print pages as an image. // bReverse - If true, print from nEnd to nStart. // bAnnotations - If true (the default), annotations are // printed. // Return Value: // None. void (*Doc_print)(struct _IPDF_JsPlatform* pThis, FPDF_BOOL bUI, int nStart, int nEnd, FPDF_BOOL bSilent, FPDF_BOOL bShrinkToFit, FPDF_BOOL bPrintAsImage, FPDF_BOOL bReverse, FPDF_BOOL bAnnotations); // Method: Doc_submitForm // Send the form data to a specified URL. // Interface Version: // 1 // Implementation Required: // yes // Parameters: // pThis - Pointer to the interface structure itself // formData - Pointer to the data buffer to be sent. // length - The size,in bytes, of the buffer pointed by // formData parameter. // URL - The URL to send to. // Return Value: // None. void (*Doc_submitForm)(struct _IPDF_JsPlatform* pThis, void* formData, int length, FPDF_WIDESTRING URL); // Method: Doc_gotoPage // Jump to a specified page. // Interface Version: // 1 // Implementation Required: // yes // Parameters: // pThis - Pointer to the interface structure itself // nPageNum - The specified page number, zero for the first page. // Return Value: // None. void (*Doc_gotoPage)(struct _IPDF_JsPlatform* pThis, int nPageNum); // Method: Field_browse // Show a file selection dialog, and return the selected file path. // Interface Version: // 1 // Implementation Required: // yes // Parameters: // pThis - Pointer to the interface structure itself. // filePath - Pointer to the data buffer to receive the file // path. Can be NULL. // length - The length of the buffer, in bytes. Can be 0. // Return Value: // Number of bytes the filePath consumes, including trailing zeros. // Comments: // The filePath should always be provided in local encoding. int (*Field_browse)(struct _IPDF_JsPlatform* pThis, void* filePath, int length); // Pointer for embedder-specific data. Unused by PDFium, and despite // its name, can be any data the embedder desires, though traditionally // a FPDF_FORMFILLINFO interface. void* m_pFormfillinfo; // Version 2. void* m_isolate; // Unused in v3, retain for compatibility. unsigned int m_v8EmbedderSlot; // Unused in v3, retain for compatibility. // Version 3. // Version 3 moves m_Isolate and m_v8EmbedderSlot to FPDF_LIBRARY_CONFIG. } IPDF_JSPLATFORM; // Flags for Cursor type #define FXCT_ARROW 0 #define FXCT_NESW 1 #define FXCT_NWSE 2 #define FXCT_VBEAM 3 #define FXCT_HBEAM 4 #define FXCT_HAND 5 // Function signature for the callback function passed to the FFI_SetTimer // method. // Parameters: // idEvent - Identifier of the timer. // Return value: // None. typedef void (*TimerCallback)(int idEvent); // Declares of a struct type to the local system time. typedef struct _FPDF_SYSTEMTIME { unsigned short wYear; // years since 1900 unsigned short wMonth; // months since January - [0,11] unsigned short wDayOfWeek; // days since Sunday - [0,6] unsigned short wDay; // day of the month - [1,31] unsigned short wHour; // hours since midnight - [0,23] unsigned short wMinute; // minutes after the hour - [0,59] unsigned short wSecond; // seconds after the minute - [0,59] unsigned short wMilliseconds; // milliseconds after the second - [0,999] } FPDF_SYSTEMTIME; #ifdef PDF_ENABLE_XFA // Pageview event flags #define FXFA_PAGEVIEWEVENT_POSTADDED 1 // After a new pageview is added. #define FXFA_PAGEVIEWEVENT_POSTREMOVED 3 // After a pageview is removed. // Definitions for Right Context Menu Features Of XFA Fields #define FXFA_MENU_COPY 1 #define FXFA_MENU_CUT 2 #define FXFA_MENU_SELECTALL 4 #define FXFA_MENU_UNDO 8 #define FXFA_MENU_REDO 16 #define FXFA_MENU_PASTE 32 // Definitions for File Type. #define FXFA_SAVEAS_XML 1 #define FXFA_SAVEAS_XDP 2 #endif // PDF_ENABLE_XFA typedef struct _FPDF_FORMFILLINFO { // Version number of the interface. // Version 1 contains stable interfaces. Version 2 has additional // experimental interfaces. // When PDFium is built without the XFA module, version can be 1 or 2. // With version 1, only stable interfaces are called. With version 2, // additional experimental interfaces are also called. // When PDFium is built with the XFA module, version must be 2. // All the XFA related interfaces are experimental. If PDFium is built with // the XFA module and version 1 then none of the XFA related interfaces // would be called. When PDFium is built with XFA module then the version // must be 2. int version; // Version 1. // Method: Release // Give the implementation a chance to release any resources after the // interface is no longer used. // Interface Version: // 1 // Implementation Required: // No // Comments: // Called by PDFium during the final cleanup process. // Parameters: // pThis - Pointer to the interface structure itself // Return Value: // None void (*Release)(struct _FPDF_FORMFILLINFO* pThis); // Method: FFI_Invalidate // Invalidate the client area within the specified rectangle. // Interface Version: // 1 // Implementation Required: // yes // Parameters: // pThis - Pointer to the interface structure itself. // page - Handle to the page. Returned by FPDF_LoadPage(). // left - Left position of the client area in PDF page // coordinates. // top - Top position of the client area in PDF page // coordinates. // right - Right position of the client area in PDF page // coordinates. // bottom - Bottom position of the client area in PDF page // coordinates. // Return Value: // None. // Comments: // All positions are measured in PDF "user space". // Implementation should call FPDF_RenderPageBitmap() for repainting // the specified page area. void (*FFI_Invalidate)(struct _FPDF_FORMFILLINFO* pThis, FPDF_PAGE page, double left, double top, double right, double bottom); // Method: FFI_OutputSelectedRect // When the user selects text in form fields with the mouse, this // callback function will be invoked with the selected areas. // Interface Version: // 1 // Implementation Required: // No // Parameters: // pThis - Pointer to the interface structure itself. // page - Handle to the page. Returned by FPDF_LoadPage()/ // left - Left position of the client area in PDF page // coordinates. // top - Top position of the client area in PDF page // coordinates. // right - Right position of the client area in PDF page // coordinates. // bottom - Bottom position of the client area in PDF page // coordinates. // Return Value: // None. // Comments: // This callback function is useful for implementing special text // selection effects. An implementation should first record the // returned rectangles, then draw them one by one during the next // painting period. Lastly, it should remove all the recorded // rectangles when finished painting. void (*FFI_OutputSelectedRect)(struct _FPDF_FORMFILLINFO* pThis, FPDF_PAGE page, double left, double top, double right, double bottom); // Method: FFI_SetCursor // Set the Cursor shape. // Interface Version: // 1 // Implementation Required: // yes // Parameters: // pThis - Pointer to the interface structure itself. // nCursorType - Cursor type, see Flags for Cursor type for details. // Return value: // None. void (*FFI_SetCursor)(struct _FPDF_FORMFILLINFO* pThis, int nCursorType); // Method: FFI_SetTimer // This method installs a system timer. An interval value is specified, // and every time that interval elapses, the system must call into the // callback function with the timer ID as returned by this function. // Interface Version: // 1 // Implementation Required: // yes // Parameters: // pThis - Pointer to the interface structure itself. // uElapse - Specifies the time-out value, in milliseconds. // lpTimerFunc - A pointer to the callback function-TimerCallback. // Return value: // The timer identifier of the new timer if the function is successful. // An application passes this value to the FFI_KillTimer method to kill // the timer. Nonzero if it is successful; otherwise, it is zero. int (*FFI_SetTimer)(struct _FPDF_FORMFILLINFO* pThis, int uElapse, TimerCallback lpTimerFunc); // Method: FFI_KillTimer // This method uninstalls a system timer, as set by an earlier call to // FFI_SetTimer. // Interface Version: // 1 // Implementation Required: // yes // Parameters: // pThis - Pointer to the interface structure itself. // nTimerID - The timer ID returned by FFI_SetTimer function. // Return value: // None. void (*FFI_KillTimer)(struct _FPDF_FORMFILLINFO* pThis, int nTimerID); // Method: FFI_GetLocalTime // This method receives the current local time on the system. // Interface Version: // 1 // Implementation Required: // yes // Parameters: // pThis - Pointer to the interface structure itself. // Return value: // The local time. See FPDF_SYSTEMTIME above for details. // Note: Unused. FPDF_SYSTEMTIME (*FFI_GetLocalTime)(struct _FPDF_FORMFILLINFO* pThis); // Method: FFI_OnChange // This method will be invoked to notify the implementation when the // value of any FormField on the document had been changed. // Interface Version: // 1 // Implementation Required: // no // Parameters: // pThis - Pointer to the interface structure itself. // Return value: // None. void (*FFI_OnChange)(struct _FPDF_FORMFILLINFO* pThis); // Method: FFI_GetPage // This method receives the page handle associated with a specified // page index. // Interface Version: // 1 // Implementation Required: // yes // Parameters: // pThis - Pointer to the interface structure itself. // document - Handle to document. Returned by FPDF_LoadDocument(). // nPageIndex - Index number of the page. 0 for the first page. // Return value: // Handle to the page, as previously returned to the implementation by // FPDF_LoadPage(). // Comments: // The implementation is expected to keep track of the page handles it // receives from PDFium, and their mappings to page numbers. In some // cases, the document-level JavaScript action may refer to a page // which hadn't been loaded yet. To successfully run the Javascript // action, the implementation needs to load the page. FPDF_PAGE (*FFI_GetPage)(struct _FPDF_FORMFILLINFO* pThis, FPDF_DOCUMENT document, int nPageIndex); // Method: FFI_GetCurrentPage // This method receives the handle to the current page. // Interface Version: // 1 // Implementation Required: // Yes when V8 support is present, otherwise unused. // Parameters: // pThis - Pointer to the interface structure itself. // document - Handle to document. Returned by FPDF_LoadDocument(). // Return value: // Handle to the page. Returned by FPDF_LoadPage(). // Comments: // PDFium doesn't keep keep track of the "current page" (e.g. the one // that is most visible on screen), so it must ask the embedder for // this information. FPDF_PAGE (*FFI_GetCurrentPage)(struct _FPDF_FORMFILLINFO* pThis, FPDF_DOCUMENT document); // Method: FFI_GetRotation // This method receives currently rotation of the page view. // Interface Version: // 1 // Implementation Required: // yes // Parameters: // pThis - Pointer to the interface structure itself. // page - Handle to page, as returned by FPDF_LoadPage(). // Return value: // A number to indicate the page rotation in 90 degree increments // in a clockwise direction: // 0 - 0 degrees // 1 - 90 degrees // 2 - 180 degrees // 3 - 270 degrees // Note: Unused. int (*FFI_GetRotation)(struct _FPDF_FORMFILLINFO* pThis, FPDF_PAGE page); // Method: FFI_ExecuteNamedAction // This method will execute a named action. // Interface Version: // 1 // Implementation Required: // yes // Parameters: // pThis - Pointer to the interface structure itself. // namedAction - A byte string which indicates the named action, // terminated by 0. // Return value: // None. // Comments: // See ISO 32000-1:2008, section 12.6.4.11 for descriptions of the // standard named actions, but note that a document may supply any // name of its choosing. void (*FFI_ExecuteNamedAction)(struct _FPDF_FORMFILLINFO* pThis, FPDF_BYTESTRING namedAction); // Method: FFI_SetTextFieldFocus // Called when a text field is getting or losing focus. // Interface Version: // 1 // Implementation Required: // no // Parameters: // pThis - Pointer to the interface structure itself. // value - The string value of the form field, in UTF-16LE // format. // valueLen - The length of the string value. This is the // number of characters, not bytes. // is_focus - True if the form field is getting focus, false // if the form field is losing focus. // Return value: // None. // Comments: // Only supports text fields and combobox fields. void (*FFI_SetTextFieldFocus)(struct _FPDF_FORMFILLINFO* pThis, FPDF_WIDESTRING value, FPDF_DWORD valueLen, FPDF_BOOL is_focus); // Method: FFI_DoURIAction // Ask the implementation to navigate to a uniform resource identifier. // Interface Version: // 1 // Implementation Required: // No // Parameters: // pThis - Pointer to the interface structure itself. // bsURI - A byte string which indicates the uniform // resource identifier, terminated by 0. // Return value: // None. // Comments: // If the embedder is version 2 or higher and have implementation for // FFI_DoURIActionWithKeyboardModifier, then // FFI_DoURIActionWithKeyboardModifier takes precedence over // FFI_DoURIAction. // See the URI actions description of <> // for more details. void (*FFI_DoURIAction)(struct _FPDF_FORMFILLINFO* pThis, FPDF_BYTESTRING bsURI); // Method: FFI_DoGoToAction // This action changes the view to a specified destination. // Interface Version: // 1 // Implementation Required: // No // Parameters: // pThis - Pointer to the interface structure itself. // nPageIndex - The index of the PDF page. // zoomMode - The zoom mode for viewing page. See below. // fPosArray - The float array which carries the position info. // sizeofArray - The size of float array. // PDFZoom values: // - XYZ = 1 // - FITPAGE = 2 // - FITHORZ = 3 // - FITVERT = 4 // - FITRECT = 5 // - FITBBOX = 6 // - FITBHORZ = 7 // - FITBVERT = 8 // Return value: // None. // Comments: // See the Destinations description of <> // in 8.2.1 for more details. void (*FFI_DoGoToAction)(struct _FPDF_FORMFILLINFO* pThis, int nPageIndex, int zoomMode, float* fPosArray, int sizeofArray); // Pointer to IPDF_JSPLATFORM interface. // Unused if PDFium is built without V8 support. Otherwise, if NULL, then // JavaScript will be prevented from executing while rendering the document. IPDF_JSPLATFORM* m_pJsPlatform; // Version 2 - Experimental. // Whether the XFA module is disabled when built with the XFA module. // Interface Version: // Ignored if |version| < 2. FPDF_BOOL xfa_disabled; // Method: FFI_DisplayCaret // This method will show the caret at specified position. // Interface Version: // Ignored if |version| < 2. // Implementation Required: // Required for XFA, otherwise set to NULL. // Parameters: // pThis - Pointer to the interface structure itself. // page - Handle to page. Returned by FPDF_LoadPage(). // left - Left position of the client area in PDF page // coordinates. // top - Top position of the client area in PDF page // coordinates. // right - Right position of the client area in PDF page // coordinates. // bottom - Bottom position of the client area in PDF page // coordinates. // Return value: // None. void (*FFI_DisplayCaret)(struct _FPDF_FORMFILLINFO* pThis, FPDF_PAGE page, FPDF_BOOL bVisible, double left, double top, double right, double bottom); // Method: FFI_GetCurrentPageIndex // This method will get the current page index. // Interface Version: // Ignored if |version| < 2. // Implementation Required: // Required for XFA, otherwise set to NULL. // Parameters: // pThis - Pointer to the interface structure itself. // document - Handle to document from FPDF_LoadDocument(). // Return value: // The index of current page. int (*FFI_GetCurrentPageIndex)(struct _FPDF_FORMFILLINFO* pThis, FPDF_DOCUMENT document); // Method: FFI_SetCurrentPage // This method will set the current page. // Interface Version: // Ignored if |version| < 2. // Implementation Required: // Required for XFA, otherwise set to NULL. // Parameters: // pThis - Pointer to the interface structure itself. // document - Handle to document from FPDF_LoadDocument(). // iCurPage - The index of the PDF page. // Return value: // None. void (*FFI_SetCurrentPage)(struct _FPDF_FORMFILLINFO* pThis, FPDF_DOCUMENT document, int iCurPage); // Method: FFI_GotoURL // This method will navigate to the specified URL. // Interface Version: // Ignored if |version| < 2. // Implementation Required: // Required for XFA, otherwise set to NULL. // Parameters: // pThis - Pointer to the interface structure itself. // document - Handle to document from FPDF_LoadDocument(). // wsURL - The string value of the URL, in UTF-16LE format. // Return value: // None. void (*FFI_GotoURL)(struct _FPDF_FORMFILLINFO* pThis, FPDF_DOCUMENT document, FPDF_WIDESTRING wsURL); // Method: FFI_GetPageViewRect // This method will get the current page view rectangle. // Interface Version: // Ignored if |version| < 2. // Implementation Required: // Required for XFA, otherwise set to NULL. // Parameters: // pThis - Pointer to the interface structure itself. // page - Handle to page. Returned by FPDF_LoadPage(). // left - The pointer to receive left position of the page // view area in PDF page coordinates. // top - The pointer to receive top position of the page // view area in PDF page coordinates. // right - The pointer to receive right position of the // page view area in PDF page coordinates. // bottom - The pointer to receive bottom position of the // page view area in PDF page coordinates. // Return value: // None. void (*FFI_GetPageViewRect)(struct _FPDF_FORMFILLINFO* pThis, FPDF_PAGE page, double* left, double* top, double* right, double* bottom); // Method: FFI_PageEvent // This method fires when pages have been added to or deleted from // the XFA document. // Interface Version: // Ignored if |version| < 2. // Implementation Required: // Required for XFA, otherwise set to NULL. // Parameters: // pThis - Pointer to the interface structure itself. // page_count - The number of pages to be added or deleted. // event_type - See FXFA_PAGEVIEWEVENT_* above. // Return value: // None. // Comments: // The pages to be added or deleted always start from the last page // of document. This means that if parameter page_count is 2 and // event type is FXFA_PAGEVIEWEVENT_POSTADDED, 2 new pages have been // appended to the tail of document; If page_count is 2 and // event type is FXFA_PAGEVIEWEVENT_POSTREMOVED, the last 2 pages // have been deleted. void (*FFI_PageEvent)(struct _FPDF_FORMFILLINFO* pThis, int page_count, FPDF_DWORD event_type); // Method: FFI_PopupMenu // This method will track the right context menu for XFA fields. // Interface Version: // Ignored if |version| < 2. // Implementation Required: // Required for XFA, otherwise set to NULL. // Parameters: // pThis - Pointer to the interface structure itself. // page - Handle to page. Returned by FPDF_LoadPage(). // hWidget - Always null, exists for compatibility. // menuFlag - The menu flags. Please refer to macro definition // of FXFA_MENU_XXX and this can be one or a // combination of these macros. // x - X position of the client area in PDF page // coordinates. // y - Y position of the client area in PDF page // coordinates. // Return value: // TRUE indicates success; otherwise false. FPDF_BOOL (*FFI_PopupMenu)(struct _FPDF_FORMFILLINFO* pThis, FPDF_PAGE page, FPDF_WIDGET hWidget, int menuFlag, float x, float y); // Method: FFI_OpenFile // This method will open the specified file with the specified mode. // Interface Version: // Ignored if |version| < 2. // Implementation Required: // Required for XFA, otherwise set to NULL. // Parameters: // pThis - Pointer to the interface structure itself. // fileFlag - The file flag. Please refer to macro definition // of FXFA_SAVEAS_XXX and use one of these macros. // wsURL - The string value of the file URL, in UTF-16LE // format. // mode - The mode for open file, e.g. "rb" or "wb". // Return value: // The handle to FPDF_FILEHANDLER. FPDF_FILEHANDLER* (*FFI_OpenFile)(struct _FPDF_FORMFILLINFO* pThis, int fileFlag, FPDF_WIDESTRING wsURL, const char* mode); // Method: FFI_EmailTo // This method will email the specified file stream to the specified // contact. // Interface Version: // Ignored if |version| < 2. // Implementation Required: // Required for XFA, otherwise set to NULL. // Parameters: // pThis - Pointer to the interface structure itself. // pFileHandler - Handle to the FPDF_FILEHANDLER. // pTo - A semicolon-delimited list of recipients for the // message,in UTF-16LE format. // pSubject - The subject of the message,in UTF-16LE format. // pCC - A semicolon-delimited list of CC recipients for // the message,in UTF-16LE format. // pBcc - A semicolon-delimited list of BCC recipients for // the message,in UTF-16LE format. // pMsg - Pointer to the data buffer to be sent.Can be // NULL,in UTF-16LE format. // Return value: // None. void (*FFI_EmailTo)(struct _FPDF_FORMFILLINFO* pThis, FPDF_FILEHANDLER* fileHandler, FPDF_WIDESTRING pTo, FPDF_WIDESTRING pSubject, FPDF_WIDESTRING pCC, FPDF_WIDESTRING pBcc, FPDF_WIDESTRING pMsg); // Method: FFI_UploadTo // This method will upload the specified file stream to the // specified URL. // Interface Version: // Ignored if |version| < 2. // Implementation Required: // Required for XFA, otherwise set to NULL. // Parameters: // pThis - Pointer to the interface structure itself. // pFileHandler - Handle to the FPDF_FILEHANDLER. // fileFlag - The file flag. Please refer to macro definition // of FXFA_SAVEAS_XXX and use one of these macros. // uploadTo - Pointer to the URL path, in UTF-16LE format. // Return value: // None. void (*FFI_UploadTo)(struct _FPDF_FORMFILLINFO* pThis, FPDF_FILEHANDLER* fileHandler, int fileFlag, FPDF_WIDESTRING uploadTo); // Method: FFI_GetPlatform // This method will get the current platform. // Interface Version: // Ignored if |version| < 2. // Implementation Required: // Required for XFA, otherwise set to NULL. // Parameters: // pThis - Pointer to the interface structure itself. // platform - Pointer to the data buffer to receive the // platform,in UTF-16LE format. Can be NULL. // length - The length of the buffer in bytes. Can be // 0 to query the required size. // Return value: // The length of the buffer, number of bytes. int (*FFI_GetPlatform)(struct _FPDF_FORMFILLINFO* pThis, void* platform, int length); // Method: FFI_GetLanguage // This method will get the current language. // Interface Version: // Ignored if |version| < 2. // Implementation Required: // Required for XFA, otherwise set to NULL. // Parameters: // pThis - Pointer to the interface structure itself. // language - Pointer to the data buffer to receive the // current language. Can be NULL. // length - The length of the buffer in bytes. Can be // 0 to query the required size. // Return value: // The length of the buffer, number of bytes. int (*FFI_GetLanguage)(struct _FPDF_FORMFILLINFO* pThis, void* language, int length); // Method: FFI_DownloadFromURL // This method will download the specified file from the URL. // Interface Version: // Ignored if |version| < 2. // Implementation Required: // Required for XFA, otherwise set to NULL. // Parameters: // pThis - Pointer to the interface structure itself. // URL - The string value of the file URL, in UTF-16LE // format. // Return value: // The handle to FPDF_FILEHANDLER. FPDF_FILEHANDLER* (*FFI_DownloadFromURL)(struct _FPDF_FORMFILLINFO* pThis, FPDF_WIDESTRING URL); // Method: FFI_PostRequestURL // This method will post the request to the server URL. // Interface Version: // Ignored if |version| < 2. // Implementation Required: // Required for XFA, otherwise set to NULL. // Parameters: // pThis - Pointer to the interface structure itself. // wsURL - The string value of the server URL, in UTF-16LE // format. // wsData - The post data,in UTF-16LE format. // wsContentType - The content type of the request data, in // UTF-16LE format. // wsEncode - The encode type, in UTF-16LE format. // wsHeader - The request header,in UTF-16LE format. // response - Pointer to the FPDF_BSTR to receive the response // data from the server, in UTF-16LE format. // Return value: // TRUE indicates success, otherwise FALSE. FPDF_BOOL (*FFI_PostRequestURL)(struct _FPDF_FORMFILLINFO* pThis, FPDF_WIDESTRING wsURL, FPDF_WIDESTRING wsData, FPDF_WIDESTRING wsContentType, FPDF_WIDESTRING wsEncode, FPDF_WIDESTRING wsHeader, FPDF_BSTR* response); // Method: FFI_PutRequestURL // This method will put the request to the server URL. // Interface Version: // Ignored if |version| < 2. // Implementation Required: // Required for XFA, otherwise set to NULL. // Parameters: // pThis - Pointer to the interface structure itself. // wsURL - The string value of the server URL, in UTF-16LE // format. // wsData - The put data, in UTF-16LE format. // wsEncode - The encode type, in UTR-16LE format. // Return value: // TRUE indicates success, otherwise FALSE. FPDF_BOOL (*FFI_PutRequestURL)(struct _FPDF_FORMFILLINFO* pThis, FPDF_WIDESTRING wsURL, FPDF_WIDESTRING wsData, FPDF_WIDESTRING wsEncode); // Method: FFI_OnFocusChange // Called when the focused annotation is updated. // Interface Version: // Ignored if |version| < 2. // Implementation Required: // No // Parameters: // param - Pointer to the interface structure itself. // annot - The focused annotation. // page_index - Index number of the page which contains the // focused annotation. 0 for the first page. // Return value: // None. // Comments: // This callback function is useful for implementing any view based // action such as scrolling the annotation rect into view. The // embedder should not copy and store the annot as its scope is // limited to this call only. void (*FFI_OnFocusChange)(struct _FPDF_FORMFILLINFO* param, FPDF_ANNOTATION annot, int page_index); // Method: FFI_DoURIActionWithKeyboardModifier // Ask the implementation to navigate to a uniform resource identifier // with the specified modifiers. // Interface Version: // Ignored if |version| < 2. // Implementation Required: // No // Parameters: // param - Pointer to the interface structure itself. // uri - A byte string which indicates the uniform // resource identifier, terminated by 0. // modifiers - Keyboard modifier that indicates which of // the virtual keys are down, if any. // Return value: // None. // Comments: // If the embedder who is version 2 and does not implement this API, // then a call will be redirected to FFI_DoURIAction. // See the URI actions description of <> // for more details. void(*FFI_DoURIActionWithKeyboardModifier)(struct _FPDF_FORMFILLINFO* param, FPDF_BYTESTRING uri, int modifiers); } FPDF_FORMFILLINFO; // Function: FPDFDOC_InitFormFillEnvironment // Initialize form fill environment. // Parameters: // document - Handle to document from FPDF_LoadDocument(). // formInfo - Pointer to a FPDF_FORMFILLINFO structure. // Return Value: // Handle to the form fill module, or NULL on failure. // Comments: // This function should be called before any form fill operation. // The FPDF_FORMFILLINFO passed in via |formInfo| must remain valid until // the returned FPDF_FORMHANDLE is closed. FPDF_EXPORT FPDF_FORMHANDLE FPDF_CALLCONV FPDFDOC_InitFormFillEnvironment(FPDF_DOCUMENT document, FPDF_FORMFILLINFO* formInfo); // Function: FPDFDOC_ExitFormFillEnvironment // Take ownership of |hHandle| and exit form fill environment. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // Return Value: // None. // Comments: // This function is a no-op when |hHandle| is null. FPDF_EXPORT void FPDF_CALLCONV FPDFDOC_ExitFormFillEnvironment(FPDF_FORMHANDLE hHandle); // Function: FORM_OnAfterLoadPage // This method is required for implementing all the form related // functions. Should be invoked after user successfully loaded a // PDF page, and FPDFDOC_InitFormFillEnvironment() has been invoked. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // Return Value: // None. FPDF_EXPORT void FPDF_CALLCONV FORM_OnAfterLoadPage(FPDF_PAGE page, FPDF_FORMHANDLE hHandle); // Function: FORM_OnBeforeClosePage // This method is required for implementing all the form related // functions. Should be invoked before user closes the PDF page. // Parameters: // page - Handle to the page, as returned by FPDF_LoadPage(). // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // Return Value: // None. FPDF_EXPORT void FPDF_CALLCONV FORM_OnBeforeClosePage(FPDF_PAGE page, FPDF_FORMHANDLE hHandle); // Function: FORM_DoDocumentJSAction // This method is required for performing document-level JavaScript // actions. It should be invoked after the PDF document has been loaded. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // Return Value: // None. // Comments: // If there is document-level JavaScript action embedded in the // document, this method will execute the JavaScript action. Otherwise, // the method will do nothing. FPDF_EXPORT void FPDF_CALLCONV FORM_DoDocumentJSAction(FPDF_FORMHANDLE hHandle); // Function: FORM_DoDocumentOpenAction // This method is required for performing open-action when the document // is opened. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // Return Value: // None. // Comments: // This method will do nothing if there are no open-actions embedded // in the document. FPDF_EXPORT void FPDF_CALLCONV FORM_DoDocumentOpenAction(FPDF_FORMHANDLE hHandle); // Additional actions type of document: // WC, before closing document, JavaScript action. // WS, before saving document, JavaScript action. // DS, after saving document, JavaScript action. // WP, before printing document, JavaScript action. // DP, after printing document, JavaScript action. #define FPDFDOC_AACTION_WC 0x10 #define FPDFDOC_AACTION_WS 0x11 #define FPDFDOC_AACTION_DS 0x12 #define FPDFDOC_AACTION_WP 0x13 #define FPDFDOC_AACTION_DP 0x14 // Function: FORM_DoDocumentAAction // This method is required for performing the document's // additional-action. // Parameters: // hHandle - Handle to the form fill module. Returned by // FPDFDOC_InitFormFillEnvironment. // aaType - The type of the additional-actions which defined // above. // Return Value: // None. // Comments: // This method will do nothing if there is no document // additional-action corresponding to the specified |aaType|. FPDF_EXPORT void FPDF_CALLCONV FORM_DoDocumentAAction(FPDF_FORMHANDLE hHandle, int aaType); // Additional-action types of page object: // OPEN (/O) -- An action to be performed when the page is opened // CLOSE (/C) -- An action to be performed when the page is closed #define FPDFPAGE_AACTION_OPEN 0 #define FPDFPAGE_AACTION_CLOSE 1 // Function: FORM_DoPageAAction // This method is required for performing the page object's // additional-action when opened or closed. // Parameters: // page - Handle to the page, as returned by FPDF_LoadPage(). // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // aaType - The type of the page object's additional-actions // which defined above. // Return Value: // None. // Comments: // This method will do nothing if no additional-action corresponding // to the specified |aaType| exists. FPDF_EXPORT void FPDF_CALLCONV FORM_DoPageAAction(FPDF_PAGE page, FPDF_FORMHANDLE hHandle, int aaType); // Function: FORM_OnMouseMove // Call this member function when the mouse cursor moves. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page, as returned by FPDF_LoadPage(). // modifier - Indicates whether various virtual keys are down. // page_x - Specifies the x-coordinate of the cursor in PDF user // space. // page_y - Specifies the y-coordinate of the cursor in PDF user // space. // Return Value: // True indicates success; otherwise false. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnMouseMove(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, int modifier, double page_x, double page_y); // Experimental API // Function: FORM_OnMouseWheel // Call this member function when the user scrolls the mouse wheel. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page, as returned by FPDF_LoadPage(). // modifier - Indicates whether various virtual keys are down. // page_coord - Specifies the coordinates of the cursor in PDF user // space. // delta_x - Specifies the amount of wheel movement on the x-axis, // in units of platform-agnostic wheel deltas. Negative // values mean left. // delta_y - Specifies the amount of wheel movement on the y-axis, // in units of platform-agnostic wheel deltas. Negative // values mean down. // Return Value: // True indicates success; otherwise false. // Comments: // For |delta_x| and |delta_y|, the caller must normalize // platform-specific wheel deltas. e.g. On Windows, a delta value of 240 // for a WM_MOUSEWHEEL event normalizes to 2, since Windows defines // WHEEL_DELTA as 120. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnMouseWheel( FPDF_FORMHANDLE hHandle, FPDF_PAGE page, int modifier, const FS_POINTF* page_coord, int delta_x, int delta_y); // Function: FORM_OnFocus // This function focuses the form annotation at a given point. If the // annotation at the point already has focus, nothing happens. If there // is no annotation at the point, removes form focus. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page, as returned by FPDF_LoadPage(). // modifier - Indicates whether various virtual keys are down. // page_x - Specifies the x-coordinate of the cursor in PDF user // space. // page_y - Specifies the y-coordinate of the cursor in PDF user // space. // Return Value: // True if there is an annotation at the given point and it has focus. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnFocus(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, int modifier, double page_x, double page_y); // Function: FORM_OnLButtonDown // Call this member function when the user presses the left // mouse button. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page, as returned by FPDF_LoadPage(). // modifier - Indicates whether various virtual keys are down. // page_x - Specifies the x-coordinate of the cursor in PDF user // space. // page_y - Specifies the y-coordinate of the cursor in PDF user // space. // Return Value: // True indicates success; otherwise false. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnLButtonDown(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, int modifier, double page_x, double page_y); // Function: FORM_OnRButtonDown // Same as above, execpt for the right mouse button. // Comments: // At the present time, has no effect except in XFA builds, but is // included for the sake of symmetry. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnRButtonDown(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, int modifier, double page_x, double page_y); // Function: FORM_OnLButtonUp // Call this member function when the user releases the left // mouse button. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page, as returned by FPDF_LoadPage(). // modifier - Indicates whether various virtual keys are down. // page_x - Specifies the x-coordinate of the cursor in device. // page_y - Specifies the y-coordinate of the cursor in device. // Return Value: // True indicates success; otherwise false. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnLButtonUp(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, int modifier, double page_x, double page_y); // Function: FORM_OnRButtonUp // Same as above, execpt for the right mouse button. // Comments: // At the present time, has no effect except in XFA builds, but is // included for the sake of symmetry. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnRButtonUp(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, int modifier, double page_x, double page_y); // Function: FORM_OnLButtonDoubleClick // Call this member function when the user double clicks the // left mouse button. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page, as returned by FPDF_LoadPage(). // modifier - Indicates whether various virtual keys are down. // page_x - Specifies the x-coordinate of the cursor in PDF user // space. // page_y - Specifies the y-coordinate of the cursor in PDF user // space. // Return Value: // True indicates success; otherwise false. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnLButtonDoubleClick(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, int modifier, double page_x, double page_y); // Function: FORM_OnKeyDown // Call this member function when a nonsystem key is pressed. // Parameters: // hHandle - Handle to the form fill module, aseturned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page, as returned by FPDF_LoadPage(). // nKeyCode - The virtual-key code of the given key (see // fpdf_fwlevent.h for virtual key codes). // modifier - Mask of key flags (see fpdf_fwlevent.h for key // flag values). // Return Value: // True indicates success; otherwise false. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnKeyDown(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, int nKeyCode, int modifier); // Function: FORM_OnKeyUp // Call this member function when a nonsystem key is released. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page, as returned by FPDF_LoadPage(). // nKeyCode - The virtual-key code of the given key (see // fpdf_fwlevent.h for virtual key codes). // modifier - Mask of key flags (see fpdf_fwlevent.h for key // flag values). // Return Value: // True indicates success; otherwise false. // Comments: // Currently unimplemented and always returns false. PDFium reserves this // API and may implement it in the future on an as-needed basis. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnKeyUp(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, int nKeyCode, int modifier); // Function: FORM_OnChar // Call this member function when a keystroke translates to a // nonsystem character. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page, as returned by FPDF_LoadPage(). // nChar - The character code value itself. // modifier - Mask of key flags (see fpdf_fwlevent.h for key // flag values). // Return Value: // True indicates success; otherwise false. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnChar(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, int nChar, int modifier); // Experimental API // Function: FORM_GetFocusedText // Call this function to obtain the text within the current focused // field, if any. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page, as returned by FPDF_LoadPage(). // buffer - Buffer for holding the form text, encoded in // UTF-16LE. If NULL, |buffer| is not modified. // buflen - Length of |buffer| in bytes. If |buflen| is less // than the length of the form text string, |buffer| is // not modified. // Return Value: // Length in bytes for the text in the focused field. FPDF_EXPORT unsigned long FPDF_CALLCONV FORM_GetFocusedText(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, void* buffer, unsigned long buflen); // Function: FORM_GetSelectedText // Call this function to obtain selected text within a form text // field or form combobox text field. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page, as returned by FPDF_LoadPage(). // buffer - Buffer for holding the selected text, encoded in // UTF-16LE. If NULL, |buffer| is not modified. // buflen - Length of |buffer| in bytes. If |buflen| is less // than the length of the selected text string, // |buffer| is not modified. // Return Value: // Length in bytes of selected text in form text field or form combobox // text field. FPDF_EXPORT unsigned long FPDF_CALLCONV FORM_GetSelectedText(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, void* buffer, unsigned long buflen); // Experimental API // Function: FORM_ReplaceAndKeepSelection // Call this function to replace the selected text in a form // text field or user-editable form combobox text field with another // text string (which can be empty or non-empty). If there is no // selected text, this function will append the replacement text after // the current caret position. After the insertion, the inserted text // will be selected. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page, as Returned by FPDF_LoadPage(). // wsText - The text to be inserted, in UTF-16LE format. // Return Value: // None. FPDF_EXPORT void FPDF_CALLCONV FORM_ReplaceAndKeepSelection(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, FPDF_WIDESTRING wsText); // Function: FORM_ReplaceSelection // Call this function to replace the selected text in a form // text field or user-editable form combobox text field with another // text string (which can be empty or non-empty). If there is no // selected text, this function will append the replacement text after // the current caret position. After the insertion, the selection range // will be set to empty. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page, as Returned by FPDF_LoadPage(). // wsText - The text to be inserted, in UTF-16LE format. // Return Value: // None. FPDF_EXPORT void FPDF_CALLCONV FORM_ReplaceSelection(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, FPDF_WIDESTRING wsText); // Experimental API // Function: FORM_SelectAllText // Call this function to select all the text within the currently focused // form text field or form combobox text field. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page, as returned by FPDF_LoadPage(). // Return Value: // Whether the operation succeeded or not. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_SelectAllText(FPDF_FORMHANDLE hHandle, FPDF_PAGE page); // Function: FORM_CanUndo // Find out if it is possible for the current focused widget in a given // form to perform an undo operation. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page, as returned by FPDF_LoadPage(). // Return Value: // True if it is possible to undo. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_CanUndo(FPDF_FORMHANDLE hHandle, FPDF_PAGE page); // Function: FORM_CanRedo // Find out if it is possible for the current focused widget in a given // form to perform a redo operation. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page, as returned by FPDF_LoadPage(). // Return Value: // True if it is possible to redo. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_CanRedo(FPDF_FORMHANDLE hHandle, FPDF_PAGE page); // Function: FORM_Undo // Make the current focused widget perform an undo operation. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page, as returned by FPDF_LoadPage(). // Return Value: // True if the undo operation succeeded. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_Undo(FPDF_FORMHANDLE hHandle, FPDF_PAGE page); // Function: FORM_Redo // Make the current focused widget perform a redo operation. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page, as returned by FPDF_LoadPage(). // Return Value: // True if the redo operation succeeded. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_Redo(FPDF_FORMHANDLE hHandle, FPDF_PAGE page); // Function: FORM_ForceToKillFocus. // Call this member function to force to kill the focus of the form // field which has focus. If it would kill the focus of a form field, // save the value of form field if was changed by theuser. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // Return Value: // True indicates success; otherwise false. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_ForceToKillFocus(FPDF_FORMHANDLE hHandle); // Experimental API. // Function: FORM_GetFocusedAnnot. // Call this member function to get the currently focused annotation. // Parameters: // handle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // page_index - Buffer to hold the index number of the page which // contains the focused annotation. 0 for the first page. // Can't be NULL. // annot - Buffer to hold the focused annotation. Can't be NULL. // Return Value: // On success, return true and write to the out parameters. Otherwise // return false and leave the out parameters unmodified. // Comments: // Not currently supported for XFA forms - will report no focused // annotation. // Must call FPDFPage_CloseAnnot() when the annotation returned in |annot| // by this function is no longer needed. // This will return true and set |page_index| to -1 and |annot| to NULL, // if there is no focused annotation. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_GetFocusedAnnot(FPDF_FORMHANDLE handle, int* page_index, FPDF_ANNOTATION* annot); // Experimental API. // Function: FORM_SetFocusedAnnot. // Call this member function to set the currently focused annotation. // Parameters: // handle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // annot - Handle to an annotation. // Return Value: // True indicates success; otherwise false. // Comments: // |annot| can't be NULL. To kill focus, use FORM_ForceToKillFocus() // instead. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_SetFocusedAnnot(FPDF_FORMHANDLE handle, FPDF_ANNOTATION annot); // Form Field Types // The names of the defines are stable, but the specific values associated with // them are not, so do not hardcode their values. #define FPDF_FORMFIELD_UNKNOWN 0 // Unknown. #define FPDF_FORMFIELD_PUSHBUTTON 1 // push button type. #define FPDF_FORMFIELD_CHECKBOX 2 // check box type. #define FPDF_FORMFIELD_RADIOBUTTON 3 // radio button type. #define FPDF_FORMFIELD_COMBOBOX 4 // combo box type. #define FPDF_FORMFIELD_LISTBOX 5 // list box type. #define FPDF_FORMFIELD_TEXTFIELD 6 // text field type. #define FPDF_FORMFIELD_SIGNATURE 7 // text field type. #ifdef PDF_ENABLE_XFA #define FPDF_FORMFIELD_XFA 8 // Generic XFA type. #define FPDF_FORMFIELD_XFA_CHECKBOX 9 // XFA check box type. #define FPDF_FORMFIELD_XFA_COMBOBOX 10 // XFA combo box type. #define FPDF_FORMFIELD_XFA_IMAGEFIELD 11 // XFA image field type. #define FPDF_FORMFIELD_XFA_LISTBOX 12 // XFA list box type. #define FPDF_FORMFIELD_XFA_PUSHBUTTON 13 // XFA push button type. #define FPDF_FORMFIELD_XFA_SIGNATURE 14 // XFA signture field type. #define FPDF_FORMFIELD_XFA_TEXTFIELD 15 // XFA text field type. #endif // PDF_ENABLE_XFA #ifdef PDF_ENABLE_XFA #define FPDF_FORMFIELD_COUNT 16 #else // PDF_ENABLE_XFA #define FPDF_FORMFIELD_COUNT 8 #endif // PDF_ENABLE_XFA #ifdef PDF_ENABLE_XFA #define IS_XFA_FORMFIELD(type) \ (((type) == FPDF_FORMFIELD_XFA) || \ ((type) == FPDF_FORMFIELD_XFA_CHECKBOX) || \ ((type) == FPDF_FORMFIELD_XFA_COMBOBOX) || \ ((type) == FPDF_FORMFIELD_XFA_IMAGEFIELD) || \ ((type) == FPDF_FORMFIELD_XFA_LISTBOX) || \ ((type) == FPDF_FORMFIELD_XFA_PUSHBUTTON) || \ ((type) == FPDF_FORMFIELD_XFA_SIGNATURE) || \ ((type) == FPDF_FORMFIELD_XFA_TEXTFIELD)) #endif // PDF_ENABLE_XFA // Function: FPDFPage_HasFormFieldAtPoint // Get the form field type by point. // Parameters: // hHandle - Handle to the form fill module. Returned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page. Returned by FPDF_LoadPage(). // page_x - X position in PDF "user space". // page_y - Y position in PDF "user space". // Return Value: // Return the type of the form field; -1 indicates no field. // See field types above. FPDF_EXPORT int FPDF_CALLCONV FPDFPage_HasFormFieldAtPoint(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, double page_x, double page_y); // Function: FPDFPage_FormFieldZOrderAtPoint // Get the form field z-order by point. // Parameters: // hHandle - Handle to the form fill module. Returned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page. Returned by FPDF_LoadPage(). // page_x - X position in PDF "user space". // page_y - Y position in PDF "user space". // Return Value: // Return the z-order of the form field; -1 indicates no field. // Higher numbers are closer to the front. FPDF_EXPORT int FPDF_CALLCONV FPDFPage_FormFieldZOrderAtPoint(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, double page_x, double page_y); // Function: FPDF_SetFormFieldHighlightColor // Set the highlight color of the specified (or all) form fields // in the document. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // doc - Handle to the document, as returned by // FPDF_LoadDocument(). // fieldType - A 32-bit integer indicating the type of a form // field (defined above). // color - The highlight color of the form field. Constructed by // 0xxxrrggbb. // Return Value: // None. // Comments: // When the parameter fieldType is set to FPDF_FORMFIELD_UNKNOWN, the // highlight color will be applied to all the form fields in the // document. // Please refresh the client window to show the highlight immediately // if necessary. FPDF_EXPORT void FPDF_CALLCONV FPDF_SetFormFieldHighlightColor(FPDF_FORMHANDLE hHandle, int fieldType, unsigned long color); // Function: FPDF_SetFormFieldHighlightAlpha // Set the transparency of the form field highlight color in the // document. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // doc - Handle to the document, as returaned by // FPDF_LoadDocument(). // alpha - The transparency of the form field highlight color, // between 0-255. // Return Value: // None. FPDF_EXPORT void FPDF_CALLCONV FPDF_SetFormFieldHighlightAlpha(FPDF_FORMHANDLE hHandle, unsigned char alpha); // Function: FPDF_RemoveFormFieldHighlight // Remove the form field highlight color in the document. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // Return Value: // None. // Comments: // Please refresh the client window to remove the highlight immediately // if necessary. FPDF_EXPORT void FPDF_CALLCONV FPDF_RemoveFormFieldHighlight(FPDF_FORMHANDLE hHandle); // Function: FPDF_FFLDraw // Render FormFields and popup window on a page to a device independent // bitmap. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // bitmap - Handle to the device independent bitmap (as the // output buffer). Bitmap handles can be created by // FPDFBitmap_Create(). // page - Handle to the page, as returned by FPDF_LoadPage(). // start_x - Left pixel position of the display area in the // device coordinates. // start_y - Top pixel position of the display area in the device // coordinates. // size_x - Horizontal size (in pixels) for displaying the page. // size_y - Vertical size (in pixels) for displaying the page. // rotate - Page orientation: 0 (normal), 1 (rotated 90 degrees // clockwise), 2 (rotated 180 degrees), 3 (rotated 90 // degrees counter-clockwise). // flags - 0 for normal display, or combination of flags // defined above. // Return Value: // None. // Comments: // This function is designed to render annotations that are // user-interactive, which are widget annotations (for FormFields) and // popup annotations. // With the FPDF_ANNOT flag, this function will render a popup annotation // when users mouse-hover on a non-widget annotation. Regardless of // FPDF_ANNOT flag, this function will always render widget annotations // for FormFields. // In order to implement the FormFill functions, implementation should // call this function after rendering functions, such as // FPDF_RenderPageBitmap() or FPDF_RenderPageBitmap_Start(), have // finished rendering the page contents. FPDF_EXPORT void FPDF_CALLCONV FPDF_FFLDraw(FPDF_FORMHANDLE hHandle, FPDF_BITMAP bitmap, FPDF_PAGE page, int start_x, int start_y, int size_x, int size_y, int rotate, int flags); #if defined(PDF_USE_SKIA) FPDF_EXPORT void FPDF_CALLCONV FPDF_FFLDrawSkia(FPDF_FORMHANDLE hHandle, FPDF_SKIA_CANVAS canvas, FPDF_PAGE page, int start_x, int start_y, int size_x, int size_y, int rotate, int flags); #endif // Experimental API // Function: FPDF_GetFormType // Returns the type of form contained in the PDF document. // Parameters: // document - Handle to document. // Return Value: // Integer value representing one of the FORMTYPE_ values. // Comments: // If |document| is NULL, then the return value is FORMTYPE_NONE. FPDF_EXPORT int FPDF_CALLCONV FPDF_GetFormType(FPDF_DOCUMENT document); // Experimental API // Function: FORM_SetIndexSelected // Selects/deselects the value at the given |index| of the focused // annotation. // Parameters: // hHandle - Handle to the form fill module. Returned by // FPDFDOC_InitFormFillEnvironment. // page - Handle to the page. Returned by FPDF_LoadPage // index - 0-based index of value to be set as // selected/unselected // selected - true to select, false to deselect // Return Value: // TRUE if the operation succeeded. // FALSE if the operation failed or widget is not a supported type. // Comments: // Intended for use with listbox/combobox widget types. Comboboxes // have at most a single value selected at a time which cannot be // deselected. Deselect on a combobox is a no-op that returns false. // Default implementation is a no-op that will return false for // other types. // Not currently supported for XFA forms - will return false. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_SetIndexSelected(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, int index, FPDF_BOOL selected); // Experimental API // Function: FORM_IsIndexSelected // Returns whether or not the value at |index| of the focused // annotation is currently selected. // Parameters: // hHandle - Handle to the form fill module. Returned by // FPDFDOC_InitFormFillEnvironment. // page - Handle to the page. Returned by FPDF_LoadPage // index - 0-based Index of value to check // Return Value: // TRUE if value at |index| is currently selected. // FALSE if value at |index| is not selected or widget is not a // supported type. // Comments: // Intended for use with listbox/combobox widget types. Default // implementation is a no-op that will return false for other types. // Not currently supported for XFA forms - will return false. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_IsIndexSelected(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, int index); // Function: FPDF_LoadXFA // If the document consists of XFA fields, call this method to // attempt to load XFA fields. // Parameters: // document - Handle to document from FPDF_LoadDocument(). // Return Value: // TRUE upon success, otherwise FALSE. If XFA support is not built // into PDFium, performs no action and always returns FALSE. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_LoadXFA(FPDF_DOCUMENT document); #ifdef __cplusplus } #endif #endif // PUBLIC_FPDF_FORMFILL_H_ ================================================ FILE: external/pdfium/macos-arm64/include/fpdf_fwlevent.h ================================================ // Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #ifndef PUBLIC_FPDF_FWLEVENT_H_ #define PUBLIC_FPDF_FWLEVENT_H_ // NOLINTNEXTLINE(build/include) #include "fpdfview.h" #ifdef __cplusplus extern "C" { #endif // __cplusplus // Key flags. typedef enum { FWL_EVENTFLAG_ShiftKey = 1 << 0, FWL_EVENTFLAG_ControlKey = 1 << 1, FWL_EVENTFLAG_AltKey = 1 << 2, FWL_EVENTFLAG_MetaKey = 1 << 3, FWL_EVENTFLAG_KeyPad = 1 << 4, FWL_EVENTFLAG_AutoRepeat = 1 << 5, FWL_EVENTFLAG_LeftButtonDown = 1 << 6, FWL_EVENTFLAG_MiddleButtonDown = 1 << 7, FWL_EVENTFLAG_RightButtonDown = 1 << 8, } FWL_EVENTFLAG; // Virtual keycodes. typedef enum { FWL_VKEY_Back = 0x08, FWL_VKEY_Tab = 0x09, FWL_VKEY_NewLine = 0x0A, FWL_VKEY_Clear = 0x0C, FWL_VKEY_Return = 0x0D, FWL_VKEY_Shift = 0x10, FWL_VKEY_Control = 0x11, FWL_VKEY_Menu = 0x12, FWL_VKEY_Pause = 0x13, FWL_VKEY_Capital = 0x14, FWL_VKEY_Kana = 0x15, FWL_VKEY_Hangul = 0x15, FWL_VKEY_Junja = 0x17, FWL_VKEY_Final = 0x18, FWL_VKEY_Hanja = 0x19, FWL_VKEY_Kanji = 0x19, FWL_VKEY_Escape = 0x1B, FWL_VKEY_Convert = 0x1C, FWL_VKEY_NonConvert = 0x1D, FWL_VKEY_Accept = 0x1E, FWL_VKEY_ModeChange = 0x1F, FWL_VKEY_Space = 0x20, FWL_VKEY_Prior = 0x21, FWL_VKEY_Next = 0x22, FWL_VKEY_End = 0x23, FWL_VKEY_Home = 0x24, FWL_VKEY_Left = 0x25, FWL_VKEY_Up = 0x26, FWL_VKEY_Right = 0x27, FWL_VKEY_Down = 0x28, FWL_VKEY_Select = 0x29, FWL_VKEY_Print = 0x2A, FWL_VKEY_Execute = 0x2B, FWL_VKEY_Snapshot = 0x2C, FWL_VKEY_Insert = 0x2D, FWL_VKEY_Delete = 0x2E, FWL_VKEY_Help = 0x2F, FWL_VKEY_0 = 0x30, FWL_VKEY_1 = 0x31, FWL_VKEY_2 = 0x32, FWL_VKEY_3 = 0x33, FWL_VKEY_4 = 0x34, FWL_VKEY_5 = 0x35, FWL_VKEY_6 = 0x36, FWL_VKEY_7 = 0x37, FWL_VKEY_8 = 0x38, FWL_VKEY_9 = 0x39, FWL_VKEY_A = 0x41, FWL_VKEY_B = 0x42, FWL_VKEY_C = 0x43, FWL_VKEY_D = 0x44, FWL_VKEY_E = 0x45, FWL_VKEY_F = 0x46, FWL_VKEY_G = 0x47, FWL_VKEY_H = 0x48, FWL_VKEY_I = 0x49, FWL_VKEY_J = 0x4A, FWL_VKEY_K = 0x4B, FWL_VKEY_L = 0x4C, FWL_VKEY_M = 0x4D, FWL_VKEY_N = 0x4E, FWL_VKEY_O = 0x4F, FWL_VKEY_P = 0x50, FWL_VKEY_Q = 0x51, FWL_VKEY_R = 0x52, FWL_VKEY_S = 0x53, FWL_VKEY_T = 0x54, FWL_VKEY_U = 0x55, FWL_VKEY_V = 0x56, FWL_VKEY_W = 0x57, FWL_VKEY_X = 0x58, FWL_VKEY_Y = 0x59, FWL_VKEY_Z = 0x5A, FWL_VKEY_LWin = 0x5B, FWL_VKEY_Command = 0x5B, FWL_VKEY_RWin = 0x5C, FWL_VKEY_Apps = 0x5D, FWL_VKEY_Sleep = 0x5F, FWL_VKEY_NumPad0 = 0x60, FWL_VKEY_NumPad1 = 0x61, FWL_VKEY_NumPad2 = 0x62, FWL_VKEY_NumPad3 = 0x63, FWL_VKEY_NumPad4 = 0x64, FWL_VKEY_NumPad5 = 0x65, FWL_VKEY_NumPad6 = 0x66, FWL_VKEY_NumPad7 = 0x67, FWL_VKEY_NumPad8 = 0x68, FWL_VKEY_NumPad9 = 0x69, FWL_VKEY_Multiply = 0x6A, FWL_VKEY_Add = 0x6B, FWL_VKEY_Separator = 0x6C, FWL_VKEY_Subtract = 0x6D, FWL_VKEY_Decimal = 0x6E, FWL_VKEY_Divide = 0x6F, FWL_VKEY_F1 = 0x70, FWL_VKEY_F2 = 0x71, FWL_VKEY_F3 = 0x72, FWL_VKEY_F4 = 0x73, FWL_VKEY_F5 = 0x74, FWL_VKEY_F6 = 0x75, FWL_VKEY_F7 = 0x76, FWL_VKEY_F8 = 0x77, FWL_VKEY_F9 = 0x78, FWL_VKEY_F10 = 0x79, FWL_VKEY_F11 = 0x7A, FWL_VKEY_F12 = 0x7B, FWL_VKEY_F13 = 0x7C, FWL_VKEY_F14 = 0x7D, FWL_VKEY_F15 = 0x7E, FWL_VKEY_F16 = 0x7F, FWL_VKEY_F17 = 0x80, FWL_VKEY_F18 = 0x81, FWL_VKEY_F19 = 0x82, FWL_VKEY_F20 = 0x83, FWL_VKEY_F21 = 0x84, FWL_VKEY_F22 = 0x85, FWL_VKEY_F23 = 0x86, FWL_VKEY_F24 = 0x87, FWL_VKEY_NunLock = 0x90, FWL_VKEY_Scroll = 0x91, FWL_VKEY_LShift = 0xA0, FWL_VKEY_RShift = 0xA1, FWL_VKEY_LControl = 0xA2, FWL_VKEY_RControl = 0xA3, FWL_VKEY_LMenu = 0xA4, FWL_VKEY_RMenu = 0xA5, FWL_VKEY_BROWSER_Back = 0xA6, FWL_VKEY_BROWSER_Forward = 0xA7, FWL_VKEY_BROWSER_Refresh = 0xA8, FWL_VKEY_BROWSER_Stop = 0xA9, FWL_VKEY_BROWSER_Search = 0xAA, FWL_VKEY_BROWSER_Favorites = 0xAB, FWL_VKEY_BROWSER_Home = 0xAC, FWL_VKEY_VOLUME_Mute = 0xAD, FWL_VKEY_VOLUME_Down = 0xAE, FWL_VKEY_VOLUME_Up = 0xAF, FWL_VKEY_MEDIA_NEXT_Track = 0xB0, FWL_VKEY_MEDIA_PREV_Track = 0xB1, FWL_VKEY_MEDIA_Stop = 0xB2, FWL_VKEY_MEDIA_PLAY_Pause = 0xB3, FWL_VKEY_MEDIA_LAUNCH_Mail = 0xB4, FWL_VKEY_MEDIA_LAUNCH_MEDIA_Select = 0xB5, FWL_VKEY_MEDIA_LAUNCH_APP1 = 0xB6, FWL_VKEY_MEDIA_LAUNCH_APP2 = 0xB7, FWL_VKEY_OEM_1 = 0xBA, FWL_VKEY_OEM_Plus = 0xBB, FWL_VKEY_OEM_Comma = 0xBC, FWL_VKEY_OEM_Minus = 0xBD, FWL_VKEY_OEM_Period = 0xBE, FWL_VKEY_OEM_2 = 0xBF, FWL_VKEY_OEM_3 = 0xC0, FWL_VKEY_OEM_4 = 0xDB, FWL_VKEY_OEM_5 = 0xDC, FWL_VKEY_OEM_6 = 0xDD, FWL_VKEY_OEM_7 = 0xDE, FWL_VKEY_OEM_8 = 0xDF, FWL_VKEY_OEM_102 = 0xE2, FWL_VKEY_ProcessKey = 0xE5, FWL_VKEY_Packet = 0xE7, FWL_VKEY_Attn = 0xF6, FWL_VKEY_Crsel = 0xF7, FWL_VKEY_Exsel = 0xF8, FWL_VKEY_Ereof = 0xF9, FWL_VKEY_Play = 0xFA, FWL_VKEY_Zoom = 0xFB, FWL_VKEY_NoName = 0xFC, FWL_VKEY_PA1 = 0xFD, FWL_VKEY_OEM_Clear = 0xFE, FWL_VKEY_Unknown = 0, } FWL_VKEYCODE; #ifdef __cplusplus } // extern "C" #endif // __cplusplus #endif // PUBLIC_FPDF_FWLEVENT_H_ ================================================ FILE: external/pdfium/macos-arm64/include/fpdf_javascript.h ================================================ // Copyright 2019 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef PUBLIC_FPDF_JAVASCRIPT_H_ #define PUBLIC_FPDF_JAVASCRIPT_H_ // NOLINTNEXTLINE(build/include) #include "fpdfview.h" #ifdef __cplusplus extern "C" { #endif // __cplusplus // Experimental API. // Get the number of JavaScript actions in |document|. // // document - handle to a document. // // Returns the number of JavaScript actions in |document| or -1 on error. FPDF_EXPORT int FPDF_CALLCONV FPDFDoc_GetJavaScriptActionCount(FPDF_DOCUMENT document); // Experimental API. // Get the JavaScript action at |index| in |document|. // // document - handle to a document. // index - the index of the requested JavaScript action. // // Returns the handle to the JavaScript action, or NULL on failure. // Caller owns the returned handle and must close it with // FPDFDoc_CloseJavaScriptAction(). FPDF_EXPORT FPDF_JAVASCRIPT_ACTION FPDF_CALLCONV FPDFDoc_GetJavaScriptAction(FPDF_DOCUMENT document, int index); // Experimental API. // Close a loaded FPDF_JAVASCRIPT_ACTION object. // javascript - Handle to a JavaScript action. FPDF_EXPORT void FPDF_CALLCONV FPDFDoc_CloseJavaScriptAction(FPDF_JAVASCRIPT_ACTION javascript); // Experimental API. // Get the name from the |javascript| handle. |buffer| is only modified if // |buflen| is longer than the length of the name. On errors, |buffer| is // unmodified and the returned length is 0. // // javascript - handle to an JavaScript action. // buffer - buffer for holding the name, encoded in UTF-16LE. // buflen - length of the buffer in bytes. // // Returns the length of the JavaScript action name in bytes. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFJavaScriptAction_GetName(FPDF_JAVASCRIPT_ACTION javascript, FPDF_WCHAR* buffer, unsigned long buflen); // Experimental API. // Get the script from the |javascript| handle. |buffer| is only modified if // |buflen| is longer than the length of the script. On errors, |buffer| is // unmodified and the returned length is 0. // // javascript - handle to an JavaScript action. // buffer - buffer for holding the name, encoded in UTF-16LE. // buflen - length of the buffer in bytes. // // Returns the length of the JavaScript action name in bytes. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFJavaScriptAction_GetScript(FPDF_JAVASCRIPT_ACTION javascript, FPDF_WCHAR* buffer, unsigned long buflen); #ifdef __cplusplus } // extern "C" #endif // __cplusplus #endif // PUBLIC_FPDF_JAVASCRIPT_H_ ================================================ FILE: external/pdfium/macos-arm64/include/fpdf_ppo.h ================================================ // Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #ifndef PUBLIC_FPDF_PPO_H_ #define PUBLIC_FPDF_PPO_H_ // NOLINTNEXTLINE(build/include) #include "fpdfview.h" #ifdef __cplusplus extern "C" { #endif // Experimental API. // Import pages to a FPDF_DOCUMENT. // // dest_doc - The destination document for the pages. // src_doc - The document to be imported. // page_indices - An array of page indices to be imported. The first page is // zero. If |page_indices| is NULL, all pages from |src_doc| // are imported. // length - The length of the |page_indices| array. // index - The page index at which to insert the first imported page // into |dest_doc|. The first page is zero. // // Returns TRUE on success. Returns FALSE if any pages in |page_indices| is // invalid. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_ImportPagesByIndex(FPDF_DOCUMENT dest_doc, FPDF_DOCUMENT src_doc, const int* page_indices, unsigned long length, int index); // Import pages to a FPDF_DOCUMENT. // // dest_doc - The destination document for the pages. // src_doc - The document to be imported. // pagerange - A page range string, Such as "1,3,5-7". The first page is one. // If |pagerange| is NULL, all pages from |src_doc| are imported. // index - The page index at which to insert the first imported page into // |dest_doc|. The first page is zero. // // Returns TRUE on success. Returns FALSE if any pages in |pagerange| is // invalid or if |pagerange| cannot be read. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_ImportPages(FPDF_DOCUMENT dest_doc, FPDF_DOCUMENT src_doc, FPDF_BYTESTRING pagerange, int index); // Experimental API. // Create a new document from |src_doc|. The pages of |src_doc| will be // combined to provide |num_pages_on_x_axis x num_pages_on_y_axis| pages per // |output_doc| page. // // src_doc - The document to be imported. // output_width - The output page width in PDF "user space" units. // output_height - The output page height in PDF "user space" units. // num_pages_on_x_axis - The number of pages on X Axis. // num_pages_on_y_axis - The number of pages on Y Axis. // // Return value: // A handle to the created document, or NULL on failure. // // Comments: // number of pages per page = num_pages_on_x_axis * num_pages_on_y_axis // FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV FPDF_ImportNPagesToOne(FPDF_DOCUMENT src_doc, float output_width, float output_height, size_t num_pages_on_x_axis, size_t num_pages_on_y_axis); // Experimental API. // Create a template to generate form xobjects from |src_doc|'s page at // |src_page_index|, for use in |dest_doc|. // // Returns a handle on success, or NULL on failure. Caller owns the newly // created object. FPDF_EXPORT FPDF_XOBJECT FPDF_CALLCONV FPDF_NewXObjectFromPage(FPDF_DOCUMENT dest_doc, FPDF_DOCUMENT src_doc, int src_page_index); // Experimental API. // Close an FPDF_XOBJECT handle created by FPDF_NewXObjectFromPage(). // FPDF_PAGEOBJECTs created from the FPDF_XOBJECT handle are not affected. FPDF_EXPORT void FPDF_CALLCONV FPDF_CloseXObject(FPDF_XOBJECT xobject); // Experimental API. // Create a new form object from an FPDF_XOBJECT object. // // Returns a new form object on success, or NULL on failure. Caller owns the // newly created object. FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV FPDF_NewFormObjectFromXObject(FPDF_XOBJECT xobject); // Copy the viewer preferences from |src_doc| into |dest_doc|. // // dest_doc - Document to write the viewer preferences into. // src_doc - Document to read the viewer preferences from. // // Returns TRUE on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_CopyViewerPreferences(FPDF_DOCUMENT dest_doc, FPDF_DOCUMENT src_doc); #ifdef __cplusplus } // extern "C" #endif // __cplusplus #endif // PUBLIC_FPDF_PPO_H_ ================================================ FILE: external/pdfium/macos-arm64/include/fpdf_progressive.h ================================================ // Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #ifndef PUBLIC_FPDF_PROGRESSIVE_H_ #define PUBLIC_FPDF_PROGRESSIVE_H_ // clang-format off // NOLINTNEXTLINE(build/include) #include "fpdfview.h" // Flags for progressive process status. #define FPDF_RENDER_READY 0 #define FPDF_RENDER_TOBECONTINUED 1 #define FPDF_RENDER_DONE 2 #define FPDF_RENDER_FAILED 3 #ifdef __cplusplus extern "C" { #endif // IFPDF_RENDERINFO interface. typedef struct _IFSDK_PAUSE { // Version number of the interface. Currently must be 1. int version; // Method: NeedToPauseNow // Check if we need to pause a progressive process now. // Interface Version: // 1 // Implementation Required: // yes // Parameters: // pThis - Pointer to the interface structure itself // Return Value: // Non-zero for pause now, 0 for continue. FPDF_BOOL (*NeedToPauseNow)(struct _IFSDK_PAUSE* pThis); // A user defined data pointer, used by user's application. Can be NULL. void* user; } IFSDK_PAUSE; // Experimental API. // Function: FPDF_RenderPageBitmapWithColorScheme_Start // Start to render page contents to a device independent bitmap // progressively with a specified color scheme for the content. // Parameters: // bitmap - Handle to the device independent bitmap (as the // output buffer). Bitmap handle can be created by // FPDFBitmap_Create function. // page - Handle to the page as returned by FPDF_LoadPage // function. // start_x - Left pixel position of the display area in the // bitmap coordinate. // start_y - Top pixel position of the display area in the // bitmap coordinate. // size_x - Horizontal size (in pixels) for displaying the // page. // size_y - Vertical size (in pixels) for displaying the page. // rotate - Page orientation: 0 (normal), 1 (rotated 90 // degrees clockwise), 2 (rotated 180 degrees), // 3 (rotated 90 degrees counter-clockwise). // flags - 0 for normal display, or combination of flags // defined in fpdfview.h. With FPDF_ANNOT flag, it // renders all annotations that does not require // user-interaction, which are all annotations except // widget and popup annotations. // color_scheme - Color scheme to be used in rendering the |page|. // If null, this function will work similar to // FPDF_RenderPageBitmap_Start(). // pause - The IFSDK_PAUSE interface. A callback mechanism // allowing the page rendering process. // Return value: // Rendering Status. See flags for progressive process status for the // details. FPDF_EXPORT int FPDF_CALLCONV FPDF_RenderPageBitmapWithColorScheme_Start(FPDF_BITMAP bitmap, FPDF_PAGE page, int start_x, int start_y, int size_x, int size_y, int rotate, int flags, const FPDF_COLORSCHEME* color_scheme, IFSDK_PAUSE* pause); // Function: FPDF_RenderPageBitmap_Start // Start to render page contents to a device independent bitmap // progressively. // Parameters: // bitmap - Handle to the device independent bitmap (as the // output buffer). Bitmap handle can be created by // FPDFBitmap_Create(). // page - Handle to the page, as returned by FPDF_LoadPage(). // start_x - Left pixel position of the display area in the // bitmap coordinates. // start_y - Top pixel position of the display area in the bitmap // coordinates. // size_x - Horizontal size (in pixels) for displaying the page. // size_y - Vertical size (in pixels) for displaying the page. // rotate - Page orientation: 0 (normal), 1 (rotated 90 degrees // clockwise), 2 (rotated 180 degrees), 3 (rotated 90 // degrees counter-clockwise). // flags - 0 for normal display, or combination of flags // defined in fpdfview.h. With FPDF_ANNOT flag, it // renders all annotations that does not require // user-interaction, which are all annotations except // widget and popup annotations. // pause - The IFSDK_PAUSE interface.A callback mechanism // allowing the page rendering process // Return value: // Rendering Status. See flags for progressive process status for the // details. FPDF_EXPORT int FPDF_CALLCONV FPDF_RenderPageBitmap_Start(FPDF_BITMAP bitmap, FPDF_PAGE page, int start_x, int start_y, int size_x, int size_y, int rotate, int flags, IFSDK_PAUSE* pause); // Function: FPDF_RenderPage_Continue // Continue rendering a PDF page. // Parameters: // page - Handle to the page, as returned by FPDF_LoadPage(). // pause - The IFSDK_PAUSE interface (a callback mechanism // allowing the page rendering process to be paused // before it's finished). This can be NULL if you // don't want to pause. // Return value: // The rendering status. See flags for progressive process status for // the details. FPDF_EXPORT int FPDF_CALLCONV FPDF_RenderPage_Continue(FPDF_PAGE page, IFSDK_PAUSE* pause); // Function: FPDF_RenderPage_Close // Release the resource allocate during page rendering. Need to be // called after finishing rendering or // cancel the rendering. // Parameters: // page - Handle to the page, as returned by FPDF_LoadPage(). // Return value: // None. FPDF_EXPORT void FPDF_CALLCONV FPDF_RenderPage_Close(FPDF_PAGE page); #ifdef __cplusplus } #endif #endif // PUBLIC_FPDF_PROGRESSIVE_H_ ================================================ FILE: external/pdfium/macos-arm64/include/fpdf_save.h ================================================ // Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #ifndef PUBLIC_FPDF_SAVE_H_ #define PUBLIC_FPDF_SAVE_H_ // clang-format off // NOLINTNEXTLINE(build/include) #include "fpdfview.h" #ifdef __cplusplus extern "C" { #endif // Structure for custom file write typedef struct FPDF_FILEWRITE_ { // // Version number of the interface. Currently must be 1. // int version; // Method: WriteBlock // Output a block of data in your custom way. // Interface Version: // 1 // Implementation Required: // Yes // Comments: // Called by function FPDF_SaveDocument // Parameters: // self - Pointer to the structure itself // data - Pointer to a buffer to output // size - The size of the buffer. // Return value: // Should be non-zero if successful, zero for error. int (*WriteBlock)(struct FPDF_FILEWRITE_* self, const void* data, unsigned long size); } FPDF_FILEWRITE; // Flags for FPDF_SaveAsCopy(). // FPDF_INCREMENTAL and FPDF_NO_INCREMENTAL cannot be used together. #define FPDF_INCREMENTAL (1 << 0) #define FPDF_NO_INCREMENTAL (1 << 1) // Deprecated. Use FPDF_REMOVE_SECURITY instead. // TODO(crbug.com/42270430): Remove FPDF_REMOVE_SECURITY_DEPRECATED. #define FPDF_REMOVE_SECURITY_DEPRECATED 3 #define FPDF_REMOVE_SECURITY (1 << 2) // Experimental. Subsets any embedded font files for new text objects added to // the document. #define FPDF_SUBSET_NEW_FONTS (1 << 3) // Function: FPDF_SaveAsCopy // Saves the copy of specified document in custom way. // Parameters: // document - Handle to document, as returned by // FPDF_LoadDocument() or FPDF_CreateNewDocument(). // file_write - A pointer to a custom file write structure. // flags - Flags above that affect how the PDF gets saved. // Pass in 0 when there are no flags. // Return value: // TRUE for succeed, FALSE for failed. // FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_SaveAsCopy(FPDF_DOCUMENT document, FPDF_FILEWRITE* file_write, FPDF_DWORD flags); // Function: FPDF_SaveWithVersion // Same as FPDF_SaveAsCopy(), except the file version of the // saved document can be specified by the caller. // Parameters: // document - Handle to document. // file_write - A pointer to a custom file write structure. // flags - The creating flags. // file_version - The PDF file version. File version: 14 for 1.4, // 15 for 1.5, ... // Return value: // TRUE if succeed, FALSE if failed. // FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_SaveWithVersion(FPDF_DOCUMENT document, FPDF_FILEWRITE* file_write, FPDF_DWORD flags, int file_version); #ifdef __cplusplus } #endif #endif // PUBLIC_FPDF_SAVE_H_ ================================================ FILE: external/pdfium/macos-arm64/include/fpdf_searchex.h ================================================ // Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #ifndef PUBLIC_FPDF_SEARCHEX_H_ #define PUBLIC_FPDF_SEARCHEX_H_ // NOLINTNEXTLINE(build/include) #include "fpdfview.h" #ifdef __cplusplus extern "C" { #endif // __cplusplus // Get the character index in |text_page| internal character list. // // text_page - a text page information structure. // nTextIndex - index of the text returned from FPDFText_GetText(). // // Returns the index of the character in internal character list. -1 for error. FPDF_EXPORT int FPDF_CALLCONV FPDFText_GetCharIndexFromTextIndex(FPDF_TEXTPAGE text_page, int nTextIndex); // Get the text index in |text_page| internal character list. // // text_page - a text page information structure. // nCharIndex - index of the character in internal character list. // // Returns the index of the text returned from FPDFText_GetText(). -1 for error. FPDF_EXPORT int FPDF_CALLCONV FPDFText_GetTextIndexFromCharIndex(FPDF_TEXTPAGE text_page, int nCharIndex); #ifdef __cplusplus } // extern "C" #endif // __cplusplus #endif // PUBLIC_FPDF_SEARCHEX_H_ ================================================ FILE: external/pdfium/macos-arm64/include/fpdf_signature.h ================================================ // Copyright 2020 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef PUBLIC_FPDF_SIGNATURE_H_ #define PUBLIC_FPDF_SIGNATURE_H_ // NOLINTNEXTLINE(build/include) #include "fpdfview.h" #ifdef __cplusplus extern "C" { #endif // __cplusplus // Experimental API. // Function: FPDF_GetSignatureCount // Get total number of signatures in the document. // Parameters: // document - Handle to document. Returned by FPDF_LoadDocument(). // Return value: // Total number of signatures in the document on success, -1 on error. FPDF_EXPORT int FPDF_CALLCONV FPDF_GetSignatureCount(FPDF_DOCUMENT document); // Experimental API. // Function: FPDF_GetSignatureObject // Get the Nth signature of the document. // Parameters: // document - Handle to document. Returned by FPDF_LoadDocument(). // index - Index into the array of signatures of the document. // Return value: // Returns the handle to the signature, or NULL on failure. The caller // does not take ownership of the returned FPDF_SIGNATURE. Instead, it // remains valid until FPDF_CloseDocument() is called for the document. FPDF_EXPORT FPDF_SIGNATURE FPDF_CALLCONV FPDF_GetSignatureObject(FPDF_DOCUMENT document, int index); // Experimental API. // Function: FPDFSignatureObj_GetContents // Get the contents of a signature object. // Parameters: // signature - Handle to the signature object. Returned by // FPDF_GetSignatureObject(). // buffer - The address of a buffer that receives the contents. // length - The size, in bytes, of |buffer|. // Return value: // Returns the number of bytes in the contents on success, 0 on error. // // For public-key signatures, |buffer| is either a DER-encoded PKCS#1 binary or // a DER-encoded PKCS#7 binary. If |length| is less than the returned length, or // |buffer| is NULL, |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFSignatureObj_GetContents(FPDF_SIGNATURE signature, void* buffer, unsigned long length); // Experimental API. // Function: FPDFSignatureObj_GetByteRange // Get the byte range of a signature object. // Parameters: // signature - Handle to the signature object. Returned by // FPDF_GetSignatureObject(). // buffer - The address of a buffer that receives the // byte range. // length - The size, in ints, of |buffer|. // Return value: // Returns the number of ints in the byte range on // success, 0 on error. // // |buffer| is an array of pairs of integers (starting byte offset, // length in bytes) that describes the exact byte range for the digest // calculation. If |length| is less than the returned length, or // |buffer| is NULL, |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFSignatureObj_GetByteRange(FPDF_SIGNATURE signature, int* buffer, unsigned long length); // Experimental API. // Function: FPDFSignatureObj_GetSubFilter // Get the encoding of the value of a signature object. // Parameters: // signature - Handle to the signature object. Returned by // FPDF_GetSignatureObject(). // buffer - The address of a buffer that receives the encoding. // length - The size, in bytes, of |buffer|. // Return value: // Returns the number of bytes in the encoding name (including the // trailing NUL character) on success, 0 on error. // // The |buffer| is always encoded in 7-bit ASCII. If |length| is less than the // returned length, or |buffer| is NULL, |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFSignatureObj_GetSubFilter(FPDF_SIGNATURE signature, char* buffer, unsigned long length); // Experimental API. // Function: FPDFSignatureObj_GetReason // Get the reason (comment) of the signature object. // Parameters: // signature - Handle to the signature object. Returned by // FPDF_GetSignatureObject(). // buffer - The address of a buffer that receives the reason. // length - The size, in bytes, of |buffer|. // Return value: // Returns the number of bytes in the reason on success, 0 on error. // // Regardless of the platform, the |buffer| is always in UTF-16LE encoding. The // string is terminated by a UTF16 NUL character. If |length| is less than the // returned length, or |buffer| is NULL, |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFSignatureObj_GetReason(FPDF_SIGNATURE signature, void* buffer, unsigned long length); // Experimental API. // Function: FPDFSignatureObj_GetTime // Get the time of signing of a signature object. // Parameters: // signature - Handle to the signature object. Returned by // FPDF_GetSignatureObject(). // buffer - The address of a buffer that receives the time. // length - The size, in bytes, of |buffer|. // Return value: // Returns the number of bytes in the encoding name (including the // trailing NUL character) on success, 0 on error. // // The |buffer| is always encoded in 7-bit ASCII. If |length| is less than the // returned length, or |buffer| is NULL, |buffer| will not be modified. // // The format of time is expected to be D:YYYYMMDDHHMMSS+XX'YY', i.e. it's // percision is seconds, with timezone information. This value should be used // only when the time of signing is not available in the (PKCS#7 binary) // signature. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFSignatureObj_GetTime(FPDF_SIGNATURE signature, char* buffer, unsigned long length); // Experimental API. // Function: FPDFSignatureObj_GetDocMDPPermission // Get the DocMDP permission of a signature object. // Parameters: // signature - Handle to the signature object. Returned by // FPDF_GetSignatureObject(). // Return value: // Returns the permission (1, 2 or 3) on success, 0 on error. FPDF_EXPORT unsigned int FPDF_CALLCONV FPDFSignatureObj_GetDocMDPPermission(FPDF_SIGNATURE signature); #ifdef __cplusplus } // extern "C" #endif // __cplusplus #endif // PUBLIC_FPDF_SIGNATURE_H_ ================================================ FILE: external/pdfium/macos-arm64/include/fpdf_structtree.h ================================================ // Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #ifndef PUBLIC_FPDF_STRUCTTREE_H_ #define PUBLIC_FPDF_STRUCTTREE_H_ // clang-format off // NOLINTNEXTLINE(build/include) #include "fpdfview.h" #ifdef __cplusplus extern "C" { #endif // Function: FPDF_StructTree_GetForPage // Get the structure tree for a page. // Parameters: // page - Handle to the page, as returned by FPDF_LoadPage(). // Return value: // A handle to the structure tree or NULL on error. The caller owns the // returned handle and must use FPDF_StructTree_Close() to release it. // The handle should be released before |page| gets released. FPDF_EXPORT FPDF_STRUCTTREE FPDF_CALLCONV FPDF_StructTree_GetForPage(FPDF_PAGE page); // Function: FPDF_StructTree_Close // Release a resource allocated by FPDF_StructTree_GetForPage(). // Parameters: // struct_tree - Handle to the structure tree, as returned by // FPDF_StructTree_LoadPage(). // Return value: // None. FPDF_EXPORT void FPDF_CALLCONV FPDF_StructTree_Close(FPDF_STRUCTTREE struct_tree); // Function: FPDF_StructTree_CountChildren // Count the number of children for the structure tree. // Parameters: // struct_tree - Handle to the structure tree, as returned by // FPDF_StructTree_LoadPage(). // Return value: // The number of children, or -1 on error. FPDF_EXPORT int FPDF_CALLCONV FPDF_StructTree_CountChildren(FPDF_STRUCTTREE struct_tree); // Function: FPDF_StructTree_GetChildAtIndex // Get a child in the structure tree. // Parameters: // struct_tree - Handle to the structure tree, as returned by // FPDF_StructTree_LoadPage(). // index - The index for the child, 0-based. // Return value: // The child at the n-th index or NULL on error. The caller does not // own the handle. The handle remains valid as long as |struct_tree| // remains valid. // Comments: // The |index| must be less than the FPDF_StructTree_CountChildren() // return value. FPDF_EXPORT FPDF_STRUCTELEMENT FPDF_CALLCONV FPDF_StructTree_GetChildAtIndex(FPDF_STRUCTTREE struct_tree, int index); // Function: FPDF_StructElement_GetAltText // Get the alt text for a given element. // Parameters: // struct_element - Handle to the struct element. // buffer - A buffer for output the alt text. May be NULL. // buflen - The length of the buffer, in bytes. May be 0. // Return value: // The number of bytes in the alt text, including the terminating NUL // character. The number of bytes is returned regardless of the // |buffer| and |buflen| parameters. // Comments: // Regardless of the platform, the |buffer| is always in UTF-16LE // encoding. The string is terminated by a UTF16 NUL character. If // |buflen| is less than the required length, or |buffer| is NULL, // |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_StructElement_GetAltText(FPDF_STRUCTELEMENT struct_element, void* buffer, unsigned long buflen); // Experimental API. // Function: FPDF_StructElement_GetActualText // Get the actual text for a given element. // Parameters: // struct_element - Handle to the struct element. // buffer - A buffer for output the actual text. May be NULL. // buflen - The length of the buffer, in bytes. May be 0. // Return value: // The number of bytes in the actual text, including the terminating // NUL character. The number of bytes is returned regardless of the // |buffer| and |buflen| parameters. // Comments: // Regardless of the platform, the |buffer| is always in UTF-16LE // encoding. The string is terminated by a UTF16 NUL character. If // |buflen| is less than the required length, or |buffer| is NULL, // |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_StructElement_GetActualText(FPDF_STRUCTELEMENT struct_element, void* buffer, unsigned long buflen); // Experimental API. // Function: FPDF_StructElement_GetExpansion // Get the expansion of an abbreviation or acronym for a given element. // Parameters: // struct_element - Handle to the struct element. // buffer - A buffer for output the expansion text. May be // NULL. // buflen - The length of the buffer, in bytes. May be 0. // Return value: // The number of bytes in the expansion text, including the terminating // NUL character. The number of bytes is returned regardless of the // |buffer| and |buflen| parameters. // Comments: // Regardless of the platform, the |buffer| is always in UTF-16LE // encoding. The string is terminated by a UTF16 NUL character. If // |buflen| is less than the required length, or |buffer| is NULL, // |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_StructElement_GetExpansion(FPDF_STRUCTELEMENT struct_element, void* buffer, unsigned long buflen); // Function: FPDF_StructElement_GetID // Get the ID for a given element. // Parameters: // struct_element - Handle to the struct element. // buffer - A buffer for output the ID string. May be NULL. // buflen - The length of the buffer, in bytes. May be 0. // Return value: // The number of bytes in the ID string, including the terminating NUL // character. The number of bytes is returned regardless of the // |buffer| and |buflen| parameters. // Comments: // Regardless of the platform, the |buffer| is always in UTF-16LE // encoding. The string is terminated by a UTF16 NUL character. If // |buflen| is less than the required length, or |buffer| is NULL, // |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_StructElement_GetID(FPDF_STRUCTELEMENT struct_element, void* buffer, unsigned long buflen); // Experimental API. // Function: FPDF_StructElement_GetLang // Get the case-insensitive IETF BCP 47 language code for an element. // Parameters: // struct_element - Handle to the struct element. // buffer - A buffer for output the lang string. May be NULL. // buflen - The length of the buffer, in bytes. May be 0. // Return value: // The number of bytes in the ID string, including the terminating NUL // character. The number of bytes is returned regardless of the // |buffer| and |buflen| parameters. // Comments: // Regardless of the platform, the |buffer| is always in UTF-16LE // encoding. The string is terminated by a UTF16 NUL character. If // |buflen| is less than the required length, or |buffer| is NULL, // |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_StructElement_GetLang(FPDF_STRUCTELEMENT struct_element, void* buffer, unsigned long buflen); // Experimental API. // Function: FPDF_StructElement_GetStringAttribute // Get a struct element attribute of type "name" or "string". // Parameters: // struct_element - Handle to the struct element. // attr_name - The name of the attribute to retrieve. // buffer - A buffer for output. May be NULL. // buflen - The length of the buffer, in bytes. May be 0. // Return value: // The number of bytes in the attribute value, including the // terminating NUL character. The number of bytes is returned // regardless of the |buffer| and |buflen| parameters. // Comments: // Regardless of the platform, the |buffer| is always in UTF-16LE // encoding. The string is terminated by a UTF16 NUL character. If // |buflen| is less than the required length, or |buffer| is NULL, // |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_StructElement_GetStringAttribute(FPDF_STRUCTELEMENT struct_element, FPDF_BYTESTRING attr_name, void* buffer, unsigned long buflen); // Function: FPDF_StructElement_GetMarkedContentID // Get the marked content ID for a given element. // Parameters: // struct_element - Handle to the struct element. // Return value: // The marked content ID of the element. If no ID exists, returns // -1. // Comments: // FPDF_StructElement_GetMarkedContentIdAtIndex() may be able to // extract more marked content IDs out of |struct_element|. This API // may be deprecated in the future. FPDF_EXPORT int FPDF_CALLCONV FPDF_StructElement_GetMarkedContentID(FPDF_STRUCTELEMENT struct_element); // Function: FPDF_StructElement_GetType // Get the type (/S) for a given element. // Parameters: // struct_element - Handle to the struct element. // buffer - A buffer for output. May be NULL. // buflen - The length of the buffer, in bytes. May be 0. // Return value: // The number of bytes in the type, including the terminating NUL // character. The number of bytes is returned regardless of the // |buffer| and |buflen| parameters. // Comments: // Regardless of the platform, the |buffer| is always in UTF-16LE // encoding. The string is terminated by a UTF16 NUL character. If // |buflen| is less than the required length, or |buffer| is NULL, // |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_StructElement_GetType(FPDF_STRUCTELEMENT struct_element, void* buffer, unsigned long buflen); // Experimental API. // Function: FPDF_StructElement_GetObjType // Get the object type (/Type) for a given element. // Parameters: // struct_element - Handle to the struct element. // buffer - A buffer for output. May be NULL. // buflen - The length of the buffer, in bytes. May be 0. // Return value: // The number of bytes in the object type, including the terminating // NUL character. The number of bytes is returned regardless of the // |buffer| and |buflen| parameters. // Comments: // Regardless of the platform, the |buffer| is always in UTF-16LE // encoding. The string is terminated by a UTF16 NUL character. If // |buflen| is less than the required length, or |buffer| is NULL, // |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_StructElement_GetObjType(FPDF_STRUCTELEMENT struct_element, void* buffer, unsigned long buflen); // Function: FPDF_StructElement_GetTitle // Get the title (/T) for a given element. // Parameters: // struct_element - Handle to the struct element. // buffer - A buffer for output. May be NULL. // buflen - The length of the buffer, in bytes. May be 0. // Return value: // The number of bytes in the title, including the terminating NUL // character. The number of bytes is returned regardless of the // |buffer| and |buflen| parameters. // Comments: // Regardless of the platform, the |buffer| is always in UTF-16LE // encoding. The string is terminated by a UTF16 NUL character. If // |buflen| is less than the required length, or |buffer| is NULL, // |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_StructElement_GetTitle(FPDF_STRUCTELEMENT struct_element, void* buffer, unsigned long buflen); // Function: FPDF_StructElement_CountChildren // Count the number of children for the structure element. // Parameters: // struct_element - Handle to the struct element. // Return value: // The number of children, or -1 on error. FPDF_EXPORT int FPDF_CALLCONV FPDF_StructElement_CountChildren(FPDF_STRUCTELEMENT struct_element); // Function: FPDF_StructElement_GetChildAtIndex // Get a child in the structure element. // Parameters: // struct_element - Handle to the struct element. // index - The index for the child, 0-based. // Return value: // The child at the n-th index or NULL on error. // Comments: // If the child exists but is not an element, then this function will // return NULL. This will also return NULL for out of bounds indices. // The |index| must be less than the FPDF_StructElement_CountChildren() // return value. FPDF_EXPORT FPDF_STRUCTELEMENT FPDF_CALLCONV FPDF_StructElement_GetChildAtIndex(FPDF_STRUCTELEMENT struct_element, int index); // Experimental API. // Function: FPDF_StructElement_GetChildMarkedContentID // Get the child's content id // Parameters: // struct_element - Handle to the struct element. // index - The index for the child, 0-based. // Return value: // The marked content ID of the child. If no ID exists, returns -1. // Comments: // If the child exists but is not a stream or object, then this // function will return -1. This will also return -1 for out of bounds // indices. Compared to FPDF_StructElement_GetMarkedContentIdAtIndex, // it is scoped to the current page. // The |index| must be less than the FPDF_StructElement_CountChildren() // return value. FPDF_EXPORT int FPDF_CALLCONV FPDF_StructElement_GetChildMarkedContentID(FPDF_STRUCTELEMENT struct_element, int index); // Experimental API. // Function: FPDF_StructElement_GetParent // Get the parent of the structure element. // Parameters: // struct_element - Handle to the struct element. // Return value: // The parent structure element or NULL on error. // Comments: // If structure element is StructTreeRoot, then this function will // return NULL. FPDF_EXPORT FPDF_STRUCTELEMENT FPDF_CALLCONV FPDF_StructElement_GetParent(FPDF_STRUCTELEMENT struct_element); // Function: FPDF_StructElement_GetAttributeCount // Count the number of attributes for the structure element. // Parameters: // struct_element - Handle to the struct element. // Return value: // The number of attributes, or -1 on error. FPDF_EXPORT int FPDF_CALLCONV FPDF_StructElement_GetAttributeCount(FPDF_STRUCTELEMENT struct_element); // Experimental API. // Function: FPDF_StructElement_GetAttributeAtIndex // Get an attribute object in the structure element. // Parameters: // struct_element - Handle to the struct element. // index - The index for the attribute object, 0-based. // Return value: // The attribute object at the n-th index or NULL on error. // Comments: // If the attribute object exists but is not a dict, then this // function will return NULL. This will also return NULL for out of // bounds indices. The caller does not own the handle. The handle // remains valid as long as |struct_element| remains valid. // The |index| must be less than the // FPDF_StructElement_GetAttributeCount() return value. FPDF_EXPORT FPDF_STRUCTELEMENT_ATTR FPDF_CALLCONV FPDF_StructElement_GetAttributeAtIndex(FPDF_STRUCTELEMENT struct_element, int index); // Experimental API. // Function: FPDF_StructElement_Attr_GetCount // Count the number of attributes in a structure element attribute map. // Parameters: // struct_attribute - Handle to the struct element attribute. // Return value: // The number of attributes, or -1 on error. FPDF_EXPORT int FPDF_CALLCONV FPDF_StructElement_Attr_GetCount(FPDF_STRUCTELEMENT_ATTR struct_attribute); // Experimental API. // Function: FPDF_StructElement_Attr_GetName // Get the name of an attribute in a structure element attribute map. // Parameters: // struct_attribute - Handle to the struct element attribute. // index - The index of attribute in the map. // buffer - A buffer for output. May be NULL. This is only // modified if |buflen| is longer than the length // of the key. Optional, pass null to just // retrieve the size of the buffer needed. // buflen - The length of the buffer. // out_buflen - A pointer to variable that will receive the // minimum buffer size to contain the key. Not // filled if FALSE is returned. // Return value: // TRUE if the operation was successful, FALSE otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_StructElement_Attr_GetName(FPDF_STRUCTELEMENT_ATTR struct_attribute, int index, void* buffer, unsigned long buflen, unsigned long* out_buflen); // Experimental API. // Function: FPDF_StructElement_Attr_GetValue // Get a handle to a value for an attribute in a structure element // attribute map. // Parameters: // struct_attribute - Handle to the struct element attribute. // name - The attribute name. // Return value: // Returns a handle to the value associated with the input, if any. // Returns NULL on failure. The caller does not own the handle. // The handle remains valid as long as |struct_attribute| remains // valid. FPDF_EXPORT FPDF_STRUCTELEMENT_ATTR_VALUE FPDF_CALLCONV FPDF_StructElement_Attr_GetValue(FPDF_STRUCTELEMENT_ATTR struct_attribute, FPDF_BYTESTRING name); // Experimental API. // Function: FPDF_StructElement_Attr_GetType // Get the type of an attribute in a structure element attribute map. // Parameters: // value - Handle to the value. // Return value: // Returns the type of the value, or FPDF_OBJECT_UNKNOWN in case of // failure. Note that this will never return FPDF_OBJECT_REFERENCE, as // references are always dereferenced. FPDF_EXPORT FPDF_OBJECT_TYPE FPDF_CALLCONV FPDF_StructElement_Attr_GetType(FPDF_STRUCTELEMENT_ATTR_VALUE value); // Experimental API. // Function: FPDF_StructElement_Attr_GetBooleanValue // Get the value of a boolean attribute in an attribute map as // FPDF_BOOL. FPDF_StructElement_Attr_GetType() should have returned // FPDF_OBJECT_BOOLEAN for this property. // Parameters: // value - Handle to the value. // out_value - A pointer to variable that will receive the value. Not // filled if false is returned. // Return value: // Returns TRUE if the attribute maps to a boolean value, FALSE // otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_StructElement_Attr_GetBooleanValue(FPDF_STRUCTELEMENT_ATTR_VALUE value, FPDF_BOOL* out_value); // Experimental API. // Function: FPDF_StructElement_Attr_GetNumberValue // Get the value of a number attribute in an attribute map as float. // FPDF_StructElement_Attr_GetType() should have returned // FPDF_OBJECT_NUMBER for this property. // Parameters: // value - Handle to the value. // out_value - A pointer to variable that will receive the value. Not // filled if false is returned. // Return value: // Returns TRUE if the attribute maps to a number value, FALSE // otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_StructElement_Attr_GetNumberValue(FPDF_STRUCTELEMENT_ATTR_VALUE value, float* out_value); // Experimental API. // Function: FPDF_StructElement_Attr_GetStringValue // Get the value of a string attribute in an attribute map as string. // FPDF_StructElement_Attr_GetType() should have returned // FPDF_OBJECT_STRING or FPDF_OBJECT_NAME for this property. // Parameters: // value - Handle to the value. // buffer - A buffer for holding the returned key in UTF-16LE. // This is only modified if |buflen| is longer than the // length of the key. Optional, pass null to just // retrieve the size of the buffer needed. // buflen - The length of the buffer. // out_buflen - A pointer to variable that will receive the minimum // buffer size to contain the key. Not filled if FALSE is // returned. // Return value: // Returns TRUE if the attribute maps to a string value, FALSE // otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_StructElement_Attr_GetStringValue(FPDF_STRUCTELEMENT_ATTR_VALUE value, void* buffer, unsigned long buflen, unsigned long* out_buflen); // Experimental API. // Function: FPDF_StructElement_Attr_GetBlobValue // Get the value of a blob attribute in an attribute map as string. // Parameters: // value - Handle to the value. // buffer - A buffer for holding the returned value. This is only // modified if |buflen| is at least as long as the length // of the value. Optional, pass null to just retrieve the // size of the buffer needed. // buflen - The length of the buffer. // out_buflen - A pointer to variable that will receive the minimum // buffer size to contain the key. Not filled if FALSE is // returned. // Return value: // Returns TRUE if the attribute maps to a string value, FALSE // otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_StructElement_Attr_GetBlobValue(FPDF_STRUCTELEMENT_ATTR_VALUE value, void* buffer, unsigned long buflen, unsigned long* out_buflen); // Experimental API. // Function: FPDF_StructElement_Attr_CountChildren // Count the number of children values in an attribute. // Parameters: // value - Handle to the value. // Return value: // The number of children, or -1 on error. FPDF_EXPORT int FPDF_CALLCONV FPDF_StructElement_Attr_CountChildren(FPDF_STRUCTELEMENT_ATTR_VALUE value); // Experimental API. // Function: FPDF_StructElement_Attr_GetChildAtIndex // Get a child from an attribute. // Parameters: // value - Handle to the value. // index - The index for the child, 0-based. // Return value: // The child at the n-th index or NULL on error. // Comments: // The |index| must be less than the // FPDF_StructElement_Attr_CountChildren() return value. FPDF_EXPORT FPDF_STRUCTELEMENT_ATTR_VALUE FPDF_CALLCONV FPDF_StructElement_Attr_GetChildAtIndex(FPDF_STRUCTELEMENT_ATTR_VALUE value, int index); // Experimental API. // Function: FPDF_StructElement_GetMarkedContentIdCount // Get the count of marked content ids for a given element. // Parameters: // struct_element - Handle to the struct element. // Return value: // The count of marked content ids or -1 if none exists. FPDF_EXPORT int FPDF_CALLCONV FPDF_StructElement_GetMarkedContentIdCount(FPDF_STRUCTELEMENT struct_element); // Experimental API. // Function: FPDF_StructElement_GetMarkedContentIdAtIndex // Get the marked content id at a given index for a given element. // Parameters: // struct_element - Handle to the struct element. // index - The index of the marked content id, 0-based. // Return value: // The marked content ID of the element. If no ID exists, returns // -1. // Comments: // The |index| must be less than the // FPDF_StructElement_GetMarkedContentIdCount() return value. // This will likely supersede FPDF_StructElement_GetMarkedContentID(). FPDF_EXPORT int FPDF_CALLCONV FPDF_StructElement_GetMarkedContentIdAtIndex(FPDF_STRUCTELEMENT struct_element, int index); #ifdef __cplusplus } // extern "C" #endif #endif // PUBLIC_FPDF_STRUCTTREE_H_ ================================================ FILE: external/pdfium/macos-arm64/include/fpdf_sysfontinfo.h ================================================ // Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #ifndef PUBLIC_FPDF_SYSFONTINFO_H_ #define PUBLIC_FPDF_SYSFONTINFO_H_ #include // clang-format off // NOLINTNEXTLINE(build/include) #include "fpdfview.h" // Character sets for the font #define FXFONT_ANSI_CHARSET 0 #define FXFONT_DEFAULT_CHARSET 1 #define FXFONT_SYMBOL_CHARSET 2 #define FXFONT_SHIFTJIS_CHARSET 128 #define FXFONT_HANGEUL_CHARSET 129 #define FXFONT_GB2312_CHARSET 134 #define FXFONT_CHINESEBIG5_CHARSET 136 #define FXFONT_GREEK_CHARSET 161 #define FXFONT_VIETNAMESE_CHARSET 163 #define FXFONT_HEBREW_CHARSET 177 #define FXFONT_ARABIC_CHARSET 178 #define FXFONT_CYRILLIC_CHARSET 204 #define FXFONT_THAI_CHARSET 222 #define FXFONT_EASTERNEUROPEAN_CHARSET 238 // Font pitch and family flags #define FXFONT_FF_FIXEDPITCH (1 << 0) #define FXFONT_FF_ROMAN (1 << 4) #define FXFONT_FF_SCRIPT (4 << 4) // Typical weight values #define FXFONT_FW_NORMAL 400 #define FXFONT_FW_BOLD 700 // Exported Functions #ifdef __cplusplus extern "C" { #endif // Interface: FPDF_SYSFONTINFO // Interface for getting system font information and font mapping typedef struct _FPDF_SYSFONTINFO { // Version number of the interface. Currently must be 1 or 2. // Version 1: Traditional behavior - calls EnumFonts during initialization. // Version 2: Per-request behavior - skips EnumFonts, relies on MapFont. // Experimental: Subject to change based on feedback. int version; // Method: Release // Give implementation a chance to release any data after the // interface is no longer used. // Interface Version: // 1 and 2 // Implementation Required: // No // Parameters: // pThis - Pointer to the interface structure itself // Return Value: // None // Comments: // Called by PDFium during the final cleanup process. void (*Release)(struct _FPDF_SYSFONTINFO* pThis); // Method: EnumFonts // Enumerate all fonts installed on the system // Interface Version: // 1 // Implementation Required: // No // Parameters: // pThis - Pointer to the interface structure itself // pMapper - An opaque pointer to internal font mapper, used // when calling FPDF_AddInstalledFont(). // Return Value: // None // Comments: // Implementations should call FPDF_AddInstalledFont() function for // each font found. Only TrueType/OpenType and Type1 fonts are // accepted by PDFium. // NOTE: This method will not be called when version is set to 2. // Version 2 relies entirely on MapFont() for per-request matching. void (*EnumFonts)(struct _FPDF_SYSFONTINFO* pThis, void* pMapper); // Method: MapFont // Use the system font mapper to get a font handle from requested // parameters. // Interface Version: // 1 and 2 // Implementation Required: // Required if GetFont method is not implemented. // Parameters: // pThis - Pointer to the interface structure itself // weight - Weight of the requested font. 400 is normal and // 700 is bold. // bItalic - Italic option of the requested font, TRUE or // FALSE. // charset - Character set identifier for the requested font. // See above defined constants. // pitch_family - A combination of flags. See above defined // constants. // face - Typeface name. Currently use system local encoding // only. // bExact - Obsolete: this parameter is now ignored. // Return Value: // An opaque pointer for font handle, or NULL if system mapping is // not supported. // Comments: // If the system supports native font mapper (like Windows), // implementation can implement this method to get a font handle. // Otherwise, PDFium will do the mapping and then call GetFont // method. Only TrueType/OpenType and Type1 fonts are accepted // by PDFium. void* (*MapFont)(struct _FPDF_SYSFONTINFO* pThis, int weight, FPDF_BOOL bItalic, int charset, int pitch_family, const char* face, FPDF_BOOL* bExact); // Method: GetFont // Get a handle to a particular font by its internal ID // Interface Version: // 1 and 2 // Implementation Required: // Required if MapFont method is not implemented. // Return Value: // An opaque pointer for font handle. // Parameters: // pThis - Pointer to the interface structure itself // face - Typeface name in system local encoding. // Comments: // If the system mapping not supported, PDFium will do the font // mapping and use this method to get a font handle. void* (*GetFont)(struct _FPDF_SYSFONTINFO* pThis, const char* face); // Method: GetFontData // Get font data from a font // Interface Version: // 1 and 2 // Implementation Required: // Yes // Parameters: // pThis - Pointer to the interface structure itself // hFont - Font handle returned by MapFont or GetFont method // table - TrueType/OpenType table identifier (refer to // TrueType specification), or 0 for the whole file. // buffer - The buffer receiving the font data. Can be NULL if // not provided. // buf_size - Buffer size, can be zero if not provided. // Return Value: // Number of bytes needed, if buffer not provided or not large // enough, or number of bytes written into buffer otherwise. // Comments: // Can read either the full font file, or a particular // TrueType/OpenType table. unsigned long (*GetFontData)(struct _FPDF_SYSFONTINFO* pThis, void* hFont, unsigned int table, unsigned char* buffer, unsigned long buf_size); // Method: GetFaceName // Get face name from a font handle // Interface Version: // 1 and 2 // Implementation Required: // No // Parameters: // pThis - Pointer to the interface structure itself // hFont - Font handle returned by MapFont or GetFont method // buffer - The buffer receiving the face name. Can be NULL if // not provided // buf_size - Buffer size, can be zero if not provided // Return Value: // Number of bytes needed, if buffer not provided or not large // enough, or number of bytes written into buffer otherwise. unsigned long (*GetFaceName)(struct _FPDF_SYSFONTINFO* pThis, void* hFont, char* buffer, unsigned long buf_size); // Method: GetFontCharset // Get character set information for a font handle // Interface Version: // 1 and 2 // Implementation Required: // No // Parameters: // pThis - Pointer to the interface structure itself // hFont - Font handle returned by MapFont or GetFont method // Return Value: // Character set identifier. See defined constants above. int (*GetFontCharset)(struct _FPDF_SYSFONTINFO* pThis, void* hFont); // Method: DeleteFont // Delete a font handle // Interface Version: // 1 and 2 // Implementation Required: // Yes // Parameters: // pThis - Pointer to the interface structure itself // hFont - Font handle returned by MapFont or GetFont method // Return Value: // None void (*DeleteFont)(struct _FPDF_SYSFONTINFO* pThis, void* hFont); } FPDF_SYSFONTINFO; // Struct: FPDF_CharsetFontMap // Provides the name of a font to use for a given charset value. typedef struct FPDF_CharsetFontMap_ { int charset; // Character Set Enum value, see FXFONT_*_CHARSET above. const char* fontname; // Name of default font to use with that charset. } FPDF_CharsetFontMap; // Function: FPDF_GetDefaultTTFMap // Returns a pointer to the default character set to TT Font name map. The // map is an array of FPDF_CharsetFontMap structs, with its end indicated // by a { -1, NULL } entry. // Parameters: // None. // Return Value: // Pointer to the Charset Font Map. // Note: // Once FPDF_GetDefaultTTFMapCount() and FPDF_GetDefaultTTFMapEntry() are no // longer experimental, this API will be marked as deprecated. // See https://crbug.com/348468114 FPDF_EXPORT const FPDF_CharsetFontMap* FPDF_CALLCONV FPDF_GetDefaultTTFMap(); // Experimental API. // // Function: FPDF_GetDefaultTTFMapCount // Returns the number of entries in the default character set to TT Font name // map. // Parameters: // None. // Return Value: // The number of entries in the map. FPDF_EXPORT size_t FPDF_CALLCONV FPDF_GetDefaultTTFMapCount(); // Experimental API. // // Function: FPDF_GetDefaultTTFMapEntry // Returns an entry in the default character set to TT Font name map. // Parameters: // index - The index to the entry in the map to retrieve. // Return Value: // A pointer to the entry, if it is in the map, or NULL if the index is out // of bounds. FPDF_EXPORT const FPDF_CharsetFontMap* FPDF_CALLCONV FPDF_GetDefaultTTFMapEntry(size_t index); // Function: FPDF_AddInstalledFont // Add a system font to the list in PDFium. // Comments: // This function is only called during the system font list building // process. // Parameters: // mapper - Opaque pointer to Foxit font mapper // face - The font face name // charset - Font character set. See above defined constants. // Return Value: // None. FPDF_EXPORT void FPDF_CALLCONV FPDF_AddInstalledFont(void* mapper, const char* face, int charset); // Function: FPDF_SetSystemFontInfo // Set the system font info interface into PDFium // Parameters: // font_info - Pointer to a FPDF_SYSFONTINFO structure // Return Value: // None // Comments: // Platform support implementation should implement required methods of // FFDF_SYSFONTINFO interface, then call this function during PDFium // initialization process. // // Call this with NULL to tell PDFium to stop using a previously set // |FPDF_SYSFONTINFO|. FPDF_EXPORT void FPDF_CALLCONV FPDF_SetSystemFontInfo(FPDF_SYSFONTINFO* font_info); // Function: FPDF_GetDefaultSystemFontInfo // Get default system font info interface for current platform // Parameters: // None // Return Value: // Pointer to a FPDF_SYSFONTINFO structure describing the default // interface, or NULL if the platform doesn't have a default interface. // Application should call FPDF_FreeDefaultSystemFontInfo to free the // returned pointer. // Comments: // For some platforms, PDFium implements a default version of system // font info interface. The default implementation can be passed to // FPDF_SetSystemFontInfo(). FPDF_EXPORT FPDF_SYSFONTINFO* FPDF_CALLCONV FPDF_GetDefaultSystemFontInfo(); // Function: FPDF_FreeDefaultSystemFontInfo // Free a default system font info interface // Parameters: // font_info - Pointer to a FPDF_SYSFONTINFO structure // Return Value: // None // Comments: // This function should be called on the output from // FPDF_GetDefaultSystemFontInfo() once it is no longer needed. FPDF_EXPORT void FPDF_CALLCONV FPDF_FreeDefaultSystemFontInfo(FPDF_SYSFONTINFO* font_info); #ifdef __cplusplus } #endif #endif // PUBLIC_FPDF_SYSFONTINFO_H_ ================================================ FILE: external/pdfium/macos-arm64/include/fpdf_text.h ================================================ // Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #ifndef PUBLIC_FPDF_TEXT_H_ #define PUBLIC_FPDF_TEXT_H_ // clang-format off // NOLINTNEXTLINE(build/include) #include "fpdfview.h" // Exported Functions #ifdef __cplusplus extern "C" { #endif // Function: FPDFText_LoadPage // Prepare information about all characters in a page. // Parameters: // page - Handle to the page. Returned by FPDF_LoadPage function // (in FPDFVIEW module). // Return value: // A handle to the text page information structure. // NULL if something goes wrong. // Comments: // Application must call FPDFText_ClosePage to release the text page // information. // FPDF_EXPORT FPDF_TEXTPAGE FPDF_CALLCONV FPDFText_LoadPage(FPDF_PAGE page); // Function: FPDFText_ClosePage // Release all resources allocated for a text page information // structure. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // Return Value: // None. // FPDF_EXPORT void FPDF_CALLCONV FPDFText_ClosePage(FPDF_TEXTPAGE text_page); // Function: FPDFText_CountChars // Get number of characters in a page. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // Return value: // Number of characters in the page. Return -1 for error. // Generated characters, like additional space characters, new line // characters, are also counted. // Comments: // Characters in a page form a "stream", inside the stream, each // character has an index. // We will use the index parameters in many of FPDFTEXT functions. The // first character in the page // has an index value of zero. // FPDF_EXPORT int FPDF_CALLCONV FPDFText_CountChars(FPDF_TEXTPAGE text_page); // Function: FPDFText_GetUnicode // Get Unicode of a character in a page. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // index - Zero-based index of the character. // Return value: // The Unicode of the particular character. // If a character is not encoded in Unicode and Foxit engine can't // convert to Unicode, // the return value will be zero. // FPDF_EXPORT unsigned int FPDF_CALLCONV FPDFText_GetUnicode(FPDF_TEXTPAGE text_page, int index); // Experimental API. // Function: FPDFText_GetTextObject // Get the FPDF_PAGEOBJECT associated with a given character. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // index - Zero-based index of the character. // Return value: // The associated text object for the character at |index|, or NULL on // error. The returned text object, if non-null, is of type // |FPDF_PAGEOBJ_TEXT|. The caller does not own the returned object. // FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV FPDFText_GetTextObject(FPDF_TEXTPAGE text_page, int index); // Experimental API. // Function: FPDFText_IsGenerated // Get if a character in a page is generated by PDFium. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // index - Zero-based index of the character. // Return value: // 1 if the character is generated by PDFium. // 0 if the character is not generated by PDFium. // -1 if there was an error. // FPDF_EXPORT int FPDF_CALLCONV FPDFText_IsGenerated(FPDF_TEXTPAGE text_page, int index); // Experimental API. // Function: FPDFText_IsHyphen // Get if a character in a page is a hyphen. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // index - Zero-based index of the character. // Return value: // 1 if the character is a hyphen. // 0 if the character is not a hyphen. // -1 if there was an error. // FPDF_EXPORT int FPDF_CALLCONV FPDFText_IsHyphen(FPDF_TEXTPAGE text_page, int index); // Experimental API. // Function: FPDFText_HasUnicodeMapError // Get if a character in a page has an invalid unicode mapping. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // index - Zero-based index of the character. // Return value: // 1 if the character has an invalid unicode mapping. // 0 if the character has no known unicode mapping issues. // -1 if there was an error. // FPDF_EXPORT int FPDF_CALLCONV FPDFText_HasUnicodeMapError(FPDF_TEXTPAGE text_page, int index); // Function: FPDFText_GetFontSize // Get the font size of a particular character. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // index - Zero-based index of the character. // Return value: // The font size of the particular character, measured in points (about // 1/72 inch). This is the typographic size of the font (so called // "em size"). // FPDF_EXPORT double FPDF_CALLCONV FPDFText_GetFontSize(FPDF_TEXTPAGE text_page, int index); // Experimental API. // Function: FPDFText_GetFontInfo // Get the font name and flags of a particular character. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // index - Zero-based index of the character. // buffer - A buffer receiving the font name. // buflen - The length of |buffer| in bytes. // flags - Optional pointer to an int receiving the font flags. // These flags should be interpreted per PDF spec 1.7 // Section 5.7.1 Font Descriptor Flags. // Return value: // On success, return the length of the font name, including the // trailing NUL character, in bytes. If this length is less than or // equal to |length|, |buffer| is set to the font name, |flags| is // set to the font flags. |buffer| is in UTF-8 encoding. Return 0 on // failure. // FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFText_GetFontInfo(FPDF_TEXTPAGE text_page, int index, void* buffer, unsigned long buflen, int* flags); // Experimental API. // Function: FPDFText_GetFontWeight // Get the font weight of a particular character. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // index - Zero-based index of the character. // Return value: // On success, return the font weight of the particular character. If // |text_page| is invalid, if |index| is out of bounds, or if the // character's text object is undefined, return -1. // FPDF_EXPORT int FPDF_CALLCONV FPDFText_GetFontWeight(FPDF_TEXTPAGE text_page, int index); // Experimental API. // Function: FPDFText_GetFillColor // Get the fill color of a particular character. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // index - Zero-based index of the character. // R - Pointer to an unsigned int number receiving the // red value of the fill color. // G - Pointer to an unsigned int number receiving the // green value of the fill color. // B - Pointer to an unsigned int number receiving the // blue value of the fill color. // A - Pointer to an unsigned int number receiving the // alpha value of the fill color. // Return value: // Whether the call succeeded. If false, |R|, |G|, |B| and |A| are // unchanged. // FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFText_GetFillColor(FPDF_TEXTPAGE text_page, int index, unsigned int* R, unsigned int* G, unsigned int* B, unsigned int* A); // Experimental API. // Function: FPDFText_GetStrokeColor // Get the stroke color of a particular character. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // index - Zero-based index of the character. // R - Pointer to an unsigned int number receiving the // red value of the stroke color. // G - Pointer to an unsigned int number receiving the // green value of the stroke color. // B - Pointer to an unsigned int number receiving the // blue value of the stroke color. // A - Pointer to an unsigned int number receiving the // alpha value of the stroke color. // Return value: // Whether the call succeeded. If false, |R|, |G|, |B| and |A| are // unchanged. // FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFText_GetStrokeColor(FPDF_TEXTPAGE text_page, int index, unsigned int* R, unsigned int* G, unsigned int* B, unsigned int* A); // Experimental API. // Function: FPDFText_GetCharAngle // Get character rotation angle. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // index - Zero-based index of the character. // Return Value: // On success, return the angle value in radian. Value will always be // greater or equal to 0. If |text_page| is invalid, or if |index| is // out of bounds, then return -1. // FPDF_EXPORT float FPDF_CALLCONV FPDFText_GetCharAngle(FPDF_TEXTPAGE text_page, int index); // Function: FPDFText_GetCharBox // Get bounding box of a particular character. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // index - Zero-based index of the character. // left - Pointer to a double number receiving left position // of the character box. // right - Pointer to a double number receiving right position // of the character box. // bottom - Pointer to a double number receiving bottom position // of the character box. // top - Pointer to a double number receiving top position of // the character box. // Return Value: // On success, return TRUE and fill in |left|, |right|, |bottom|, and // |top|. If |text_page| is invalid, or if |index| is out of bounds, // then return FALSE, and the out parameters remain unmodified. // Comments: // All positions are measured in PDF "user space". // FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFText_GetCharBox(FPDF_TEXTPAGE text_page, int index, double* left, double* right, double* bottom, double* top); // Experimental API. // Function: FPDFText_GetLooseCharBox // Get a "loose" bounding box of a particular character, i.e., covering // the entire glyph bounds, without taking the actual glyph shape into // account. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // index - Zero-based index of the character. // rect - Pointer to a FS_RECTF receiving the character box. // Return Value: // On success, return TRUE and fill in |rect|. If |text_page| is // invalid, or if |index| is out of bounds, then return FALSE, and the // |rect| out parameter remains unmodified. // Comments: // All positions are measured in PDF "user space". // FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFText_GetLooseCharBox(FPDF_TEXTPAGE text_page, int index, FS_RECTF* rect); // Experimental API. // Function: FPDFText_GetMatrix // Get the effective transformation matrix for a particular character. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage(). // index - Zero-based index of the character. // matrix - Pointer to a FS_MATRIX receiving the transformation // matrix. // Return Value: // On success, return TRUE and fill in |matrix|. If |text_page| is // invalid, or if |index| is out of bounds, or if |matrix| is NULL, // then return FALSE, and |matrix| remains unmodified. // FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFText_GetMatrix(FPDF_TEXTPAGE text_page, int index, FS_MATRIX* matrix); // Function: FPDFText_GetCharOrigin // Get origin of a particular character. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // index - Zero-based index of the character. // x - Pointer to a double number receiving x coordinate of // the character origin. // y - Pointer to a double number receiving y coordinate of // the character origin. // Return Value: // Whether the call succeeded. If false, x and y are unchanged. // Comments: // All positions are measured in PDF "user space". // FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFText_GetCharOrigin(FPDF_TEXTPAGE text_page, int index, double* x, double* y); // Function: FPDFText_GetCharIndexAtPos // Get the index of a character at or nearby a certain position on the // page. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // x - X position in PDF "user space". // y - Y position in PDF "user space". // xTolerance - An x-axis tolerance value for character hit // detection, in point units. // yTolerance - A y-axis tolerance value for character hit // detection, in point units. // Return Value: // The zero-based index of the character at, or nearby the point (x,y). // If there is no character at or nearby the point, return value will // be -1. If an error occurs, -3 will be returned. // FPDF_EXPORT int FPDF_CALLCONV FPDFText_GetCharIndexAtPos(FPDF_TEXTPAGE text_page, double x, double y, double xTolerance, double yTolerance); // Function: FPDFText_GetText // Extract unicode text string from the page. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // start_index - Index for the start characters. // count - Number of UCS-2 values to be extracted. // result - A buffer (allocated by application) receiving the // extracted UCS-2 values. The buffer must be able to // hold `count` UCS-2 values plus a terminator. // Return Value: // Number of characters written into the result buffer, including the // trailing terminator. // Comments: // This function ignores characters without UCS-2 representations. // It considers all characters on the page, even those that are not // visible when the page has a cropbox. To filter out the characters // outside of the cropbox, use FPDF_GetPageBoundingBox() and // FPDFText_GetCharBox(). // FPDF_EXPORT int FPDF_CALLCONV FPDFText_GetText(FPDF_TEXTPAGE text_page, int start_index, int count, unsigned short* result); // Function: FPDFText_CountRects // Counts number of rectangular areas occupied by a segment of text, // and caches the result for subsequent FPDFText_GetRect() calls. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // start_index - Index for the start character. // count - Number of characters, or -1 for all remaining. // Return value: // Number of rectangles, 0 if text_page is null, or -1 on bad // start_index. // Comments: // This function, along with FPDFText_GetRect can be used by // applications to detect the position on the page for a text segment, // so proper areas can be highlighted. The FPDFText_* functions will // automatically merge small character boxes into bigger one if those // characters are on the same line and use same font settings. // FPDF_EXPORT int FPDF_CALLCONV FPDFText_CountRects(FPDF_TEXTPAGE text_page, int start_index, int count); // Function: FPDFText_GetRect // Get a rectangular area from the result generated by // FPDFText_CountRects. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // rect_index - Zero-based index for the rectangle. // left - Pointer to a double value receiving the rectangle // left boundary. // top - Pointer to a double value receiving the rectangle // top boundary. // right - Pointer to a double value receiving the rectangle // right boundary. // bottom - Pointer to a double value receiving the rectangle // bottom boundary. // Return Value: // On success, return TRUE and fill in |left|, |top|, |right|, and // |bottom|. If |text_page| is invalid then return FALSE, and the out // parameters remain unmodified. If |text_page| is valid but // |rect_index| is out of bounds, then return FALSE and set the out // parameters to 0. // FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFText_GetRect(FPDF_TEXTPAGE text_page, int rect_index, double* left, double* top, double* right, double* bottom); // Function: FPDFText_GetBoundedText // Extract unicode text within a rectangular boundary on the page. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // left - Left boundary. // top - Top boundary. // right - Right boundary. // bottom - Bottom boundary. // buffer - Caller-allocated buffer to receive UTF-16 values. // buflen - Number of UTF-16 values (not bytes) that `buffer` // is capable of holding. // Return Value: // If buffer is NULL or buflen is zero, return number of UTF-16 // values (not bytes) of text present within the rectangle, excluding // a terminating NUL. Generally you should pass a buffer at least one // larger than this if you want a terminating NUL, which will be // provided if space is available. Otherwise, return number of UTF-16 // values copied into the buffer, including the terminating NUL when // space for it is available. // Comment: // If the buffer is too small, as much text as will fit is copied into // it. May return a split surrogate in that case. // FPDF_EXPORT int FPDF_CALLCONV FPDFText_GetBoundedText(FPDF_TEXTPAGE text_page, double left, double top, double right, double bottom, unsigned short* buffer, int buflen); // Flags used by FPDFText_FindStart function. // // If not set, it will not match case by default. #define FPDF_MATCHCASE 0x00000001 // If not set, it will not match the whole word by default. #define FPDF_MATCHWHOLEWORD 0x00000002 // If not set, it will skip past the current match to look for the next match. #define FPDF_CONSECUTIVE 0x00000004 // Function: FPDFText_FindStart // Start a search. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // findwhat - A unicode match pattern. // flags - Option flags. // start_index - Start from this character. -1 for end of the page. // Return Value: // A handle for the search context. FPDFText_FindClose must be called // to release this handle. // FPDF_EXPORT FPDF_SCHHANDLE FPDF_CALLCONV FPDFText_FindStart(FPDF_TEXTPAGE text_page, FPDF_WIDESTRING findwhat, unsigned long flags, int start_index); // Function: FPDFText_FindNext // Search in the direction from page start to end. // Parameters: // handle - A search context handle returned by // FPDFText_FindStart. // Return Value: // Whether a match is found. // FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFText_FindNext(FPDF_SCHHANDLE handle); // Function: FPDFText_FindPrev // Search in the direction from page end to start. // Parameters: // handle - A search context handle returned by // FPDFText_FindStart. // Return Value: // Whether a match is found. // FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFText_FindPrev(FPDF_SCHHANDLE handle); // Function: FPDFText_GetSchResultIndex // Get the starting character index of the search result. // Parameters: // handle - A search context handle returned by // FPDFText_FindStart. // Return Value: // Index for the starting character. // FPDF_EXPORT int FPDF_CALLCONV FPDFText_GetSchResultIndex(FPDF_SCHHANDLE handle); // Function: FPDFText_GetSchCount // Get the number of matched characters in the search result. // Parameters: // handle - A search context handle returned by // FPDFText_FindStart. // Return Value: // Number of matched characters. // FPDF_EXPORT int FPDF_CALLCONV FPDFText_GetSchCount(FPDF_SCHHANDLE handle); // Function: FPDFText_FindClose // Release a search context. // Parameters: // handle - A search context handle returned by // FPDFText_FindStart. // Return Value: // None. // FPDF_EXPORT void FPDF_CALLCONV FPDFText_FindClose(FPDF_SCHHANDLE handle); // Function: FPDFLink_LoadWebLinks // Prepare information about weblinks in a page. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // Return Value: // A handle to the page's links information structure, or // NULL if something goes wrong. // Comments: // Weblinks are those links implicitly embedded in PDF pages. PDF also // has a type of annotation called "link" (FPDFTEXT doesn't deal with // that kind of link). FPDFTEXT weblink feature is useful for // automatically detecting links in the page contents. For example, // things like "https://www.example.com" will be detected, so // applications can allow user to click on those characters to activate // the link, even the PDF doesn't come with link annotations. // // FPDFLink_CloseWebLinks must be called to release resources. // FPDF_EXPORT FPDF_PAGELINK FPDF_CALLCONV FPDFLink_LoadWebLinks(FPDF_TEXTPAGE text_page); // Function: FPDFLink_CountWebLinks // Count number of detected web links. // Parameters: // link_page - Handle returned by FPDFLink_LoadWebLinks. // Return Value: // Number of detected web links. // FPDF_EXPORT int FPDF_CALLCONV FPDFLink_CountWebLinks(FPDF_PAGELINK link_page); // Function: FPDFLink_GetURL // Fetch the URL information for a detected web link. // Parameters: // link_page - Handle returned by FPDFLink_LoadWebLinks. // link_index - Zero-based index for the link. // buffer - A unicode buffer for the result. // buflen - Number of 16-bit code units (not bytes) for the // buffer, including an additional terminator. // Return Value: // If |buffer| is NULL or |buflen| is zero, return the number of 16-bit // code units (not bytes) needed to buffer the result (an additional // terminator is included in this count). // Otherwise, copy the result into |buffer|, truncating at |buflen| if // the result is too large to fit, and return the number of 16-bit code // units actually copied into the buffer (the additional terminator is // also included in this count). // If |link_index| does not correspond to a valid link, then the result // is an empty string. // FPDF_EXPORT int FPDF_CALLCONV FPDFLink_GetURL(FPDF_PAGELINK link_page, int link_index, unsigned short* buffer, int buflen); // Function: FPDFLink_CountRects // Count number of rectangular areas for the link. // Parameters: // link_page - Handle returned by FPDFLink_LoadWebLinks. // link_index - Zero-based index for the link. // Return Value: // Number of rectangular areas for the link. If |link_index| does // not correspond to a valid link, then 0 is returned. // FPDF_EXPORT int FPDF_CALLCONV FPDFLink_CountRects(FPDF_PAGELINK link_page, int link_index); // Function: FPDFLink_GetRect // Fetch the boundaries of a rectangle for a link. // Parameters: // link_page - Handle returned by FPDFLink_LoadWebLinks. // link_index - Zero-based index for the link. // rect_index - Zero-based index for a rectangle. // left - Pointer to a double value receiving the rectangle // left boundary. // top - Pointer to a double value receiving the rectangle // top boundary. // right - Pointer to a double value receiving the rectangle // right boundary. // bottom - Pointer to a double value receiving the rectangle // bottom boundary. // Return Value: // On success, return TRUE and fill in |left|, |top|, |right|, and // |bottom|. If |link_page| is invalid or if |link_index| does not // correspond to a valid link, then return FALSE, and the out // parameters remain unmodified. // FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFLink_GetRect(FPDF_PAGELINK link_page, int link_index, int rect_index, double* left, double* top, double* right, double* bottom); // Experimental API. // Function: FPDFLink_GetTextRange // Fetch the start char index and char count for a link. // Parameters: // link_page - Handle returned by FPDFLink_LoadWebLinks. // link_index - Zero-based index for the link. // start_char_index - pointer to int receiving the start char index // char_count - pointer to int receiving the char count // Return Value: // On success, return TRUE and fill in |start_char_index| and // |char_count|. if |link_page| is invalid or if |link_index| does // not correspond to a valid link, then return FALSE and the out // parameters remain unmodified. // FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFLink_GetTextRange(FPDF_PAGELINK link_page, int link_index, int* start_char_index, int* char_count); // Function: FPDFLink_CloseWebLinks // Release resources used by weblink feature. // Parameters: // link_page - Handle returned by FPDFLink_LoadWebLinks. // Return Value: // None. // FPDF_EXPORT void FPDF_CALLCONV FPDFLink_CloseWebLinks(FPDF_PAGELINK link_page); #ifdef __cplusplus } #endif #endif // PUBLIC_FPDF_TEXT_H_ ================================================ FILE: external/pdfium/macos-arm64/include/fpdf_thumbnail.h ================================================ // Copyright 2019 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef PUBLIC_FPDF_THUMBNAIL_H_ #define PUBLIC_FPDF_THUMBNAIL_H_ #include // NOLINTNEXTLINE(build/include) #include "fpdfview.h" #ifdef __cplusplus extern "C" { #endif // Experimental API. // Gets the decoded data from the thumbnail of |page| if it exists. // This only modifies |buffer| if |buflen| less than or equal to the // size of the decoded data. Returns the size of the decoded // data or 0 if thumbnail DNE. Optional, pass null to just retrieve // the size of the buffer needed. // // page - handle to a page. // buffer - buffer for holding the decoded image data. // buflen - length of the buffer in bytes. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFPage_GetDecodedThumbnailData(FPDF_PAGE page, void* buffer, unsigned long buflen); // Experimental API. // Gets the raw data from the thumbnail of |page| if it exists. // This only modifies |buffer| if |buflen| is less than or equal to // the size of the raw data. Returns the size of the raw data or 0 // if thumbnail DNE. Optional, pass null to just retrieve the size // of the buffer needed. // // page - handle to a page. // buffer - buffer for holding the raw image data. // buflen - length of the buffer in bytes. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFPage_GetRawThumbnailData(FPDF_PAGE page, void* buffer, unsigned long buflen); // Experimental API. // Returns the thumbnail of |page| as a FPDF_BITMAP. Returns a nullptr // if unable to access the thumbnail's stream. // // page - handle to a page. FPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV FPDFPage_GetThumbnailAsBitmap(FPDF_PAGE page); #ifdef __cplusplus } #endif #endif // PUBLIC_FPDF_THUMBNAIL_H_ ================================================ FILE: external/pdfium/macos-arm64/include/fpdf_transformpage.h ================================================ // Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #ifndef PUBLIC_FPDF_TRANSFORMPAGE_H_ #define PUBLIC_FPDF_TRANSFORMPAGE_H_ // NOLINTNEXTLINE(build/include) #include "fpdfview.h" #ifdef __cplusplus extern "C" { #endif // Set "MediaBox" entry to the page dictionary. // // page - Handle to a page. // left - The left of the rectangle. // bottom - The bottom of the rectangle. // right - The right of the rectangle. // top - The top of the rectangle. FPDF_EXPORT void FPDF_CALLCONV FPDFPage_SetMediaBox(FPDF_PAGE page, float left, float bottom, float right, float top); // Set "CropBox" entry to the page dictionary. // // page - Handle to a page. // left - The left of the rectangle. // bottom - The bottom of the rectangle. // right - The right of the rectangle. // top - The top of the rectangle. FPDF_EXPORT void FPDF_CALLCONV FPDFPage_SetCropBox(FPDF_PAGE page, float left, float bottom, float right, float top); // Set "BleedBox" entry to the page dictionary. // // page - Handle to a page. // left - The left of the rectangle. // bottom - The bottom of the rectangle. // right - The right of the rectangle. // top - The top of the rectangle. FPDF_EXPORT void FPDF_CALLCONV FPDFPage_SetBleedBox(FPDF_PAGE page, float left, float bottom, float right, float top); // Set "TrimBox" entry to the page dictionary. // // page - Handle to a page. // left - The left of the rectangle. // bottom - The bottom of the rectangle. // right - The right of the rectangle. // top - The top of the rectangle. FPDF_EXPORT void FPDF_CALLCONV FPDFPage_SetTrimBox(FPDF_PAGE page, float left, float bottom, float right, float top); // Set "ArtBox" entry to the page dictionary. // // page - Handle to a page. // left - The left of the rectangle. // bottom - The bottom of the rectangle. // right - The right of the rectangle. // top - The top of the rectangle. FPDF_EXPORT void FPDF_CALLCONV FPDFPage_SetArtBox(FPDF_PAGE page, float left, float bottom, float right, float top); // Get "MediaBox" entry from the page dictionary. // // page - Handle to a page. // left - Pointer to a float value receiving the left of the rectangle. // bottom - Pointer to a float value receiving the bottom of the rectangle. // right - Pointer to a float value receiving the right of the rectangle. // top - Pointer to a float value receiving the top of the rectangle. // // On success, return true and write to the out parameters. Otherwise return // false and leave the out parameters unmodified. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_GetMediaBox(FPDF_PAGE page, float* left, float* bottom, float* right, float* top); // Get "CropBox" entry from the page dictionary. // // page - Handle to a page. // left - Pointer to a float value receiving the left of the rectangle. // bottom - Pointer to a float value receiving the bottom of the rectangle. // right - Pointer to a float value receiving the right of the rectangle. // top - Pointer to a float value receiving the top of the rectangle. // // On success, return true and write to the out parameters. Otherwise return // false and leave the out parameters unmodified. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_GetCropBox(FPDF_PAGE page, float* left, float* bottom, float* right, float* top); // Get "BleedBox" entry from the page dictionary. // // page - Handle to a page. // left - Pointer to a float value receiving the left of the rectangle. // bottom - Pointer to a float value receiving the bottom of the rectangle. // right - Pointer to a float value receiving the right of the rectangle. // top - Pointer to a float value receiving the top of the rectangle. // // On success, return true and write to the out parameters. Otherwise return // false and leave the out parameters unmodified. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_GetBleedBox(FPDF_PAGE page, float* left, float* bottom, float* right, float* top); // Get "TrimBox" entry from the page dictionary. // // page - Handle to a page. // left - Pointer to a float value receiving the left of the rectangle. // bottom - Pointer to a float value receiving the bottom of the rectangle. // right - Pointer to a float value receiving the right of the rectangle. // top - Pointer to a float value receiving the top of the rectangle. // // On success, return true and write to the out parameters. Otherwise return // false and leave the out parameters unmodified. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_GetTrimBox(FPDF_PAGE page, float* left, float* bottom, float* right, float* top); // Get "ArtBox" entry from the page dictionary. // // page - Handle to a page. // left - Pointer to a float value receiving the left of the rectangle. // bottom - Pointer to a float value receiving the bottom of the rectangle. // right - Pointer to a float value receiving the right of the rectangle. // top - Pointer to a float value receiving the top of the rectangle. // // On success, return true and write to the out parameters. Otherwise return // false and leave the out parameters unmodified. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_GetArtBox(FPDF_PAGE page, float* left, float* bottom, float* right, float* top); // Apply transforms to |page|. // // If |matrix| is provided it will be applied to transform the page. // If |clipRect| is provided it will be used to clip the resulting page. // If neither |matrix| or |clipRect| are provided this method returns |false|. // Returns |true| if transforms are applied. // // This function will transform the whole page, and would take effect to all the // objects in the page. // // page - Page handle. // matrix - Transform matrix. // clipRect - Clipping rectangle. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_TransFormWithClip(FPDF_PAGE page, const FS_MATRIX* matrix, const FS_RECTF* clipRect); // Transform (scale, rotate, shear, move) the clip path of page object. // page_object - Handle to a page object. Returned by // FPDFPageObj_NewImageObj(). // // a - The coefficient "a" of the matrix. // b - The coefficient "b" of the matrix. // c - The coefficient "c" of the matrix. // d - The coefficient "d" of the matrix. // e - The coefficient "e" of the matrix. // f - The coefficient "f" of the matrix. FPDF_EXPORT void FPDF_CALLCONV FPDFPageObj_TransformClipPath(FPDF_PAGEOBJECT page_object, double a, double b, double c, double d, double e, double f); // Experimental API. // Get the clip path of the page object. // // page object - Handle to a page object. Returned by e.g. // FPDFPage_GetObject(). // // Returns the handle to the clip path, or NULL on failure. The caller does not // take ownership of the returned FPDF_CLIPPATH. Instead, it remains valid until // FPDF_ClosePage() is called for the page containing |page_object|. FPDF_EXPORT FPDF_CLIPPATH FPDF_CALLCONV FPDFPageObj_GetClipPath(FPDF_PAGEOBJECT page_object); // Experimental API. // Get number of paths inside |clip_path|. // // clip_path - handle to a clip_path. // // Returns the number of objects in |clip_path| or -1 on failure. FPDF_EXPORT int FPDF_CALLCONV FPDFClipPath_CountPaths(FPDF_CLIPPATH clip_path); // Experimental API. // Get number of segments inside one path of |clip_path|. // // clip_path - handle to a clip_path. // path_index - index into the array of paths of the clip path. // // Returns the number of segments or -1 on failure. FPDF_EXPORT int FPDF_CALLCONV FPDFClipPath_CountPathSegments(FPDF_CLIPPATH clip_path, int path_index); // Experimental API. // Get segment in one specific path of |clip_path| at index. // // clip_path - handle to a clip_path. // path_index - the index of a path. // segment_index - the index of a segment. // // Returns the handle to the segment, or NULL on failure. The caller does not // take ownership of the returned FPDF_PATHSEGMENT. Instead, it remains valid // until FPDF_ClosePage() is called for the page containing |clip_path|. FPDF_EXPORT FPDF_PATHSEGMENT FPDF_CALLCONV FPDFClipPath_GetPathSegment(FPDF_CLIPPATH clip_path, int path_index, int segment_index); // Create a new clip path, with a rectangle inserted. // // Caller takes ownership of the returned FPDF_CLIPPATH. It should be freed with // FPDF_DestroyClipPath(). // // left - The left of the clip box. // bottom - The bottom of the clip box. // right - The right of the clip box. // top - The top of the clip box. FPDF_EXPORT FPDF_CLIPPATH FPDF_CALLCONV FPDF_CreateClipPath(float left, float bottom, float right, float top); // Destroy the clip path. // // clipPath - A handle to the clip path. It will be invalid after this call. FPDF_EXPORT void FPDF_CALLCONV FPDF_DestroyClipPath(FPDF_CLIPPATH clipPath); // Clip the page content, the page content that outside the clipping region // become invisible. // // A clip path will be inserted before the page content stream or content array. // In this way, the page content will be clipped by this clip path. // // page - A page handle. // clipPath - A handle to the clip path. (Does not take ownership.) FPDF_EXPORT void FPDF_CALLCONV FPDFPage_InsertClipPath(FPDF_PAGE page, FPDF_CLIPPATH clipPath); #ifdef __cplusplus } #endif #endif // PUBLIC_FPDF_TRANSFORMPAGE_H_ ================================================ FILE: external/pdfium/macos-arm64/include/fpdfview.h ================================================ // Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com // This is the main header file for embedders of PDFium. It provides APIs to // initialize the library, load documents, and render pages, amongst other // things. // // NOTE: None of the PDFium APIs are thread-safe. They expect to be called // from a single thread. Barring that, embedders are required to ensure (via // a mutex or similar) that only a single PDFium call can be made at a time. // // NOTE: External docs refer to this file as "fpdfview.h", so do not rename // despite lack of consistency with other public files. #ifndef PUBLIC_FPDFVIEW_H_ #define PUBLIC_FPDFVIEW_H_ // clang-format off #include #if defined(_WIN32) && !defined(__WINDOWS__) #include #endif #ifdef PDF_ENABLE_XFA // PDF_USE_XFA is set in confirmation that this version of PDFium can support // XFA forms as requested by the PDF_ENABLE_XFA setting. #define PDF_USE_XFA #endif // PDF_ENABLE_XFA // PDF object types #define FPDF_OBJECT_UNKNOWN 0 #define FPDF_OBJECT_BOOLEAN 1 #define FPDF_OBJECT_NUMBER 2 #define FPDF_OBJECT_STRING 3 #define FPDF_OBJECT_NAME 4 #define FPDF_OBJECT_ARRAY 5 #define FPDF_OBJECT_DICTIONARY 6 #define FPDF_OBJECT_STREAM 7 #define FPDF_OBJECT_NULLOBJ 8 #define FPDF_OBJECT_REFERENCE 9 // PDF text rendering modes typedef enum { FPDF_TEXTRENDERMODE_UNKNOWN = -1, FPDF_TEXTRENDERMODE_FILL = 0, FPDF_TEXTRENDERMODE_STROKE = 1, FPDF_TEXTRENDERMODE_FILL_STROKE = 2, FPDF_TEXTRENDERMODE_INVISIBLE = 3, FPDF_TEXTRENDERMODE_FILL_CLIP = 4, FPDF_TEXTRENDERMODE_STROKE_CLIP = 5, FPDF_TEXTRENDERMODE_FILL_STROKE_CLIP = 6, FPDF_TEXTRENDERMODE_CLIP = 7, FPDF_TEXTRENDERMODE_LAST = FPDF_TEXTRENDERMODE_CLIP, } FPDF_TEXT_RENDERMODE; // PDF types - use incomplete types (never completed) to force API type safety. typedef struct fpdf_action_t__* FPDF_ACTION; typedef struct fpdf_annotation_t__* FPDF_ANNOTATION; typedef struct fpdf_attachment_t__* FPDF_ATTACHMENT; typedef struct fpdf_avail_t__* FPDF_AVAIL; typedef struct fpdf_bitmap_t__* FPDF_BITMAP; typedef struct fpdf_bookmark_t__* FPDF_BOOKMARK; typedef struct fpdf_clippath_t__* FPDF_CLIPPATH; typedef struct fpdf_dest_t__* FPDF_DEST; typedef struct fpdf_document_t__* FPDF_DOCUMENT; typedef struct fpdf_font_t__* FPDF_FONT; typedef struct fpdf_form_handle_t__* FPDF_FORMHANDLE; typedef const struct fpdf_glyphpath_t__* FPDF_GLYPHPATH; typedef struct fpdf_javascript_action_t* FPDF_JAVASCRIPT_ACTION; typedef struct fpdf_link_t__* FPDF_LINK; typedef struct fpdf_page_t__* FPDF_PAGE; typedef struct fpdf_pagelink_t__* FPDF_PAGELINK; typedef struct fpdf_pageobject_t__* FPDF_PAGEOBJECT; // (text, path, etc.) typedef struct fpdf_pageobjectmark_t__* FPDF_PAGEOBJECTMARK; typedef const struct fpdf_pagerange_t__* FPDF_PAGERANGE; typedef const struct fpdf_pathsegment_t* FPDF_PATHSEGMENT; typedef struct fpdf_schhandle_t__* FPDF_SCHHANDLE; typedef const struct fpdf_signature_t__* FPDF_SIGNATURE; typedef void* FPDF_SKIA_CANVAS; // Passed into Skia as an SkCanvas. typedef struct fpdf_structelement_t__* FPDF_STRUCTELEMENT; typedef const struct fpdf_structelement_attr_t__* FPDF_STRUCTELEMENT_ATTR; typedef const struct fpdf_structelement_attr_value_t__* FPDF_STRUCTELEMENT_ATTR_VALUE; typedef struct fpdf_structtree_t__* FPDF_STRUCTTREE; typedef struct fpdf_textpage_t__* FPDF_TEXTPAGE; typedef struct fpdf_widget_t__* FPDF_WIDGET; typedef struct fpdf_xobject_t__* FPDF_XOBJECT; // Basic data types typedef int FPDF_BOOL; typedef int FPDF_RESULT; typedef unsigned long FPDF_DWORD; typedef float FS_FLOAT; // Duplex types typedef enum _FPDF_DUPLEXTYPE_ { DuplexUndefined = 0, Simplex, DuplexFlipShortEdge, DuplexFlipLongEdge } FPDF_DUPLEXTYPE; // String types typedef unsigned short FPDF_WCHAR; // The public PDFium API uses three types of strings: byte string, wide string // (UTF-16LE encoded), and platform dependent string. // Public PDFium API type for byte strings. typedef const char* FPDF_BYTESTRING; // The public PDFium API always uses UTF-16LE encoded wide strings, each // character uses 2 bytes (except surrogation), with the low byte first. typedef const FPDF_WCHAR* FPDF_WIDESTRING; // Structure for persisting a string beyond the duration of a callback. // Note: although represented as a char*, string may be interpreted as // a UTF-16LE formated string. Used only by XFA callbacks. typedef struct FPDF_BSTR_ { char* str; // String buffer, manipulate only with FPDF_BStr_* methods. int len; // Length of the string, in bytes. } FPDF_BSTR; // For Windows programmers: In most cases it's OK to treat FPDF_WIDESTRING as a // Windows unicode string, however, special care needs to be taken if you // expect to process Unicode larger than 0xffff. // // For Linux/Unix programmers: most compiler/library environments use 4 bytes // for a Unicode character, and you have to convert between FPDF_WIDESTRING and // system wide string by yourself. typedef const char* FPDF_STRING; // Matrix for transformation, in the form [a b c d e f], equivalent to: // | a b 0 | // | c d 0 | // | e f 1 | // // Translation is performed with [1 0 0 1 tx ty]. // Scaling is performed with [sx 0 0 sy 0 0]. // See PDF Reference 1.7, 4.2.2 Common Transformations for more. typedef struct _FS_MATRIX_ { float a; float b; float c; float d; float e; float f; } FS_MATRIX; // Rectangle area(float) in device or page coordinate system. typedef struct _FS_RECTF_ { // The x-coordinate of the left-top corner. float left; // The y-coordinate of the left-top corner. float top; // The x-coordinate of the right-bottom corner. float right; // The y-coordinate of the right-bottom corner. float bottom; } * FS_LPRECTF, FS_RECTF; // Const Pointer to FS_RECTF structure. typedef const FS_RECTF* FS_LPCRECTF; // Rectangle size. Coordinate system agnostic. typedef struct FS_SIZEF_ { float width; float height; } * FS_LPSIZEF, FS_SIZEF; // Const Pointer to FS_SIZEF structure. typedef const FS_SIZEF* FS_LPCSIZEF; // 2D Point. Coordinate system agnostic. typedef struct FS_POINTF_ { float x; float y; } * FS_LPPOINTF, FS_POINTF; // Const Pointer to FS_POINTF structure. typedef const FS_POINTF* FS_LPCPOINTF; typedef struct _FS_QUADPOINTSF { FS_FLOAT x1; FS_FLOAT y1; FS_FLOAT x2; FS_FLOAT y2; FS_FLOAT x3; FS_FLOAT y3; FS_FLOAT x4; FS_FLOAT y4; } FS_QUADPOINTSF; // Annotation enums. typedef int FPDF_ANNOTATION_SUBTYPE; typedef int FPDF_ANNOT_APPEARANCEMODE; // Dictionary value types. typedef int FPDF_OBJECT_TYPE; #if defined(WIN32) #if defined(FPDF_IMPLEMENTATION) #define FPDF_EXPORT __declspec(dllexport) #else #define FPDF_EXPORT __declspec(dllimport) #endif // defined(FPDF_IMPLEMENTATION) #else #if defined(FPDF_IMPLEMENTATION) #define FPDF_EXPORT __attribute__((visibility("default"))) #else #define FPDF_EXPORT #endif // defined(FPDF_IMPLEMENTATION) #endif // defined(WIN32) #if defined(WIN32) && defined(FPDFSDK_EXPORTS) #define FPDF_CALLCONV __stdcall #else #define FPDF_CALLCONV #endif // Exported Functions #ifdef __cplusplus extern "C" { #endif // PDF renderer types - Experimental. // Selection of 2D graphics library to use for rendering to FPDF_BITMAPs. typedef enum { // Anti-Grain Geometry - https://sourceforge.net/projects/agg/ FPDF_RENDERERTYPE_AGG = 0, // Skia - https://skia.org/ FPDF_RENDERERTYPE_SKIA = 1, } FPDF_RENDERER_TYPE; // PDF font library types - Experimental. // Selection of font backend library to use. typedef enum { // FreeType - https://freetype.org/ FPDF_FONTBACKENDTYPE_FREETYPE = 0, // Fontations - https://github.com/googlefonts/fontations/ FPDF_FONTBACKENDTYPE_FONTATIONS = 1, } FPDF_FONT_BACKEND_TYPE; // Process-wide options for initializing the library. typedef struct FPDF_LIBRARY_CONFIG_ { // Version number of the interface. Currently must be 2. // Support for version 1 will be deprecated in the future. int version; // Array of paths to scan in place of the defaults when using built-in // FXGE font loading code. The array is terminated by a NULL pointer. // The Array may be NULL itself to use the default paths. May be ignored // entirely depending upon the platform. const char** m_pUserFontPaths; // Version 2. // Pointer to the v8::Isolate to use, or NULL to force PDFium to create one. void* m_pIsolate; // The embedder data slot to use in the v8::Isolate to store PDFium's // per-isolate data. The value needs to be in the range // [0, |v8::Internals::kNumIsolateDataLots|). Note that 0 is fine for most // embedders. unsigned int m_v8EmbedderSlot; // Version 3 - Experimental. // Pointer to the V8::Platform to use. void* m_pPlatform; // Version 4 - Experimental. // Explicit specification of 2D graphics rendering library to use. // |m_RendererType| must be a valid value for |FPDF_LIBRARY_CONFIG| versions // of this level or higher, or else the initialization will fail with an // immediate crash. // Note that use of a specified |FPDF_RENDERER_TYPE| value for which the // corresponding 2D graphics rendering library is not included in the build // will similarly fail with an immediate crash. FPDF_RENDERER_TYPE m_RendererType; // Version 5 - Experimental. // Explicit specification of font library to use when |m_RendererType| is set // to |FPDF_RENDERERTYPE_SKIA|. // |m_FontLibraryType| must be a valid value for |FPDF_LIBRARY_CONFIG| // versions of this level or higher, or else the initialization will fail with // an immediate crash. // Note that use of a specified |FPDF_FONT_BACKEND_TYPE| value for which the // corresponding font library is not included in the build will similarly fail // with an immediate crash. FPDF_FONT_BACKEND_TYPE m_FontLibraryType; } FPDF_LIBRARY_CONFIG; // Function: FPDF_InitLibraryWithConfig // Initialize the PDFium library and allocate global resources for it. // Parameters: // config - configuration information as above. // Return value: // None. // Comments: // You have to call this function before you can call any PDF // processing functions. FPDF_EXPORT void FPDF_CALLCONV FPDF_InitLibraryWithConfig(const FPDF_LIBRARY_CONFIG* config); // Function: FPDF_InitLibrary // Initialize the PDFium library (alternative form). // Parameters: // None // Return value: // None. // Comments: // Convenience function to call FPDF_InitLibraryWithConfig() with a // default configuration for backwards compatibility purposes. New // code should call FPDF_InitLibraryWithConfig() instead. This will // be deprecated in the future. FPDF_EXPORT void FPDF_CALLCONV FPDF_InitLibrary(); // Function: FPDF_DestroyLibrary // Release global resources allocated to the PDFium library by // FPDF_InitLibrary() or FPDF_InitLibraryWithConfig(). // Parameters: // None. // Return value: // None. // Comments: // After this function is called, you must not call any PDF // processing functions. // // Calling this function does not automatically close other // objects. It is recommended to close other objects before // closing the library with this function. FPDF_EXPORT void FPDF_CALLCONV FPDF_DestroyLibrary(); // Policy for accessing the local machine time. #define FPDF_POLICY_MACHINETIME_ACCESS 0 // Function: FPDF_SetSandBoxPolicy // Set the policy for the sandbox environment. // Parameters: // policy - The specified policy for setting, for example: // FPDF_POLICY_MACHINETIME_ACCESS. // enable - True to enable, false to disable the policy. // Return value: // None. FPDF_EXPORT void FPDF_CALLCONV FPDF_SetSandBoxPolicy(FPDF_DWORD policy, FPDF_BOOL enable); #if defined(_WIN32) // Experimental API. // Function: FPDF_SetPrintMode // Set printing mode when printing on Windows. // Parameters: // mode - FPDF_PRINTMODE_EMF to output EMF (default) // FPDF_PRINTMODE_TEXTONLY to output text only (for charstream // devices) // FPDF_PRINTMODE_POSTSCRIPT2 to output level 2 PostScript into // EMF as a series of GDI comments. // FPDF_PRINTMODE_POSTSCRIPT3 to output level 3 PostScript into // EMF as a series of GDI comments. // FPDF_PRINTMODE_POSTSCRIPT2_PASSTHROUGH to output level 2 // PostScript via ExtEscape() in PASSTHROUGH mode. // FPDF_PRINTMODE_POSTSCRIPT3_PASSTHROUGH to output level 3 // PostScript via ExtEscape() in PASSTHROUGH mode. // FPDF_PRINTMODE_EMF_IMAGE_MASKS to output EMF, with more // efficient processing of documents containing image masks. // FPDF_PRINTMODE_POSTSCRIPT3_TYPE42 to output level 3 // PostScript with embedded Type 42 fonts, when applicable, into // EMF as a series of GDI comments. // FPDF_PRINTMODE_POSTSCRIPT3_TYPE42_PASSTHROUGH to output level // 3 PostScript with embedded Type 42 fonts, when applicable, // via ExtEscape() in PASSTHROUGH mode. // Return value: // True if successful, false if unsuccessful (typically invalid input). FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_SetPrintMode(int mode); #endif // defined(_WIN32) // Function: FPDF_LoadDocument // Open and load a PDF document. // Parameters: // file_path - Path to the PDF file (including extension). // password - A string used as the password for the PDF file. // If no password is needed, empty or NULL can be used. // See comments below regarding the encoding. // Return value: // A handle to the loaded document, or NULL on failure. // Comments: // Loaded document can be closed by FPDF_CloseDocument(). // If this function fails, you can use FPDF_GetLastError() to retrieve // the reason why it failed. // // The encoding for |file_path| is UTF-8. // // The encoding for |password| can be either UTF-8 or Latin-1. PDFs, // depending on the security handler revision, will only accept one or // the other encoding. If |password|'s encoding and the PDF's expected // encoding do not match, FPDF_LoadDocument() will automatically // convert |password| to the other encoding. FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV FPDF_LoadDocument(FPDF_STRING file_path, FPDF_BYTESTRING password); // Function: FPDF_LoadMemDocument // Open and load a PDF document from memory. // Parameters: // data_buf - Pointer to a buffer containing the PDF document. // size - Number of bytes in the PDF document. // password - A string used as the password for the PDF file. // If no password is needed, empty or NULL can be used. // Return value: // A handle to the loaded document, or NULL on failure. // Comments: // The memory buffer must remain valid when the document is open. // The loaded document can be closed by FPDF_CloseDocument. // If this function fails, you can use FPDF_GetLastError() to retrieve // the reason why it failed. // // See the comments for FPDF_LoadDocument() regarding the encoding for // |password|. // Notes: // If PDFium is built with the XFA module, the application should call // FPDF_LoadXFA() function after the PDF document loaded to support XFA // fields defined in the fpdfformfill.h file. FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV FPDF_LoadMemDocument(const void* data_buf, int size, FPDF_BYTESTRING password); // Experimental API. // Function: FPDF_LoadMemDocument64 // Open and load a PDF document from memory. // Parameters: // data_buf - Pointer to a buffer containing the PDF document. // size - Number of bytes in the PDF document. // password - A string used as the password for the PDF file. // If no password is needed, empty or NULL can be used. // Return value: // A handle to the loaded document, or NULL on failure. // Comments: // The memory buffer must remain valid when the document is open. // The loaded document can be closed by FPDF_CloseDocument. // If this function fails, you can use FPDF_GetLastError() to retrieve // the reason why it failed. // // See the comments for FPDF_LoadDocument() regarding the encoding for // |password|. // Notes: // If PDFium is built with the XFA module, the application should call // FPDF_LoadXFA() function after the PDF document loaded to support XFA // fields defined in the fpdfformfill.h file. FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV FPDF_LoadMemDocument64(const void* data_buf, size_t size, FPDF_BYTESTRING password); // Structure for custom file access. typedef struct { // File length, in bytes. unsigned long m_FileLen; // A function pointer for getting a block of data from a specific position. // Position is specified by byte offset from the beginning of the file. // The pointer to the buffer is never NULL and the size is never 0. // The position and size will never go out of range of the file length. // It may be possible for PDFium to call this function multiple times for // the same position. // Return value: should be non-zero if successful, zero for error. int (*m_GetBlock)(void* param, unsigned long position, unsigned char* pBuf, unsigned long size); // A custom pointer for all implementation specific data. This pointer will // be used as the first parameter to the m_GetBlock callback. void* m_Param; } FPDF_FILEACCESS; // Structure for file reading or writing (I/O). // // Note: This is a handler and should be implemented by callers, // and is only used from XFA. typedef struct FPDF_FILEHANDLER_ { // User-defined data. // Note: Callers can use this field to track controls. void* clientData; // Callback function to release the current file stream object. // // Parameters: // clientData - Pointer to user-defined data. // Returns: // None. void (*Release)(void* clientData); // Callback function to retrieve the current file stream size. // // Parameters: // clientData - Pointer to user-defined data. // Returns: // Size of file stream. FPDF_DWORD (*GetSize)(void* clientData); // Callback function to read data from the current file stream. // // Parameters: // clientData - Pointer to user-defined data. // offset - Offset position starts from the beginning of file // stream. This parameter indicates reading position. // buffer - Memory buffer to store data which are read from // file stream. This parameter should not be NULL. // size - Size of data which should be read from file stream, // in bytes. The buffer indicated by |buffer| must be // large enough to store specified data. // Returns: // 0 for success, other value for failure. FPDF_RESULT (*ReadBlock)(void* clientData, FPDF_DWORD offset, void* buffer, FPDF_DWORD size); // Callback function to write data into the current file stream. // // Parameters: // clientData - Pointer to user-defined data. // offset - Offset position starts from the beginning of file // stream. This parameter indicates writing position. // buffer - Memory buffer contains data which is written into // file stream. This parameter should not be NULL. // size - Size of data which should be written into file // stream, in bytes. // Returns: // 0 for success, other value for failure. FPDF_RESULT (*WriteBlock)(void* clientData, FPDF_DWORD offset, const void* buffer, FPDF_DWORD size); // Callback function to flush all internal accessing buffers. // // Parameters: // clientData - Pointer to user-defined data. // Returns: // 0 for success, other value for failure. FPDF_RESULT (*Flush)(void* clientData); // Callback function to change file size. // // Description: // This function is called under writing mode usually. Implementer // can determine whether to realize it based on application requests. // Parameters: // clientData - Pointer to user-defined data. // size - New size of file stream, in bytes. // Returns: // 0 for success, other value for failure. FPDF_RESULT (*Truncate)(void* clientData, FPDF_DWORD size); } FPDF_FILEHANDLER; // Function: FPDF_LoadCustomDocument // Load PDF document from a custom access descriptor. // Parameters: // pFileAccess - A structure for accessing the file. // password - Optional password for decrypting the PDF file. // Return value: // A handle to the loaded document, or NULL on failure. // Comments: // The application must keep the file resources |pFileAccess| points to // valid until the returned FPDF_DOCUMENT is closed. |pFileAccess| // itself does not need to outlive the FPDF_DOCUMENT. // // The loaded document can be closed with FPDF_CloseDocument(). // // See the comments for FPDF_LoadDocument() regarding the encoding for // |password|. // Notes: // If PDFium is built with the XFA module, the application should call // FPDF_LoadXFA() function after the PDF document loaded to support XFA // fields defined in the fpdfformfill.h file. FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV FPDF_LoadCustomDocument(FPDF_FILEACCESS* pFileAccess, FPDF_BYTESTRING password); // Function: FPDF_GetFileVersion // Get the file version of the given PDF document. // Parameters: // doc - Handle to a document. // fileVersion - The PDF file version. File version: 14 for 1.4, 15 // for 1.5, ... // Return value: // True if succeeds, false otherwise. // Comments: // If the document was created by FPDF_CreateNewDocument, // then this function will always fail. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_GetFileVersion(FPDF_DOCUMENT doc, int* fileVersion); #define FPDF_ERR_SUCCESS 0 // No error. #define FPDF_ERR_UNKNOWN 1 // Unknown error. #define FPDF_ERR_FILE 2 // File not found or could not be opened. #define FPDF_ERR_FORMAT 3 // File not in PDF format or corrupted. #define FPDF_ERR_PASSWORD 4 // Password required or incorrect password. #define FPDF_ERR_SECURITY 5 // Unsupported security scheme. #define FPDF_ERR_PAGE 6 // Page not found or content error. #ifdef PDF_ENABLE_XFA #define FPDF_ERR_XFALOAD 7 // Load XFA error. #define FPDF_ERR_XFALAYOUT 8 // Layout XFA error. #endif // PDF_ENABLE_XFA // Function: FPDF_GetLastError // Get last error code when a function fails. // Parameters: // None. // Return value: // A 32-bit integer indicating error code as defined above. // Comments: // If the previous SDK call succeeded, the return value of this // function is not defined. This function only works in conjunction // with APIs that mention FPDF_GetLastError() in their documentation. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetLastError(); // Experimental API. // Function: FPDF_DocumentHasValidCrossReferenceTable // Whether the document's cross reference table is valid or not. // Parameters: // document - Handle to a document. Returned by FPDF_LoadDocument. // Return value: // True if the PDF parser did not encounter problems parsing the cross // reference table. False if the parser could not parse the cross // reference table and the table had to be rebuild from other data // within the document. // Comments: // The return value can change over time as the PDF parser evolves. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_DocumentHasValidCrossReferenceTable(FPDF_DOCUMENT document); // Experimental API. // Function: FPDF_GetTrailerEnds // Get the byte offsets of trailer ends. // Parameters: // document - Handle to document. Returned by FPDF_LoadDocument(). // buffer - The address of a buffer that receives the // byte offsets. // length - The size, in ints, of |buffer|. // Return value: // Returns the number of ints in the buffer on success, 0 on error. // // |buffer| is an array of integers that describes the exact byte offsets of the // trailer ends in the document. If |length| is less than the returned length, // or |document| or |buffer| is NULL, |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetTrailerEnds(FPDF_DOCUMENT document, unsigned int* buffer, unsigned long length); // Function: FPDF_GetDocPermissions // Get file permission flags of the document. // Parameters: // document - Handle to a document. Returned by FPDF_LoadDocument. // Return value: // A 32-bit integer indicating permission flags. Please refer to the // PDF Reference for detailed descriptions. If the document is not // protected or was unlocked by the owner, 0xffffffff will be returned. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetDocPermissions(FPDF_DOCUMENT document); // Function: FPDF_GetDocUserPermissions // Get user file permission flags of the document. // Parameters: // document - Handle to a document. Returned by FPDF_LoadDocument. // Return value: // A 32-bit integer indicating permission flags. Please refer to the // PDF Reference for detailed descriptions. If the document is not // protected, 0xffffffff will be returned. Always returns user // permissions, even if the document was unlocked by the owner. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetDocUserPermissions(FPDF_DOCUMENT document); // Function: FPDF_GetSecurityHandlerRevision // Get the revision for the security handler. // Parameters: // document - Handle to a document. Returned by FPDF_LoadDocument. // Return value: // The security handler revision number. Please refer to the PDF // Reference for a detailed description. If the document is not // protected, -1 will be returned. FPDF_EXPORT int FPDF_CALLCONV FPDF_GetSecurityHandlerRevision(FPDF_DOCUMENT document); // Function: FPDF_GetPageCount // Get total number of pages in the document. // Parameters: // document - Handle to document. Returned by FPDF_LoadDocument. // Return value: // Total number of pages in the document. FPDF_EXPORT int FPDF_CALLCONV FPDF_GetPageCount(FPDF_DOCUMENT document); // Function: FPDF_LoadPage // Load a page inside the document. // Parameters: // document - Handle to document. Returned by FPDF_LoadDocument // page_index - Index number of the page. 0 for the first page. // Return value: // A handle to the loaded page, or NULL if page load fails. // Comments: // The loaded page can be rendered to devices using FPDF_RenderPage. // The loaded page can be closed using FPDF_ClosePage. FPDF_EXPORT FPDF_PAGE FPDF_CALLCONV FPDF_LoadPage(FPDF_DOCUMENT document, int page_index); // Experimental API // Function: FPDF_GetPageWidthF // Get page width. // Parameters: // page - Handle to the page. Returned by FPDF_LoadPage(). // Return value: // Page width (excluding non-displayable area) measured in points. // One point is 1/72 inch (around 0.3528 mm). // Comments: // Changing the rotation of |page| affects the return value. FPDF_EXPORT float FPDF_CALLCONV FPDF_GetPageWidthF(FPDF_PAGE page); // Function: FPDF_GetPageWidth // Get page width. // Parameters: // page - Handle to the page. Returned by FPDF_LoadPage. // Return value: // Page width (excluding non-displayable area) measured in points. // One point is 1/72 inch (around 0.3528 mm). // Note: // Prefer FPDF_GetPageWidthF() above. This will be deprecated in the // future. // Comments: // Changing the rotation of |page| affects the return value. FPDF_EXPORT double FPDF_CALLCONV FPDF_GetPageWidth(FPDF_PAGE page); // Experimental API // Function: FPDF_GetPageHeightF // Get page height. // Parameters: // page - Handle to the page. Returned by FPDF_LoadPage(). // Return value: // Page height (excluding non-displayable area) measured in points. // One point is 1/72 inch (around 0.3528 mm) // Comments: // Changing the rotation of |page| affects the return value. FPDF_EXPORT float FPDF_CALLCONV FPDF_GetPageHeightF(FPDF_PAGE page); // Function: FPDF_GetPageHeight // Get page height. // Parameters: // page - Handle to the page. Returned by FPDF_LoadPage. // Return value: // Page height (excluding non-displayable area) measured in points. // One point is 1/72 inch (around 0.3528 mm) // Note: // Prefer FPDF_GetPageHeightF() above. This will be deprecated in the // future. // Comments: // Changing the rotation of |page| affects the return value. FPDF_EXPORT double FPDF_CALLCONV FPDF_GetPageHeight(FPDF_PAGE page); // Experimental API. // Function: FPDF_GetPageBoundingBox // Get the bounding box of the page. This is the intersection between // its media box and its crop box. // Parameters: // page - Handle to the page. Returned by FPDF_LoadPage. // rect - Pointer to a rect to receive the page bounding box. // On an error, |rect| won't be filled. // Return value: // True for success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_GetPageBoundingBox(FPDF_PAGE page, FS_RECTF* rect); // Experimental API. // Function: FPDF_GetPageSizeByIndexF // Get the size of the page at the given index. // Parameters: // document - Handle to document. Returned by FPDF_LoadDocument(). // page_index - Page index, zero for the first page. // size - Pointer to a FS_SIZEF to receive the page size. // (in points). // Return value: // Non-zero for success. 0 for error (document or page not found). FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_GetPageSizeByIndexF(FPDF_DOCUMENT document, int page_index, FS_SIZEF* size); // Function: FPDF_GetPageSizeByIndex // Get the size of the page at the given index. // Parameters: // document - Handle to document. Returned by FPDF_LoadDocument. // page_index - Page index, zero for the first page. // width - Pointer to a double to receive the page width // (in points). // height - Pointer to a double to receive the page height // (in points). // Return value: // Non-zero for success. 0 for error (document or page not found). // Note: // Prefer FPDF_GetPageSizeByIndexF() above. This will be deprecated in // the future. FPDF_EXPORT int FPDF_CALLCONV FPDF_GetPageSizeByIndex(FPDF_DOCUMENT document, int page_index, double* width, double* height); // Page rendering flags. They can be combined with bit-wise OR. // // Set if annotations are to be rendered. #define FPDF_ANNOT 0x01 // Set if using text rendering optimized for LCD display. This flag will only // take effect if anti-aliasing is enabled for text. #define FPDF_LCD_TEXT 0x02 // Don't use the native text output available on some platforms #define FPDF_NO_NATIVETEXT 0x04 // Grayscale output. #define FPDF_GRAYSCALE 0x08 // Obsolete, has no effect, retained for compatibility. #define FPDF_DEBUG_INFO 0x80 // Obsolete, has no effect, retained for compatibility. #define FPDF_NO_CATCH 0x100 // Limit image cache size. #define FPDF_RENDER_LIMITEDIMAGECACHE 0x200 // Always use halftone for image stretching. #define FPDF_RENDER_FORCEHALFTONE 0x400 // Render for printing. #define FPDF_PRINTING 0x800 // Set to disable anti-aliasing on text. This flag will also disable LCD // optimization for text rendering. #define FPDF_RENDER_NO_SMOOTHTEXT 0x1000 // Set to disable anti-aliasing on images. #define FPDF_RENDER_NO_SMOOTHIMAGE 0x2000 // Set to disable anti-aliasing on paths. #define FPDF_RENDER_NO_SMOOTHPATH 0x4000 // Set whether to render in a reverse Byte order, this flag is only used when // rendering to a bitmap. #define FPDF_REVERSE_BYTE_ORDER 0x10 // Set whether fill paths need to be stroked. This flag is only used when // FPDF_COLORSCHEME is passed in, since with a single fill color for paths the // boundaries of adjacent fill paths are less visible. #define FPDF_CONVERT_FILL_TO_STROKE 0x20 // Struct for color scheme. // Each should be a 32-bit value specifying the color, in 8888 ARGB format. typedef struct FPDF_COLORSCHEME_ { FPDF_DWORD path_fill_color; FPDF_DWORD path_stroke_color; FPDF_DWORD text_fill_color; FPDF_DWORD text_stroke_color; } FPDF_COLORSCHEME; #ifdef _WIN32 // Function: FPDF_RenderPage // Render contents of a page to a device (screen, bitmap, or printer). // This function is only supported on Windows. // Parameters: // dc - Handle to the device context. // page - Handle to the page. Returned by FPDF_LoadPage. // start_x - Left pixel position of the display area in // device coordinates. // start_y - Top pixel position of the display area in device // coordinates. // size_x - Horizontal size (in pixels) for displaying the page. // size_y - Vertical size (in pixels) for displaying the page. // rotate - Page orientation: // 0 (normal) // 1 (rotated 90 degrees clockwise) // 2 (rotated 180 degrees) // 3 (rotated 90 degrees counter-clockwise) // flags - 0 for normal display, or combination of flags // defined above. // Return value: // Returns true if the page is rendered successfully, false otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_RenderPage(HDC dc, FPDF_PAGE page, int start_x, int start_y, int size_x, int size_y, int rotate, int flags); #endif // Function: FPDF_RenderPageBitmap // Render contents of a page to a device independent bitmap. // Parameters: // bitmap - Handle to the device independent bitmap (as the // output buffer). The bitmap handle can be created // by FPDFBitmap_Create or retrieved from an image // object by FPDFImageObj_GetBitmap. // page - Handle to the page. Returned by FPDF_LoadPage // start_x - Left pixel position of the display area in // bitmap coordinates. // start_y - Top pixel position of the display area in bitmap // coordinates. // size_x - Horizontal size (in pixels) for displaying the page. // size_y - Vertical size (in pixels) for displaying the page. // rotate - Page orientation: // 0 (normal) // 1 (rotated 90 degrees clockwise) // 2 (rotated 180 degrees) // 3 (rotated 90 degrees counter-clockwise) // flags - 0 for normal display, or combination of the Page // Rendering flags defined above. With the FPDF_ANNOT // flag, it renders all annotations that do not require // user-interaction, which are all annotations except // widget and popup annotations. // Return value: // None. FPDF_EXPORT void FPDF_CALLCONV FPDF_RenderPageBitmap(FPDF_BITMAP bitmap, FPDF_PAGE page, int start_x, int start_y, int size_x, int size_y, int rotate, int flags); // Function: FPDF_RenderPageBitmapWithMatrix // Render contents of a page to a device independent bitmap. // Parameters: // bitmap - Handle to the device independent bitmap (as the // output buffer). The bitmap handle can be created // by FPDFBitmap_Create or retrieved by // FPDFImageObj_GetBitmap. // page - Handle to the page. Returned by FPDF_LoadPage. // matrix - The transform matrix, which must be invertible. // See PDF Reference 1.7, 4.2.2 Common Transformations. // clipping - The rect to clip to in device coords. // flags - 0 for normal display, or combination of the Page // Rendering flags defined above. With the FPDF_ANNOT // flag, it renders all annotations that do not require // user-interaction, which are all annotations except // widget and popup annotations. // Return value: // None. Note that behavior is undefined if det of |matrix| is 0. FPDF_EXPORT void FPDF_CALLCONV FPDF_RenderPageBitmapWithMatrix(FPDF_BITMAP bitmap, FPDF_PAGE page, const FS_MATRIX* matrix, const FS_RECTF* clipping, int flags); #if defined(PDF_USE_SKIA) // Experimental API. // Function: FPDF_RenderPageSkia // Render contents of a page to a Skia SkCanvas. // Parameters: // canvas - SkCanvas to render to. // page - Handle to the page. // size_x - Horizontal size (in pixels) for displaying the page. // size_y - Vertical size (in pixels) for displaying the page. // Return value: // None. FPDF_EXPORT void FPDF_CALLCONV FPDF_RenderPageSkia(FPDF_SKIA_CANVAS canvas, FPDF_PAGE page, int size_x, int size_y); #endif // Function: FPDF_ClosePage // Close a loaded PDF page. // Parameters: // page - Handle to the loaded page. // Return value: // None. FPDF_EXPORT void FPDF_CALLCONV FPDF_ClosePage(FPDF_PAGE page); // Function: FPDF_CloseDocument // Close a loaded PDF document. // Parameters: // document - Handle to the loaded document. // Return value: // None. FPDF_EXPORT void FPDF_CALLCONV FPDF_CloseDocument(FPDF_DOCUMENT document); // Function: FPDF_DeviceToPage // Convert the screen coordinates of a point to page coordinates. // Parameters: // page - Handle to the page. Returned by FPDF_LoadPage. // start_x - Left pixel position of the display area in // device coordinates. // start_y - Top pixel position of the display area in device // coordinates. // size_x - Horizontal size (in pixels) for displaying the page. // size_y - Vertical size (in pixels) for displaying the page. // rotate - Page orientation: // 0 (normal) // 1 (rotated 90 degrees clockwise) // 2 (rotated 180 degrees) // 3 (rotated 90 degrees counter-clockwise) // device_x - X value in device coordinates to be converted. // device_y - Y value in device coordinates to be converted. // page_x - A pointer to a double receiving the converted X // value in page coordinates. // page_y - A pointer to a double receiving the converted Y // value in page coordinates. // Return value: // Returns true if the conversion succeeds, and |page_x| and |page_y| // successfully receives the converted coordinates. // Comments: // The page coordinate system has its origin at the left-bottom corner // of the page, with the X-axis on the bottom going to the right, and // the Y-axis on the left side going up. // // NOTE: this coordinate system can be altered when you zoom, scroll, // or rotate a page, however, a point on the page should always have // the same coordinate values in the page coordinate system. // // The device coordinate system is device dependent. For screen device, // its origin is at the left-top corner of the window. However this // origin can be altered by the Windows coordinate transformation // utilities. // // You must make sure the start_x, start_y, size_x, size_y // and rotate parameters have exactly same values as you used in // the FPDF_RenderPage() function call. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_DeviceToPage(FPDF_PAGE page, int start_x, int start_y, int size_x, int size_y, int rotate, int device_x, int device_y, double* page_x, double* page_y); // Function: FPDF_PageToDevice // Convert the page coordinates of a point to screen coordinates. // Parameters: // page - Handle to the page. Returned by FPDF_LoadPage. // start_x - Left pixel position of the display area in // device coordinates. // start_y - Top pixel position of the display area in device // coordinates. // size_x - Horizontal size (in pixels) for displaying the page. // size_y - Vertical size (in pixels) for displaying the page. // rotate - Page orientation: // 0 (normal) // 1 (rotated 90 degrees clockwise) // 2 (rotated 180 degrees) // 3 (rotated 90 degrees counter-clockwise) // page_x - X value in page coordinates. // page_y - Y value in page coordinate. // device_x - A pointer to an integer receiving the result X // value in device coordinates. // device_y - A pointer to an integer receiving the result Y // value in device coordinates. // Return value: // Returns true if the conversion succeeds, and |device_x| and // |device_y| successfully receives the converted coordinates. // Comments: // See comments for FPDF_DeviceToPage(). FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_PageToDevice(FPDF_PAGE page, int start_x, int start_y, int size_x, int size_y, int rotate, double page_x, double page_y, int* device_x, int* device_y); // Function: FPDFBitmap_Create // Create a device independent bitmap (FXDIB). // Parameters: // width - The number of pixels in width for the bitmap. // Must be greater than 0. // height - The number of pixels in height for the bitmap. // Must be greater than 0. // alpha - A flag indicating whether the alpha channel is used. // Non-zero for using alpha, zero for not using. // Return value: // The created bitmap handle, or NULL if a parameter error or out of // memory. // Comments: // The bitmap always uses 4 bytes per pixel. The first byte is always // double word aligned. // // The byte order is BGRx (the last byte unused if no alpha channel) or // BGRA. // // The pixels in a horizontal line are stored side by side, with the // left most pixel stored first (with lower memory address). // Each line uses width * 4 bytes. // // Lines are stored one after another, with the top most line stored // first. There is no gap between adjacent lines. // // This function allocates enough memory for holding all pixels in the // bitmap, but it doesn't initialize the buffer. Applications can use // FPDFBitmap_FillRect() to fill the bitmap using any color. If the OS // allows it, this function can allocate up to 4 GB of memory. FPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV FPDFBitmap_Create(int width, int height, int alpha); // More DIB formats // Unknown or unsupported format. // All of the colors are listed in order of LSB to MSB. #define FPDFBitmap_Unknown 0 // Gray scale bitmap, one byte per pixel. #define FPDFBitmap_Gray 1 // 3 bytes per pixel, byte order: blue, green, red. #define FPDFBitmap_BGR 2 // 4 bytes per pixel, byte order: blue, green, red, unused. #define FPDFBitmap_BGRx 3 // 4 bytes per pixel, byte order: blue, green, red, alpha. // Pixel components are independent of alpha. #define FPDFBitmap_BGRA 4 // 4 bytes per pixel, byte order: blue, green, red, alpha. // Pixel components are premultiplied by alpha. // Note that this is experimental and only supported when rendering with // |FPDF_RENDERER_TYPE| is set to |FPDF_RENDERERTYPE_SKIA|. #define FPDFBitmap_BGRA_Premul 5 // Function: FPDFBitmap_CreateEx // Create a device independent bitmap (FXDIB) // Parameters: // width - The number of pixels in width for the bitmap. // Must be greater than 0. // height - The number of pixels in height for the bitmap. // Must be greater than 0. // format - A number indicating for bitmap format, as defined // above. // first_scan - A pointer to the first byte of the first line if // using an external buffer. If this parameter is NULL, // then a new buffer will be created. // stride - Number of bytes for each scan line. The value must // be 0 or greater. When the value is 0, // FPDFBitmap_CreateEx() will automatically calculate // the appropriate value using |width| and |format|. // When using an external buffer, it is recommended for // the caller to pass in the value. // When not using an external buffer, it is recommended // for the caller to pass in 0. // Return value: // The bitmap handle, or NULL if parameter error or out of memory. // Comments: // Similar to FPDFBitmap_Create function, but allows for more formats // and an external buffer is supported. The bitmap created by this // function can be used in any place that a FPDF_BITMAP handle is // required. // // If an external buffer is used, then the caller should destroy the // buffer. FPDFBitmap_Destroy() will not destroy the buffer. // // It is recommended to use FPDFBitmap_GetStride() to get the stride // value. FPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV FPDFBitmap_CreateEx(int width, int height, int format, void* first_scan, int stride); // Function: FPDFBitmap_GetFormat // Get the format of the bitmap. // Parameters: // bitmap - Handle to the bitmap. Returned by FPDFBitmap_Create // or FPDFImageObj_GetBitmap. // Return value: // The format of the bitmap. // Comments: // Only formats supported by FPDFBitmap_CreateEx are supported by this // function; see the list of such formats above. FPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetFormat(FPDF_BITMAP bitmap); // Function: FPDFBitmap_FillRect // Fill a rectangle in a bitmap. // Parameters: // bitmap - The handle to the bitmap. Returned by // FPDFBitmap_Create. // left - The left position. Starting from 0 at the // left-most pixel. // top - The top position. Starting from 0 at the // top-most line. // width - Width in pixels to be filled. // height - Height in pixels to be filled. // color - A 32-bit value specifing the color, in 8888 ARGB // format. // Return value: // Returns whether the operation succeeded or not. // Comments: // This function sets the color and (optionally) alpha value in the // specified region of the bitmap. // // NOTE: If the alpha channel is used, this function does NOT // composite the background with the source color, instead the // background will be replaced by the source color and the alpha. // // If the alpha channel is not used, the alpha parameter is ignored. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFBitmap_FillRect(FPDF_BITMAP bitmap, int left, int top, int width, int height, FPDF_DWORD color); // Function: FPDFBitmap_GetBuffer // Get data buffer of a bitmap. // Parameters: // bitmap - Handle to the bitmap. Returned by FPDFBitmap_Create // or FPDFImageObj_GetBitmap. // Return value: // The pointer to the first byte of the bitmap buffer. // Comments: // The stride may be more than width * number of bytes per pixel // // Applications can use this function to get the bitmap buffer pointer, // then manipulate any color and/or alpha values for any pixels in the // bitmap. // // Use FPDFBitmap_GetFormat() to find out the format of the data. FPDF_EXPORT void* FPDF_CALLCONV FPDFBitmap_GetBuffer(FPDF_BITMAP bitmap); // Function: FPDFBitmap_GetWidth // Get width of a bitmap. // Parameters: // bitmap - Handle to the bitmap. Returned by FPDFBitmap_Create // or FPDFImageObj_GetBitmap. // Return value: // The width of the bitmap in pixels. FPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetWidth(FPDF_BITMAP bitmap); // Function: FPDFBitmap_GetHeight // Get height of a bitmap. // Parameters: // bitmap - Handle to the bitmap. Returned by FPDFBitmap_Create // or FPDFImageObj_GetBitmap. // Return value: // The height of the bitmap in pixels. FPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetHeight(FPDF_BITMAP bitmap); // Function: FPDFBitmap_GetStride // Get number of bytes for each line in the bitmap buffer. // Parameters: // bitmap - Handle to the bitmap. Returned by FPDFBitmap_Create // or FPDFImageObj_GetBitmap. // Return value: // The number of bytes for each line in the bitmap buffer. // Comments: // The stride may be more than width * number of bytes per pixel. FPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetStride(FPDF_BITMAP bitmap); // Function: FPDFBitmap_Destroy // Destroy a bitmap and release all related buffers. // Parameters: // bitmap - Handle to the bitmap. Returned by FPDFBitmap_Create // or FPDFImageObj_GetBitmap. // Return value: // None. // Comments: // This function will not destroy any external buffers provided when // the bitmap was created. FPDF_EXPORT void FPDF_CALLCONV FPDFBitmap_Destroy(FPDF_BITMAP bitmap); // Function: FPDF_VIEWERREF_GetPrintScaling // Whether the PDF document prefers to be scaled or not. // Parameters: // document - Handle to the loaded document. // Return value: // None. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_VIEWERREF_GetPrintScaling(FPDF_DOCUMENT document); // Function: FPDF_VIEWERREF_GetNumCopies // Returns the number of copies to be printed. // Parameters: // document - Handle to the loaded document. // Return value: // The number of copies to be printed. FPDF_EXPORT int FPDF_CALLCONV FPDF_VIEWERREF_GetNumCopies(FPDF_DOCUMENT document); // Function: FPDF_VIEWERREF_GetPrintPageRange // Page numbers to initialize print dialog box when file is printed. // Parameters: // document - Handle to the loaded document. // Return value: // The print page range to be used for printing. FPDF_EXPORT FPDF_PAGERANGE FPDF_CALLCONV FPDF_VIEWERREF_GetPrintPageRange(FPDF_DOCUMENT document); // Experimental API. // Function: FPDF_VIEWERREF_GetPrintPageRangeCount // Returns the number of elements in a FPDF_PAGERANGE. // Parameters: // pagerange - Handle to the page range. // Return value: // The number of elements in the page range. Returns 0 on error. FPDF_EXPORT size_t FPDF_CALLCONV FPDF_VIEWERREF_GetPrintPageRangeCount(FPDF_PAGERANGE pagerange); // Experimental API. // Function: FPDF_VIEWERREF_GetPrintPageRangeElement // Returns an element from a FPDF_PAGERANGE. // Parameters: // pagerange - Handle to the page range. // index - Index of the element. // Return value: // The value of the element in the page range at a given index. // Returns -1 on error. FPDF_EXPORT int FPDF_CALLCONV FPDF_VIEWERREF_GetPrintPageRangeElement(FPDF_PAGERANGE pagerange, size_t index); // Function: FPDF_VIEWERREF_GetDuplex // Returns the paper handling option to be used when printing from // the print dialog. // Parameters: // document - Handle to the loaded document. // Return value: // The paper handling option to be used when printing. FPDF_EXPORT FPDF_DUPLEXTYPE FPDF_CALLCONV FPDF_VIEWERREF_GetDuplex(FPDF_DOCUMENT document); // Function: FPDF_VIEWERREF_GetName // Gets the contents for a viewer ref, with a given key. The value must // be of type "name". // Parameters: // document - Handle to the loaded document. // key - Name of the key in the viewer pref dictionary, // encoded in UTF-8. // buffer - Caller-allocate buffer to receive the key, or NULL // - to query the required length. // length - Length of the buffer. // Return value: // The number of bytes in the contents, including the NULL terminator. // Thus if the return value is 0, then that indicates an error, such // as when |document| is invalid. If |length| is less than the required // length, or |buffer| is NULL, |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_VIEWERREF_GetName(FPDF_DOCUMENT document, FPDF_BYTESTRING key, char* buffer, unsigned long length); // Function: FPDF_CountNamedDests // Get the count of named destinations in the PDF document. // Parameters: // document - Handle to a document // Return value: // The count of named destinations. FPDF_EXPORT FPDF_DWORD FPDF_CALLCONV FPDF_CountNamedDests(FPDF_DOCUMENT document); // Function: FPDF_GetNamedDestByName // Get a the destination handle for the given name. // Parameters: // document - Handle to the loaded document. // name - The name of a destination. // Return value: // The handle to the destination. FPDF_EXPORT FPDF_DEST FPDF_CALLCONV FPDF_GetNamedDestByName(FPDF_DOCUMENT document, FPDF_BYTESTRING name); // Function: FPDF_GetNamedDest // Get the named destination by index. // Parameters: // document - Handle to a document // index - The index of a named destination. // buffer - The buffer to store the destination name, // used as wchar_t*. // buflen [in/out] - Size of the buffer in bytes on input, // length of the result in bytes on output // or -1 if the buffer is too small. // Return value: // The destination handle for a given index, or NULL if there is no // named destination corresponding to |index|. // Comments: // Call this function twice to get the name of the named destination: // 1) First time pass in |buffer| as NULL and get buflen. // 2) Second time pass in allocated |buffer| and buflen to retrieve // |buffer|, which should be used as wchar_t*. // // If buflen is not sufficiently large, it will be set to -1 upon // return. FPDF_EXPORT FPDF_DEST FPDF_CALLCONV FPDF_GetNamedDest(FPDF_DOCUMENT document, int index, void* buffer, long* buflen); // Experimental API. // Function: FPDF_GetXFAPacketCount // Get the number of valid packets in the XFA entry. // Parameters: // document - Handle to the document. // Return value: // The number of valid packets, or -1 on error. FPDF_EXPORT int FPDF_CALLCONV FPDF_GetXFAPacketCount(FPDF_DOCUMENT document); // Experimental API. // Function: FPDF_GetXFAPacketName // Get the name of a packet in the XFA array. // Parameters: // document - Handle to the document. // index - Index number of the packet. 0 for the first packet. // buffer - Buffer for holding the name of the XFA packet. // buflen - Length of |buffer| in bytes. // Return value: // The length of the packet name in bytes, or 0 on error. // // |document| must be valid and |index| must be in the range [0, N), where N is // the value returned by FPDF_GetXFAPacketCount(). // |buffer| is only modified if it is non-NULL and |buflen| is greater than or // equal to the length of the packet name. The packet name includes a // terminating NUL character. |buffer| is unmodified on error. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetXFAPacketName( FPDF_DOCUMENT document, int index, void* buffer, unsigned long buflen); // Experimental API. // Function: FPDF_GetXFAPacketContent // Get the content of a packet in the XFA array. // Parameters: // document - Handle to the document. // index - Index number of the packet. 0 for the first packet. // buffer - Buffer for holding the content of the XFA packet. // buflen - Length of |buffer| in bytes. // out_buflen - Pointer to the variable that will receive the minimum // buffer size needed to contain the content of the XFA // packet. // Return value: // Whether the operation succeeded or not. // // |document| must be valid and |index| must be in the range [0, N), where N is // the value returned by FPDF_GetXFAPacketCount(). |out_buflen| must not be // NULL. When the aforementioned arguments are valid, the operation succeeds, // and |out_buflen| receives the content size. |buffer| is only modified if // |buffer| is non-null and long enough to contain the content. Callers must // check both the return value and the input |buflen| is no less than the // returned |out_buflen| before using the data in |buffer|. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_GetXFAPacketContent( FPDF_DOCUMENT document, int index, void* buffer, unsigned long buflen, unsigned long* out_buflen); #ifdef PDF_ENABLE_V8 // Function: FPDF_GetRecommendedV8Flags // Returns a space-separated string of command line flags that are // recommended to be passed into V8 via V8::SetFlagsFromString() // prior to initializing the PDFium library. // Parameters: // None. // Return value: // NUL-terminated string of the form "--flag1 --flag2". // The caller must not attempt to modify or free the result. FPDF_EXPORT const char* FPDF_CALLCONV FPDF_GetRecommendedV8Flags(); // Experimental API. // Function: FPDF_GetArrayBufferAllocatorSharedInstance() // Helper function for initializing V8 isolates that will // use PDFium's internal memory management. // Parameters: // None. // Return Value: // Pointer to a suitable v8::ArrayBuffer::Allocator, returned // as void for C compatibility. // Notes: // Use is optional, but allows external creation of isolates // matching the ones PDFium will make when none is provided // via |FPDF_LIBRARY_CONFIG::m_pIsolate|. // // Can only be called when the library is in an uninitialized or // destroyed state. FPDF_EXPORT void* FPDF_CALLCONV FPDF_GetArrayBufferAllocatorSharedInstance(); #endif // PDF_ENABLE_V8 #ifdef PDF_ENABLE_XFA // Function: FPDF_BStr_Init // Helper function to initialize a FPDF_BSTR. FPDF_EXPORT FPDF_RESULT FPDF_CALLCONV FPDF_BStr_Init(FPDF_BSTR* bstr); // Function: FPDF_BStr_Set // Helper function to copy string data into the FPDF_BSTR. FPDF_EXPORT FPDF_RESULT FPDF_CALLCONV FPDF_BStr_Set(FPDF_BSTR* bstr, const char* cstr, int length); // Function: FPDF_BStr_Clear // Helper function to clear a FPDF_BSTR. FPDF_EXPORT FPDF_RESULT FPDF_CALLCONV FPDF_BStr_Clear(FPDF_BSTR* bstr); #endif // PDF_ENABLE_XFA #ifdef __cplusplus } #endif #endif // PUBLIC_FPDFVIEW_H_ ================================================ FILE: external/pdfium/macos-arm64/include/fpdfview.h.orig ================================================ // Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com // This is the main header file for embedders of PDFium. It provides APIs to // initialize the library, load documents, and render pages, amongst other // things. // // NOTE: None of the PDFium APIs are thread-safe. They expect to be called // from a single thread. Barring that, embedders are required to ensure (via // a mutex or similar) that only a single PDFium call can be made at a time. // // NOTE: External docs refer to this file as "fpdfview.h", so do not rename // despite lack of consistency with other public files. #ifndef PUBLIC_FPDFVIEW_H_ #define PUBLIC_FPDFVIEW_H_ // clang-format off #include #if defined(_WIN32) && !defined(__WINDOWS__) #include #endif #ifdef PDF_ENABLE_XFA // PDF_USE_XFA is set in confirmation that this version of PDFium can support // XFA forms as requested by the PDF_ENABLE_XFA setting. #define PDF_USE_XFA #endif // PDF_ENABLE_XFA // PDF object types #define FPDF_OBJECT_UNKNOWN 0 #define FPDF_OBJECT_BOOLEAN 1 #define FPDF_OBJECT_NUMBER 2 #define FPDF_OBJECT_STRING 3 #define FPDF_OBJECT_NAME 4 #define FPDF_OBJECT_ARRAY 5 #define FPDF_OBJECT_DICTIONARY 6 #define FPDF_OBJECT_STREAM 7 #define FPDF_OBJECT_NULLOBJ 8 #define FPDF_OBJECT_REFERENCE 9 // PDF text rendering modes typedef enum { FPDF_TEXTRENDERMODE_UNKNOWN = -1, FPDF_TEXTRENDERMODE_FILL = 0, FPDF_TEXTRENDERMODE_STROKE = 1, FPDF_TEXTRENDERMODE_FILL_STROKE = 2, FPDF_TEXTRENDERMODE_INVISIBLE = 3, FPDF_TEXTRENDERMODE_FILL_CLIP = 4, FPDF_TEXTRENDERMODE_STROKE_CLIP = 5, FPDF_TEXTRENDERMODE_FILL_STROKE_CLIP = 6, FPDF_TEXTRENDERMODE_CLIP = 7, FPDF_TEXTRENDERMODE_LAST = FPDF_TEXTRENDERMODE_CLIP, } FPDF_TEXT_RENDERMODE; // PDF types - use incomplete types (never completed) to force API type safety. typedef struct fpdf_action_t__* FPDF_ACTION; typedef struct fpdf_annotation_t__* FPDF_ANNOTATION; typedef struct fpdf_attachment_t__* FPDF_ATTACHMENT; typedef struct fpdf_avail_t__* FPDF_AVAIL; typedef struct fpdf_bitmap_t__* FPDF_BITMAP; typedef struct fpdf_bookmark_t__* FPDF_BOOKMARK; typedef struct fpdf_clippath_t__* FPDF_CLIPPATH; typedef struct fpdf_dest_t__* FPDF_DEST; typedef struct fpdf_document_t__* FPDF_DOCUMENT; typedef struct fpdf_font_t__* FPDF_FONT; typedef struct fpdf_form_handle_t__* FPDF_FORMHANDLE; typedef const struct fpdf_glyphpath_t__* FPDF_GLYPHPATH; typedef struct fpdf_javascript_action_t* FPDF_JAVASCRIPT_ACTION; typedef struct fpdf_link_t__* FPDF_LINK; typedef struct fpdf_page_t__* FPDF_PAGE; typedef struct fpdf_pagelink_t__* FPDF_PAGELINK; typedef struct fpdf_pageobject_t__* FPDF_PAGEOBJECT; // (text, path, etc.) typedef struct fpdf_pageobjectmark_t__* FPDF_PAGEOBJECTMARK; typedef const struct fpdf_pagerange_t__* FPDF_PAGERANGE; typedef const struct fpdf_pathsegment_t* FPDF_PATHSEGMENT; typedef struct fpdf_schhandle_t__* FPDF_SCHHANDLE; typedef const struct fpdf_signature_t__* FPDF_SIGNATURE; typedef void* FPDF_SKIA_CANVAS; // Passed into Skia as an SkCanvas. typedef struct fpdf_structelement_t__* FPDF_STRUCTELEMENT; typedef const struct fpdf_structelement_attr_t__* FPDF_STRUCTELEMENT_ATTR; typedef const struct fpdf_structelement_attr_value_t__* FPDF_STRUCTELEMENT_ATTR_VALUE; typedef struct fpdf_structtree_t__* FPDF_STRUCTTREE; typedef struct fpdf_textpage_t__* FPDF_TEXTPAGE; typedef struct fpdf_widget_t__* FPDF_WIDGET; typedef struct fpdf_xobject_t__* FPDF_XOBJECT; // Basic data types typedef int FPDF_BOOL; typedef int FPDF_RESULT; typedef unsigned long FPDF_DWORD; typedef float FS_FLOAT; // Duplex types typedef enum _FPDF_DUPLEXTYPE_ { DuplexUndefined = 0, Simplex, DuplexFlipShortEdge, DuplexFlipLongEdge } FPDF_DUPLEXTYPE; // String types typedef unsigned short FPDF_WCHAR; // The public PDFium API uses three types of strings: byte string, wide string // (UTF-16LE encoded), and platform dependent string. // Public PDFium API type for byte strings. typedef const char* FPDF_BYTESTRING; // The public PDFium API always uses UTF-16LE encoded wide strings, each // character uses 2 bytes (except surrogation), with the low byte first. typedef const FPDF_WCHAR* FPDF_WIDESTRING; // Structure for persisting a string beyond the duration of a callback. // Note: although represented as a char*, string may be interpreted as // a UTF-16LE formated string. Used only by XFA callbacks. typedef struct FPDF_BSTR_ { char* str; // String buffer, manipulate only with FPDF_BStr_* methods. int len; // Length of the string, in bytes. } FPDF_BSTR; // For Windows programmers: In most cases it's OK to treat FPDF_WIDESTRING as a // Windows unicode string, however, special care needs to be taken if you // expect to process Unicode larger than 0xffff. // // For Linux/Unix programmers: most compiler/library environments use 4 bytes // for a Unicode character, and you have to convert between FPDF_WIDESTRING and // system wide string by yourself. typedef const char* FPDF_STRING; // Matrix for transformation, in the form [a b c d e f], equivalent to: // | a b 0 | // | c d 0 | // | e f 1 | // // Translation is performed with [1 0 0 1 tx ty]. // Scaling is performed with [sx 0 0 sy 0 0]. // See PDF Reference 1.7, 4.2.2 Common Transformations for more. typedef struct _FS_MATRIX_ { float a; float b; float c; float d; float e; float f; } FS_MATRIX; // Rectangle area(float) in device or page coordinate system. typedef struct _FS_RECTF_ { // The x-coordinate of the left-top corner. float left; // The y-coordinate of the left-top corner. float top; // The x-coordinate of the right-bottom corner. float right; // The y-coordinate of the right-bottom corner. float bottom; } * FS_LPRECTF, FS_RECTF; // Const Pointer to FS_RECTF structure. typedef const FS_RECTF* FS_LPCRECTF; // Rectangle size. Coordinate system agnostic. typedef struct FS_SIZEF_ { float width; float height; } * FS_LPSIZEF, FS_SIZEF; // Const Pointer to FS_SIZEF structure. typedef const FS_SIZEF* FS_LPCSIZEF; // 2D Point. Coordinate system agnostic. typedef struct FS_POINTF_ { float x; float y; } * FS_LPPOINTF, FS_POINTF; // Const Pointer to FS_POINTF structure. typedef const FS_POINTF* FS_LPCPOINTF; typedef struct _FS_QUADPOINTSF { FS_FLOAT x1; FS_FLOAT y1; FS_FLOAT x2; FS_FLOAT y2; FS_FLOAT x3; FS_FLOAT y3; FS_FLOAT x4; FS_FLOAT y4; } FS_QUADPOINTSF; // Annotation enums. typedef int FPDF_ANNOTATION_SUBTYPE; typedef int FPDF_ANNOT_APPEARANCEMODE; // Dictionary value types. typedef int FPDF_OBJECT_TYPE; #if defined(COMPONENT_BUILD) // FPDF_EXPORT should be consistent with |export| in the pdfium_fuzzer // template in testing/fuzzers/BUILD.gn. #if defined(WIN32) #if defined(FPDF_IMPLEMENTATION) #define FPDF_EXPORT __declspec(dllexport) #else #define FPDF_EXPORT __declspec(dllimport) #endif // defined(FPDF_IMPLEMENTATION) #else #if defined(FPDF_IMPLEMENTATION) #define FPDF_EXPORT __attribute__((visibility("default"))) #else #define FPDF_EXPORT #endif // defined(FPDF_IMPLEMENTATION) #endif // defined(WIN32) #else #define FPDF_EXPORT #endif // defined(COMPONENT_BUILD) #if defined(WIN32) && defined(FPDFSDK_EXPORTS) #define FPDF_CALLCONV __stdcall #else #define FPDF_CALLCONV #endif // Exported Functions #ifdef __cplusplus extern "C" { #endif // PDF renderer types - Experimental. // Selection of 2D graphics library to use for rendering to FPDF_BITMAPs. typedef enum { // Anti-Grain Geometry - https://sourceforge.net/projects/agg/ FPDF_RENDERERTYPE_AGG = 0, // Skia - https://skia.org/ FPDF_RENDERERTYPE_SKIA = 1, } FPDF_RENDERER_TYPE; // PDF font library types - Experimental. // Selection of font backend library to use. typedef enum { // FreeType - https://freetype.org/ FPDF_FONTBACKENDTYPE_FREETYPE = 0, // Fontations - https://github.com/googlefonts/fontations/ FPDF_FONTBACKENDTYPE_FONTATIONS = 1, } FPDF_FONT_BACKEND_TYPE; // Process-wide options for initializing the library. typedef struct FPDF_LIBRARY_CONFIG_ { // Version number of the interface. Currently must be 2. // Support for version 1 will be deprecated in the future. int version; // Array of paths to scan in place of the defaults when using built-in // FXGE font loading code. The array is terminated by a NULL pointer. // The Array may be NULL itself to use the default paths. May be ignored // entirely depending upon the platform. const char** m_pUserFontPaths; // Version 2. // Pointer to the v8::Isolate to use, or NULL to force PDFium to create one. void* m_pIsolate; // The embedder data slot to use in the v8::Isolate to store PDFium's // per-isolate data. The value needs to be in the range // [0, |v8::Internals::kNumIsolateDataLots|). Note that 0 is fine for most // embedders. unsigned int m_v8EmbedderSlot; // Version 3 - Experimental. // Pointer to the V8::Platform to use. void* m_pPlatform; // Version 4 - Experimental. // Explicit specification of 2D graphics rendering library to use. // |m_RendererType| must be a valid value for |FPDF_LIBRARY_CONFIG| versions // of this level or higher, or else the initialization will fail with an // immediate crash. // Note that use of a specified |FPDF_RENDERER_TYPE| value for which the // corresponding 2D graphics rendering library is not included in the build // will similarly fail with an immediate crash. FPDF_RENDERER_TYPE m_RendererType; // Version 5 - Experimental. // Explicit specification of font library to use when |m_RendererType| is set // to |FPDF_RENDERERTYPE_SKIA|. // |m_FontLibraryType| must be a valid value for |FPDF_LIBRARY_CONFIG| // versions of this level or higher, or else the initialization will fail with // an immediate crash. // Note that use of a specified |FPDF_FONT_BACKEND_TYPE| value for which the // corresponding font library is not included in the build will similarly fail // with an immediate crash. FPDF_FONT_BACKEND_TYPE m_FontLibraryType; } FPDF_LIBRARY_CONFIG; // Function: FPDF_InitLibraryWithConfig // Initialize the PDFium library and allocate global resources for it. // Parameters: // config - configuration information as above. // Return value: // None. // Comments: // You have to call this function before you can call any PDF // processing functions. FPDF_EXPORT void FPDF_CALLCONV FPDF_InitLibraryWithConfig(const FPDF_LIBRARY_CONFIG* config); // Function: FPDF_InitLibrary // Initialize the PDFium library (alternative form). // Parameters: // None // Return value: // None. // Comments: // Convenience function to call FPDF_InitLibraryWithConfig() with a // default configuration for backwards compatibility purposes. New // code should call FPDF_InitLibraryWithConfig() instead. This will // be deprecated in the future. FPDF_EXPORT void FPDF_CALLCONV FPDF_InitLibrary(); // Function: FPDF_DestroyLibrary // Release global resources allocated to the PDFium library by // FPDF_InitLibrary() or FPDF_InitLibraryWithConfig(). // Parameters: // None. // Return value: // None. // Comments: // After this function is called, you must not call any PDF // processing functions. // // Calling this function does not automatically close other // objects. It is recommended to close other objects before // closing the library with this function. FPDF_EXPORT void FPDF_CALLCONV FPDF_DestroyLibrary(); // Policy for accessing the local machine time. #define FPDF_POLICY_MACHINETIME_ACCESS 0 // Function: FPDF_SetSandBoxPolicy // Set the policy for the sandbox environment. // Parameters: // policy - The specified policy for setting, for example: // FPDF_POLICY_MACHINETIME_ACCESS. // enable - True to enable, false to disable the policy. // Return value: // None. FPDF_EXPORT void FPDF_CALLCONV FPDF_SetSandBoxPolicy(FPDF_DWORD policy, FPDF_BOOL enable); #if defined(_WIN32) // Experimental API. // Function: FPDF_SetPrintMode // Set printing mode when printing on Windows. // Parameters: // mode - FPDF_PRINTMODE_EMF to output EMF (default) // FPDF_PRINTMODE_TEXTONLY to output text only (for charstream // devices) // FPDF_PRINTMODE_POSTSCRIPT2 to output level 2 PostScript into // EMF as a series of GDI comments. // FPDF_PRINTMODE_POSTSCRIPT3 to output level 3 PostScript into // EMF as a series of GDI comments. // FPDF_PRINTMODE_POSTSCRIPT2_PASSTHROUGH to output level 2 // PostScript via ExtEscape() in PASSTHROUGH mode. // FPDF_PRINTMODE_POSTSCRIPT3_PASSTHROUGH to output level 3 // PostScript via ExtEscape() in PASSTHROUGH mode. // FPDF_PRINTMODE_EMF_IMAGE_MASKS to output EMF, with more // efficient processing of documents containing image masks. // FPDF_PRINTMODE_POSTSCRIPT3_TYPE42 to output level 3 // PostScript with embedded Type 42 fonts, when applicable, into // EMF as a series of GDI comments. // FPDF_PRINTMODE_POSTSCRIPT3_TYPE42_PASSTHROUGH to output level // 3 PostScript with embedded Type 42 fonts, when applicable, // via ExtEscape() in PASSTHROUGH mode. // Return value: // True if successful, false if unsuccessful (typically invalid input). FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_SetPrintMode(int mode); #endif // defined(_WIN32) // Function: FPDF_LoadDocument // Open and load a PDF document. // Parameters: // file_path - Path to the PDF file (including extension). // password - A string used as the password for the PDF file. // If no password is needed, empty or NULL can be used. // See comments below regarding the encoding. // Return value: // A handle to the loaded document, or NULL on failure. // Comments: // Loaded document can be closed by FPDF_CloseDocument(). // If this function fails, you can use FPDF_GetLastError() to retrieve // the reason why it failed. // // The encoding for |file_path| is UTF-8. // // The encoding for |password| can be either UTF-8 or Latin-1. PDFs, // depending on the security handler revision, will only accept one or // the other encoding. If |password|'s encoding and the PDF's expected // encoding do not match, FPDF_LoadDocument() will automatically // convert |password| to the other encoding. FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV FPDF_LoadDocument(FPDF_STRING file_path, FPDF_BYTESTRING password); // Function: FPDF_LoadMemDocument // Open and load a PDF document from memory. // Parameters: // data_buf - Pointer to a buffer containing the PDF document. // size - Number of bytes in the PDF document. // password - A string used as the password for the PDF file. // If no password is needed, empty or NULL can be used. // Return value: // A handle to the loaded document, or NULL on failure. // Comments: // The memory buffer must remain valid when the document is open. // The loaded document can be closed by FPDF_CloseDocument. // If this function fails, you can use FPDF_GetLastError() to retrieve // the reason why it failed. // // See the comments for FPDF_LoadDocument() regarding the encoding for // |password|. // Notes: // If PDFium is built with the XFA module, the application should call // FPDF_LoadXFA() function after the PDF document loaded to support XFA // fields defined in the fpdfformfill.h file. FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV FPDF_LoadMemDocument(const void* data_buf, int size, FPDF_BYTESTRING password); // Experimental API. // Function: FPDF_LoadMemDocument64 // Open and load a PDF document from memory. // Parameters: // data_buf - Pointer to a buffer containing the PDF document. // size - Number of bytes in the PDF document. // password - A string used as the password for the PDF file. // If no password is needed, empty or NULL can be used. // Return value: // A handle to the loaded document, or NULL on failure. // Comments: // The memory buffer must remain valid when the document is open. // The loaded document can be closed by FPDF_CloseDocument. // If this function fails, you can use FPDF_GetLastError() to retrieve // the reason why it failed. // // See the comments for FPDF_LoadDocument() regarding the encoding for // |password|. // Notes: // If PDFium is built with the XFA module, the application should call // FPDF_LoadXFA() function after the PDF document loaded to support XFA // fields defined in the fpdfformfill.h file. FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV FPDF_LoadMemDocument64(const void* data_buf, size_t size, FPDF_BYTESTRING password); // Structure for custom file access. typedef struct { // File length, in bytes. unsigned long m_FileLen; // A function pointer for getting a block of data from a specific position. // Position is specified by byte offset from the beginning of the file. // The pointer to the buffer is never NULL and the size is never 0. // The position and size will never go out of range of the file length. // It may be possible for PDFium to call this function multiple times for // the same position. // Return value: should be non-zero if successful, zero for error. int (*m_GetBlock)(void* param, unsigned long position, unsigned char* pBuf, unsigned long size); // A custom pointer for all implementation specific data. This pointer will // be used as the first parameter to the m_GetBlock callback. void* m_Param; } FPDF_FILEACCESS; // Structure for file reading or writing (I/O). // // Note: This is a handler and should be implemented by callers, // and is only used from XFA. typedef struct FPDF_FILEHANDLER_ { // User-defined data. // Note: Callers can use this field to track controls. void* clientData; // Callback function to release the current file stream object. // // Parameters: // clientData - Pointer to user-defined data. // Returns: // None. void (*Release)(void* clientData); // Callback function to retrieve the current file stream size. // // Parameters: // clientData - Pointer to user-defined data. // Returns: // Size of file stream. FPDF_DWORD (*GetSize)(void* clientData); // Callback function to read data from the current file stream. // // Parameters: // clientData - Pointer to user-defined data. // offset - Offset position starts from the beginning of file // stream. This parameter indicates reading position. // buffer - Memory buffer to store data which are read from // file stream. This parameter should not be NULL. // size - Size of data which should be read from file stream, // in bytes. The buffer indicated by |buffer| must be // large enough to store specified data. // Returns: // 0 for success, other value for failure. FPDF_RESULT (*ReadBlock)(void* clientData, FPDF_DWORD offset, void* buffer, FPDF_DWORD size); // Callback function to write data into the current file stream. // // Parameters: // clientData - Pointer to user-defined data. // offset - Offset position starts from the beginning of file // stream. This parameter indicates writing position. // buffer - Memory buffer contains data which is written into // file stream. This parameter should not be NULL. // size - Size of data which should be written into file // stream, in bytes. // Returns: // 0 for success, other value for failure. FPDF_RESULT (*WriteBlock)(void* clientData, FPDF_DWORD offset, const void* buffer, FPDF_DWORD size); // Callback function to flush all internal accessing buffers. // // Parameters: // clientData - Pointer to user-defined data. // Returns: // 0 for success, other value for failure. FPDF_RESULT (*Flush)(void* clientData); // Callback function to change file size. // // Description: // This function is called under writing mode usually. Implementer // can determine whether to realize it based on application requests. // Parameters: // clientData - Pointer to user-defined data. // size - New size of file stream, in bytes. // Returns: // 0 for success, other value for failure. FPDF_RESULT (*Truncate)(void* clientData, FPDF_DWORD size); } FPDF_FILEHANDLER; // Function: FPDF_LoadCustomDocument // Load PDF document from a custom access descriptor. // Parameters: // pFileAccess - A structure for accessing the file. // password - Optional password for decrypting the PDF file. // Return value: // A handle to the loaded document, or NULL on failure. // Comments: // The application must keep the file resources |pFileAccess| points to // valid until the returned FPDF_DOCUMENT is closed. |pFileAccess| // itself does not need to outlive the FPDF_DOCUMENT. // // The loaded document can be closed with FPDF_CloseDocument(). // // See the comments for FPDF_LoadDocument() regarding the encoding for // |password|. // Notes: // If PDFium is built with the XFA module, the application should call // FPDF_LoadXFA() function after the PDF document loaded to support XFA // fields defined in the fpdfformfill.h file. FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV FPDF_LoadCustomDocument(FPDF_FILEACCESS* pFileAccess, FPDF_BYTESTRING password); // Function: FPDF_GetFileVersion // Get the file version of the given PDF document. // Parameters: // doc - Handle to a document. // fileVersion - The PDF file version. File version: 14 for 1.4, 15 // for 1.5, ... // Return value: // True if succeeds, false otherwise. // Comments: // If the document was created by FPDF_CreateNewDocument, // then this function will always fail. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_GetFileVersion(FPDF_DOCUMENT doc, int* fileVersion); #define FPDF_ERR_SUCCESS 0 // No error. #define FPDF_ERR_UNKNOWN 1 // Unknown error. #define FPDF_ERR_FILE 2 // File not found or could not be opened. #define FPDF_ERR_FORMAT 3 // File not in PDF format or corrupted. #define FPDF_ERR_PASSWORD 4 // Password required or incorrect password. #define FPDF_ERR_SECURITY 5 // Unsupported security scheme. #define FPDF_ERR_PAGE 6 // Page not found or content error. #ifdef PDF_ENABLE_XFA #define FPDF_ERR_XFALOAD 7 // Load XFA error. #define FPDF_ERR_XFALAYOUT 8 // Layout XFA error. #endif // PDF_ENABLE_XFA // Function: FPDF_GetLastError // Get last error code when a function fails. // Parameters: // None. // Return value: // A 32-bit integer indicating error code as defined above. // Comments: // If the previous SDK call succeeded, the return value of this // function is not defined. This function only works in conjunction // with APIs that mention FPDF_GetLastError() in their documentation. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetLastError(); // Experimental API. // Function: FPDF_DocumentHasValidCrossReferenceTable // Whether the document's cross reference table is valid or not. // Parameters: // document - Handle to a document. Returned by FPDF_LoadDocument. // Return value: // True if the PDF parser did not encounter problems parsing the cross // reference table. False if the parser could not parse the cross // reference table and the table had to be rebuild from other data // within the document. // Comments: // The return value can change over time as the PDF parser evolves. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_DocumentHasValidCrossReferenceTable(FPDF_DOCUMENT document); // Experimental API. // Function: FPDF_GetTrailerEnds // Get the byte offsets of trailer ends. // Parameters: // document - Handle to document. Returned by FPDF_LoadDocument(). // buffer - The address of a buffer that receives the // byte offsets. // length - The size, in ints, of |buffer|. // Return value: // Returns the number of ints in the buffer on success, 0 on error. // // |buffer| is an array of integers that describes the exact byte offsets of the // trailer ends in the document. If |length| is less than the returned length, // or |document| or |buffer| is NULL, |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetTrailerEnds(FPDF_DOCUMENT document, unsigned int* buffer, unsigned long length); // Function: FPDF_GetDocPermissions // Get file permission flags of the document. // Parameters: // document - Handle to a document. Returned by FPDF_LoadDocument. // Return value: // A 32-bit integer indicating permission flags. Please refer to the // PDF Reference for detailed descriptions. If the document is not // protected or was unlocked by the owner, 0xffffffff will be returned. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetDocPermissions(FPDF_DOCUMENT document); // Function: FPDF_GetDocUserPermissions // Get user file permission flags of the document. // Parameters: // document - Handle to a document. Returned by FPDF_LoadDocument. // Return value: // A 32-bit integer indicating permission flags. Please refer to the // PDF Reference for detailed descriptions. If the document is not // protected, 0xffffffff will be returned. Always returns user // permissions, even if the document was unlocked by the owner. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetDocUserPermissions(FPDF_DOCUMENT document); // Function: FPDF_GetSecurityHandlerRevision // Get the revision for the security handler. // Parameters: // document - Handle to a document. Returned by FPDF_LoadDocument. // Return value: // The security handler revision number. Please refer to the PDF // Reference for a detailed description. If the document is not // protected, -1 will be returned. FPDF_EXPORT int FPDF_CALLCONV FPDF_GetSecurityHandlerRevision(FPDF_DOCUMENT document); // Function: FPDF_GetPageCount // Get total number of pages in the document. // Parameters: // document - Handle to document. Returned by FPDF_LoadDocument. // Return value: // Total number of pages in the document. FPDF_EXPORT int FPDF_CALLCONV FPDF_GetPageCount(FPDF_DOCUMENT document); // Function: FPDF_LoadPage // Load a page inside the document. // Parameters: // document - Handle to document. Returned by FPDF_LoadDocument // page_index - Index number of the page. 0 for the first page. // Return value: // A handle to the loaded page, or NULL if page load fails. // Comments: // The loaded page can be rendered to devices using FPDF_RenderPage. // The loaded page can be closed using FPDF_ClosePage. FPDF_EXPORT FPDF_PAGE FPDF_CALLCONV FPDF_LoadPage(FPDF_DOCUMENT document, int page_index); // Experimental API // Function: FPDF_GetPageWidthF // Get page width. // Parameters: // page - Handle to the page. Returned by FPDF_LoadPage(). // Return value: // Page width (excluding non-displayable area) measured in points. // One point is 1/72 inch (around 0.3528 mm). // Comments: // Changing the rotation of |page| affects the return value. FPDF_EXPORT float FPDF_CALLCONV FPDF_GetPageWidthF(FPDF_PAGE page); // Function: FPDF_GetPageWidth // Get page width. // Parameters: // page - Handle to the page. Returned by FPDF_LoadPage. // Return value: // Page width (excluding non-displayable area) measured in points. // One point is 1/72 inch (around 0.3528 mm). // Note: // Prefer FPDF_GetPageWidthF() above. This will be deprecated in the // future. // Comments: // Changing the rotation of |page| affects the return value. FPDF_EXPORT double FPDF_CALLCONV FPDF_GetPageWidth(FPDF_PAGE page); // Experimental API // Function: FPDF_GetPageHeightF // Get page height. // Parameters: // page - Handle to the page. Returned by FPDF_LoadPage(). // Return value: // Page height (excluding non-displayable area) measured in points. // One point is 1/72 inch (around 0.3528 mm) // Comments: // Changing the rotation of |page| affects the return value. FPDF_EXPORT float FPDF_CALLCONV FPDF_GetPageHeightF(FPDF_PAGE page); // Function: FPDF_GetPageHeight // Get page height. // Parameters: // page - Handle to the page. Returned by FPDF_LoadPage. // Return value: // Page height (excluding non-displayable area) measured in points. // One point is 1/72 inch (around 0.3528 mm) // Note: // Prefer FPDF_GetPageHeightF() above. This will be deprecated in the // future. // Comments: // Changing the rotation of |page| affects the return value. FPDF_EXPORT double FPDF_CALLCONV FPDF_GetPageHeight(FPDF_PAGE page); // Experimental API. // Function: FPDF_GetPageBoundingBox // Get the bounding box of the page. This is the intersection between // its media box and its crop box. // Parameters: // page - Handle to the page. Returned by FPDF_LoadPage. // rect - Pointer to a rect to receive the page bounding box. // On an error, |rect| won't be filled. // Return value: // True for success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_GetPageBoundingBox(FPDF_PAGE page, FS_RECTF* rect); // Experimental API. // Function: FPDF_GetPageSizeByIndexF // Get the size of the page at the given index. // Parameters: // document - Handle to document. Returned by FPDF_LoadDocument(). // page_index - Page index, zero for the first page. // size - Pointer to a FS_SIZEF to receive the page size. // (in points). // Return value: // Non-zero for success. 0 for error (document or page not found). FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_GetPageSizeByIndexF(FPDF_DOCUMENT document, int page_index, FS_SIZEF* size); // Function: FPDF_GetPageSizeByIndex // Get the size of the page at the given index. // Parameters: // document - Handle to document. Returned by FPDF_LoadDocument. // page_index - Page index, zero for the first page. // width - Pointer to a double to receive the page width // (in points). // height - Pointer to a double to receive the page height // (in points). // Return value: // Non-zero for success. 0 for error (document or page not found). // Note: // Prefer FPDF_GetPageSizeByIndexF() above. This will be deprecated in // the future. FPDF_EXPORT int FPDF_CALLCONV FPDF_GetPageSizeByIndex(FPDF_DOCUMENT document, int page_index, double* width, double* height); // Page rendering flags. They can be combined with bit-wise OR. // // Set if annotations are to be rendered. #define FPDF_ANNOT 0x01 // Set if using text rendering optimized for LCD display. This flag will only // take effect if anti-aliasing is enabled for text. #define FPDF_LCD_TEXT 0x02 // Don't use the native text output available on some platforms #define FPDF_NO_NATIVETEXT 0x04 // Grayscale output. #define FPDF_GRAYSCALE 0x08 // Obsolete, has no effect, retained for compatibility. #define FPDF_DEBUG_INFO 0x80 // Obsolete, has no effect, retained for compatibility. #define FPDF_NO_CATCH 0x100 // Limit image cache size. #define FPDF_RENDER_LIMITEDIMAGECACHE 0x200 // Always use halftone for image stretching. #define FPDF_RENDER_FORCEHALFTONE 0x400 // Render for printing. #define FPDF_PRINTING 0x800 // Set to disable anti-aliasing on text. This flag will also disable LCD // optimization for text rendering. #define FPDF_RENDER_NO_SMOOTHTEXT 0x1000 // Set to disable anti-aliasing on images. #define FPDF_RENDER_NO_SMOOTHIMAGE 0x2000 // Set to disable anti-aliasing on paths. #define FPDF_RENDER_NO_SMOOTHPATH 0x4000 // Set whether to render in a reverse Byte order, this flag is only used when // rendering to a bitmap. #define FPDF_REVERSE_BYTE_ORDER 0x10 // Set whether fill paths need to be stroked. This flag is only used when // FPDF_COLORSCHEME is passed in, since with a single fill color for paths the // boundaries of adjacent fill paths are less visible. #define FPDF_CONVERT_FILL_TO_STROKE 0x20 // Struct for color scheme. // Each should be a 32-bit value specifying the color, in 8888 ARGB format. typedef struct FPDF_COLORSCHEME_ { FPDF_DWORD path_fill_color; FPDF_DWORD path_stroke_color; FPDF_DWORD text_fill_color; FPDF_DWORD text_stroke_color; } FPDF_COLORSCHEME; #ifdef _WIN32 // Function: FPDF_RenderPage // Render contents of a page to a device (screen, bitmap, or printer). // This function is only supported on Windows. // Parameters: // dc - Handle to the device context. // page - Handle to the page. Returned by FPDF_LoadPage. // start_x - Left pixel position of the display area in // device coordinates. // start_y - Top pixel position of the display area in device // coordinates. // size_x - Horizontal size (in pixels) for displaying the page. // size_y - Vertical size (in pixels) for displaying the page. // rotate - Page orientation: // 0 (normal) // 1 (rotated 90 degrees clockwise) // 2 (rotated 180 degrees) // 3 (rotated 90 degrees counter-clockwise) // flags - 0 for normal display, or combination of flags // defined above. // Return value: // Returns true if the page is rendered successfully, false otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_RenderPage(HDC dc, FPDF_PAGE page, int start_x, int start_y, int size_x, int size_y, int rotate, int flags); #endif // Function: FPDF_RenderPageBitmap // Render contents of a page to a device independent bitmap. // Parameters: // bitmap - Handle to the device independent bitmap (as the // output buffer). The bitmap handle can be created // by FPDFBitmap_Create or retrieved from an image // object by FPDFImageObj_GetBitmap. // page - Handle to the page. Returned by FPDF_LoadPage // start_x - Left pixel position of the display area in // bitmap coordinates. // start_y - Top pixel position of the display area in bitmap // coordinates. // size_x - Horizontal size (in pixels) for displaying the page. // size_y - Vertical size (in pixels) for displaying the page. // rotate - Page orientation: // 0 (normal) // 1 (rotated 90 degrees clockwise) // 2 (rotated 180 degrees) // 3 (rotated 90 degrees counter-clockwise) // flags - 0 for normal display, or combination of the Page // Rendering flags defined above. With the FPDF_ANNOT // flag, it renders all annotations that do not require // user-interaction, which are all annotations except // widget and popup annotations. // Return value: // None. FPDF_EXPORT void FPDF_CALLCONV FPDF_RenderPageBitmap(FPDF_BITMAP bitmap, FPDF_PAGE page, int start_x, int start_y, int size_x, int size_y, int rotate, int flags); // Function: FPDF_RenderPageBitmapWithMatrix // Render contents of a page to a device independent bitmap. // Parameters: // bitmap - Handle to the device independent bitmap (as the // output buffer). The bitmap handle can be created // by FPDFBitmap_Create or retrieved by // FPDFImageObj_GetBitmap. // page - Handle to the page. Returned by FPDF_LoadPage. // matrix - The transform matrix, which must be invertible. // See PDF Reference 1.7, 4.2.2 Common Transformations. // clipping - The rect to clip to in device coords. // flags - 0 for normal display, or combination of the Page // Rendering flags defined above. With the FPDF_ANNOT // flag, it renders all annotations that do not require // user-interaction, which are all annotations except // widget and popup annotations. // Return value: // None. Note that behavior is undefined if det of |matrix| is 0. FPDF_EXPORT void FPDF_CALLCONV FPDF_RenderPageBitmapWithMatrix(FPDF_BITMAP bitmap, FPDF_PAGE page, const FS_MATRIX* matrix, const FS_RECTF* clipping, int flags); #if defined(PDF_USE_SKIA) // Experimental API. // Function: FPDF_RenderPageSkia // Render contents of a page to a Skia SkCanvas. // Parameters: // canvas - SkCanvas to render to. // page - Handle to the page. // size_x - Horizontal size (in pixels) for displaying the page. // size_y - Vertical size (in pixels) for displaying the page. // Return value: // None. FPDF_EXPORT void FPDF_CALLCONV FPDF_RenderPageSkia(FPDF_SKIA_CANVAS canvas, FPDF_PAGE page, int size_x, int size_y); #endif // Function: FPDF_ClosePage // Close a loaded PDF page. // Parameters: // page - Handle to the loaded page. // Return value: // None. FPDF_EXPORT void FPDF_CALLCONV FPDF_ClosePage(FPDF_PAGE page); // Function: FPDF_CloseDocument // Close a loaded PDF document. // Parameters: // document - Handle to the loaded document. // Return value: // None. FPDF_EXPORT void FPDF_CALLCONV FPDF_CloseDocument(FPDF_DOCUMENT document); // Function: FPDF_DeviceToPage // Convert the screen coordinates of a point to page coordinates. // Parameters: // page - Handle to the page. Returned by FPDF_LoadPage. // start_x - Left pixel position of the display area in // device coordinates. // start_y - Top pixel position of the display area in device // coordinates. // size_x - Horizontal size (in pixels) for displaying the page. // size_y - Vertical size (in pixels) for displaying the page. // rotate - Page orientation: // 0 (normal) // 1 (rotated 90 degrees clockwise) // 2 (rotated 180 degrees) // 3 (rotated 90 degrees counter-clockwise) // device_x - X value in device coordinates to be converted. // device_y - Y value in device coordinates to be converted. // page_x - A pointer to a double receiving the converted X // value in page coordinates. // page_y - A pointer to a double receiving the converted Y // value in page coordinates. // Return value: // Returns true if the conversion succeeds, and |page_x| and |page_y| // successfully receives the converted coordinates. // Comments: // The page coordinate system has its origin at the left-bottom corner // of the page, with the X-axis on the bottom going to the right, and // the Y-axis on the left side going up. // // NOTE: this coordinate system can be altered when you zoom, scroll, // or rotate a page, however, a point on the page should always have // the same coordinate values in the page coordinate system. // // The device coordinate system is device dependent. For screen device, // its origin is at the left-top corner of the window. However this // origin can be altered by the Windows coordinate transformation // utilities. // // You must make sure the start_x, start_y, size_x, size_y // and rotate parameters have exactly same values as you used in // the FPDF_RenderPage() function call. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_DeviceToPage(FPDF_PAGE page, int start_x, int start_y, int size_x, int size_y, int rotate, int device_x, int device_y, double* page_x, double* page_y); // Function: FPDF_PageToDevice // Convert the page coordinates of a point to screen coordinates. // Parameters: // page - Handle to the page. Returned by FPDF_LoadPage. // start_x - Left pixel position of the display area in // device coordinates. // start_y - Top pixel position of the display area in device // coordinates. // size_x - Horizontal size (in pixels) for displaying the page. // size_y - Vertical size (in pixels) for displaying the page. // rotate - Page orientation: // 0 (normal) // 1 (rotated 90 degrees clockwise) // 2 (rotated 180 degrees) // 3 (rotated 90 degrees counter-clockwise) // page_x - X value in page coordinates. // page_y - Y value in page coordinate. // device_x - A pointer to an integer receiving the result X // value in device coordinates. // device_y - A pointer to an integer receiving the result Y // value in device coordinates. // Return value: // Returns true if the conversion succeeds, and |device_x| and // |device_y| successfully receives the converted coordinates. // Comments: // See comments for FPDF_DeviceToPage(). FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_PageToDevice(FPDF_PAGE page, int start_x, int start_y, int size_x, int size_y, int rotate, double page_x, double page_y, int* device_x, int* device_y); // Function: FPDFBitmap_Create // Create a device independent bitmap (FXDIB). // Parameters: // width - The number of pixels in width for the bitmap. // Must be greater than 0. // height - The number of pixels in height for the bitmap. // Must be greater than 0. // alpha - A flag indicating whether the alpha channel is used. // Non-zero for using alpha, zero for not using. // Return value: // The created bitmap handle, or NULL if a parameter error or out of // memory. // Comments: // The bitmap always uses 4 bytes per pixel. The first byte is always // double word aligned. // // The byte order is BGRx (the last byte unused if no alpha channel) or // BGRA. // // The pixels in a horizontal line are stored side by side, with the // left most pixel stored first (with lower memory address). // Each line uses width * 4 bytes. // // Lines are stored one after another, with the top most line stored // first. There is no gap between adjacent lines. // // This function allocates enough memory for holding all pixels in the // bitmap, but it doesn't initialize the buffer. Applications can use // FPDFBitmap_FillRect() to fill the bitmap using any color. If the OS // allows it, this function can allocate up to 4 GB of memory. FPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV FPDFBitmap_Create(int width, int height, int alpha); // More DIB formats // Unknown or unsupported format. // All of the colors are listed in order of LSB to MSB. #define FPDFBitmap_Unknown 0 // Gray scale bitmap, one byte per pixel. #define FPDFBitmap_Gray 1 // 3 bytes per pixel, byte order: blue, green, red. #define FPDFBitmap_BGR 2 // 4 bytes per pixel, byte order: blue, green, red, unused. #define FPDFBitmap_BGRx 3 // 4 bytes per pixel, byte order: blue, green, red, alpha. // Pixel components are independent of alpha. #define FPDFBitmap_BGRA 4 // 4 bytes per pixel, byte order: blue, green, red, alpha. // Pixel components are premultiplied by alpha. // Note that this is experimental and only supported when rendering with // |FPDF_RENDERER_TYPE| is set to |FPDF_RENDERERTYPE_SKIA|. #define FPDFBitmap_BGRA_Premul 5 // Function: FPDFBitmap_CreateEx // Create a device independent bitmap (FXDIB) // Parameters: // width - The number of pixels in width for the bitmap. // Must be greater than 0. // height - The number of pixels in height for the bitmap. // Must be greater than 0. // format - A number indicating for bitmap format, as defined // above. // first_scan - A pointer to the first byte of the first line if // using an external buffer. If this parameter is NULL, // then a new buffer will be created. // stride - Number of bytes for each scan line. The value must // be 0 or greater. When the value is 0, // FPDFBitmap_CreateEx() will automatically calculate // the appropriate value using |width| and |format|. // When using an external buffer, it is recommended for // the caller to pass in the value. // When not using an external buffer, it is recommended // for the caller to pass in 0. // Return value: // The bitmap handle, or NULL if parameter error or out of memory. // Comments: // Similar to FPDFBitmap_Create function, but allows for more formats // and an external buffer is supported. The bitmap created by this // function can be used in any place that a FPDF_BITMAP handle is // required. // // If an external buffer is used, then the caller should destroy the // buffer. FPDFBitmap_Destroy() will not destroy the buffer. // // It is recommended to use FPDFBitmap_GetStride() to get the stride // value. FPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV FPDFBitmap_CreateEx(int width, int height, int format, void* first_scan, int stride); // Function: FPDFBitmap_GetFormat // Get the format of the bitmap. // Parameters: // bitmap - Handle to the bitmap. Returned by FPDFBitmap_Create // or FPDFImageObj_GetBitmap. // Return value: // The format of the bitmap. // Comments: // Only formats supported by FPDFBitmap_CreateEx are supported by this // function; see the list of such formats above. FPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetFormat(FPDF_BITMAP bitmap); // Function: FPDFBitmap_FillRect // Fill a rectangle in a bitmap. // Parameters: // bitmap - The handle to the bitmap. Returned by // FPDFBitmap_Create. // left - The left position. Starting from 0 at the // left-most pixel. // top - The top position. Starting from 0 at the // top-most line. // width - Width in pixels to be filled. // height - Height in pixels to be filled. // color - A 32-bit value specifing the color, in 8888 ARGB // format. // Return value: // Returns whether the operation succeeded or not. // Comments: // This function sets the color and (optionally) alpha value in the // specified region of the bitmap. // // NOTE: If the alpha channel is used, this function does NOT // composite the background with the source color, instead the // background will be replaced by the source color and the alpha. // // If the alpha channel is not used, the alpha parameter is ignored. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFBitmap_FillRect(FPDF_BITMAP bitmap, int left, int top, int width, int height, FPDF_DWORD color); // Function: FPDFBitmap_GetBuffer // Get data buffer of a bitmap. // Parameters: // bitmap - Handle to the bitmap. Returned by FPDFBitmap_Create // or FPDFImageObj_GetBitmap. // Return value: // The pointer to the first byte of the bitmap buffer. // Comments: // The stride may be more than width * number of bytes per pixel // // Applications can use this function to get the bitmap buffer pointer, // then manipulate any color and/or alpha values for any pixels in the // bitmap. // // Use FPDFBitmap_GetFormat() to find out the format of the data. FPDF_EXPORT void* FPDF_CALLCONV FPDFBitmap_GetBuffer(FPDF_BITMAP bitmap); // Function: FPDFBitmap_GetWidth // Get width of a bitmap. // Parameters: // bitmap - Handle to the bitmap. Returned by FPDFBitmap_Create // or FPDFImageObj_GetBitmap. // Return value: // The width of the bitmap in pixels. FPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetWidth(FPDF_BITMAP bitmap); // Function: FPDFBitmap_GetHeight // Get height of a bitmap. // Parameters: // bitmap - Handle to the bitmap. Returned by FPDFBitmap_Create // or FPDFImageObj_GetBitmap. // Return value: // The height of the bitmap in pixels. FPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetHeight(FPDF_BITMAP bitmap); // Function: FPDFBitmap_GetStride // Get number of bytes for each line in the bitmap buffer. // Parameters: // bitmap - Handle to the bitmap. Returned by FPDFBitmap_Create // or FPDFImageObj_GetBitmap. // Return value: // The number of bytes for each line in the bitmap buffer. // Comments: // The stride may be more than width * number of bytes per pixel. FPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetStride(FPDF_BITMAP bitmap); // Function: FPDFBitmap_Destroy // Destroy a bitmap and release all related buffers. // Parameters: // bitmap - Handle to the bitmap. Returned by FPDFBitmap_Create // or FPDFImageObj_GetBitmap. // Return value: // None. // Comments: // This function will not destroy any external buffers provided when // the bitmap was created. FPDF_EXPORT void FPDF_CALLCONV FPDFBitmap_Destroy(FPDF_BITMAP bitmap); // Function: FPDF_VIEWERREF_GetPrintScaling // Whether the PDF document prefers to be scaled or not. // Parameters: // document - Handle to the loaded document. // Return value: // None. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_VIEWERREF_GetPrintScaling(FPDF_DOCUMENT document); // Function: FPDF_VIEWERREF_GetNumCopies // Returns the number of copies to be printed. // Parameters: // document - Handle to the loaded document. // Return value: // The number of copies to be printed. FPDF_EXPORT int FPDF_CALLCONV FPDF_VIEWERREF_GetNumCopies(FPDF_DOCUMENT document); // Function: FPDF_VIEWERREF_GetPrintPageRange // Page numbers to initialize print dialog box when file is printed. // Parameters: // document - Handle to the loaded document. // Return value: // The print page range to be used for printing. FPDF_EXPORT FPDF_PAGERANGE FPDF_CALLCONV FPDF_VIEWERREF_GetPrintPageRange(FPDF_DOCUMENT document); // Experimental API. // Function: FPDF_VIEWERREF_GetPrintPageRangeCount // Returns the number of elements in a FPDF_PAGERANGE. // Parameters: // pagerange - Handle to the page range. // Return value: // The number of elements in the page range. Returns 0 on error. FPDF_EXPORT size_t FPDF_CALLCONV FPDF_VIEWERREF_GetPrintPageRangeCount(FPDF_PAGERANGE pagerange); // Experimental API. // Function: FPDF_VIEWERREF_GetPrintPageRangeElement // Returns an element from a FPDF_PAGERANGE. // Parameters: // pagerange - Handle to the page range. // index - Index of the element. // Return value: // The value of the element in the page range at a given index. // Returns -1 on error. FPDF_EXPORT int FPDF_CALLCONV FPDF_VIEWERREF_GetPrintPageRangeElement(FPDF_PAGERANGE pagerange, size_t index); // Function: FPDF_VIEWERREF_GetDuplex // Returns the paper handling option to be used when printing from // the print dialog. // Parameters: // document - Handle to the loaded document. // Return value: // The paper handling option to be used when printing. FPDF_EXPORT FPDF_DUPLEXTYPE FPDF_CALLCONV FPDF_VIEWERREF_GetDuplex(FPDF_DOCUMENT document); // Function: FPDF_VIEWERREF_GetName // Gets the contents for a viewer ref, with a given key. The value must // be of type "name". // Parameters: // document - Handle to the loaded document. // key - Name of the key in the viewer pref dictionary, // encoded in UTF-8. // buffer - Caller-allocate buffer to receive the key, or NULL // - to query the required length. // length - Length of the buffer. // Return value: // The number of bytes in the contents, including the NULL terminator. // Thus if the return value is 0, then that indicates an error, such // as when |document| is invalid. If |length| is less than the required // length, or |buffer| is NULL, |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_VIEWERREF_GetName(FPDF_DOCUMENT document, FPDF_BYTESTRING key, char* buffer, unsigned long length); // Function: FPDF_CountNamedDests // Get the count of named destinations in the PDF document. // Parameters: // document - Handle to a document // Return value: // The count of named destinations. FPDF_EXPORT FPDF_DWORD FPDF_CALLCONV FPDF_CountNamedDests(FPDF_DOCUMENT document); // Function: FPDF_GetNamedDestByName // Get a the destination handle for the given name. // Parameters: // document - Handle to the loaded document. // name - The name of a destination. // Return value: // The handle to the destination. FPDF_EXPORT FPDF_DEST FPDF_CALLCONV FPDF_GetNamedDestByName(FPDF_DOCUMENT document, FPDF_BYTESTRING name); // Function: FPDF_GetNamedDest // Get the named destination by index. // Parameters: // document - Handle to a document // index - The index of a named destination. // buffer - The buffer to store the destination name, // used as wchar_t*. // buflen [in/out] - Size of the buffer in bytes on input, // length of the result in bytes on output // or -1 if the buffer is too small. // Return value: // The destination handle for a given index, or NULL if there is no // named destination corresponding to |index|. // Comments: // Call this function twice to get the name of the named destination: // 1) First time pass in |buffer| as NULL and get buflen. // 2) Second time pass in allocated |buffer| and buflen to retrieve // |buffer|, which should be used as wchar_t*. // // If buflen is not sufficiently large, it will be set to -1 upon // return. FPDF_EXPORT FPDF_DEST FPDF_CALLCONV FPDF_GetNamedDest(FPDF_DOCUMENT document, int index, void* buffer, long* buflen); // Experimental API. // Function: FPDF_GetXFAPacketCount // Get the number of valid packets in the XFA entry. // Parameters: // document - Handle to the document. // Return value: // The number of valid packets, or -1 on error. FPDF_EXPORT int FPDF_CALLCONV FPDF_GetXFAPacketCount(FPDF_DOCUMENT document); // Experimental API. // Function: FPDF_GetXFAPacketName // Get the name of a packet in the XFA array. // Parameters: // document - Handle to the document. // index - Index number of the packet. 0 for the first packet. // buffer - Buffer for holding the name of the XFA packet. // buflen - Length of |buffer| in bytes. // Return value: // The length of the packet name in bytes, or 0 on error. // // |document| must be valid and |index| must be in the range [0, N), where N is // the value returned by FPDF_GetXFAPacketCount(). // |buffer| is only modified if it is non-NULL and |buflen| is greater than or // equal to the length of the packet name. The packet name includes a // terminating NUL character. |buffer| is unmodified on error. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetXFAPacketName( FPDF_DOCUMENT document, int index, void* buffer, unsigned long buflen); // Experimental API. // Function: FPDF_GetXFAPacketContent // Get the content of a packet in the XFA array. // Parameters: // document - Handle to the document. // index - Index number of the packet. 0 for the first packet. // buffer - Buffer for holding the content of the XFA packet. // buflen - Length of |buffer| in bytes. // out_buflen - Pointer to the variable that will receive the minimum // buffer size needed to contain the content of the XFA // packet. // Return value: // Whether the operation succeeded or not. // // |document| must be valid and |index| must be in the range [0, N), where N is // the value returned by FPDF_GetXFAPacketCount(). |out_buflen| must not be // NULL. When the aforementioned arguments are valid, the operation succeeds, // and |out_buflen| receives the content size. |buffer| is only modified if // |buffer| is non-null and long enough to contain the content. Callers must // check both the return value and the input |buflen| is no less than the // returned |out_buflen| before using the data in |buffer|. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_GetXFAPacketContent( FPDF_DOCUMENT document, int index, void* buffer, unsigned long buflen, unsigned long* out_buflen); #ifdef PDF_ENABLE_V8 // Function: FPDF_GetRecommendedV8Flags // Returns a space-separated string of command line flags that are // recommended to be passed into V8 via V8::SetFlagsFromString() // prior to initializing the PDFium library. // Parameters: // None. // Return value: // NUL-terminated string of the form "--flag1 --flag2". // The caller must not attempt to modify or free the result. FPDF_EXPORT const char* FPDF_CALLCONV FPDF_GetRecommendedV8Flags(); // Experimental API. // Function: FPDF_GetArrayBufferAllocatorSharedInstance() // Helper function for initializing V8 isolates that will // use PDFium's internal memory management. // Parameters: // None. // Return Value: // Pointer to a suitable v8::ArrayBuffer::Allocator, returned // as void for C compatibility. // Notes: // Use is optional, but allows external creation of isolates // matching the ones PDFium will make when none is provided // via |FPDF_LIBRARY_CONFIG::m_pIsolate|. // // Can only be called when the library is in an uninitialized or // destroyed state. FPDF_EXPORT void* FPDF_CALLCONV FPDF_GetArrayBufferAllocatorSharedInstance(); #endif // PDF_ENABLE_V8 #ifdef PDF_ENABLE_XFA // Function: FPDF_BStr_Init // Helper function to initialize a FPDF_BSTR. FPDF_EXPORT FPDF_RESULT FPDF_CALLCONV FPDF_BStr_Init(FPDF_BSTR* bstr); // Function: FPDF_BStr_Set // Helper function to copy string data into the FPDF_BSTR. FPDF_EXPORT FPDF_RESULT FPDF_CALLCONV FPDF_BStr_Set(FPDF_BSTR* bstr, const char* cstr, int length); // Function: FPDF_BStr_Clear // Helper function to clear a FPDF_BSTR. FPDF_EXPORT FPDF_RESULT FPDF_CALLCONV FPDF_BStr_Clear(FPDF_BSTR* bstr); #endif // PDF_ENABLE_XFA #ifdef __cplusplus } #endif #endif // PUBLIC_FPDFVIEW_H_ ================================================ FILE: external/pdfium/macos-arm64/licenses/abseil.txt ================================================ Apache License Version 2.0, January 2004 https://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: external/pdfium/macos-arm64/licenses/agg23.txt ================================================ //---------------------------------------------------------------------------- // Anti-Grain Geometry - Version 2.3 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) // // Permission to copy, use, modify, sell and distribute this software // is granted provided this copyright notice appears in all copies. // This software is provided "as is" without express or implied // warranty, and with no claim as to its suitability for any purpose. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- ================================================ FILE: external/pdfium/macos-arm64/licenses/fast_float.txt ================================================ MIT License Copyright (c) 2021 The fast_float authors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: external/pdfium/macos-arm64/licenses/freetype.txt ================================================ The FreeType Project LICENSE ---------------------------- 2006-Jan-27 Copyright 1996-2002, 2006 by David Turner, Robert Wilhelm, and Werner Lemberg Introduction ============ The FreeType Project is distributed in several archive packages; some of them may contain, in addition to the FreeType font engine, various tools and contributions which rely on, or relate to, the FreeType Project. This license applies to all files found in such packages, and which do not fall under their own explicit license. The license affects thus the FreeType font engine, the test programs, documentation and makefiles, at the very least. This license was inspired by the BSD, Artistic, and IJG (Independent JPEG Group) licenses, which all encourage inclusion and use of free software in commercial and freeware products alike. As a consequence, its main points are that: o We don't promise that this software works. However, we will be interested in any kind of bug reports. (`as is' distribution) o You can use this software for whatever you want, in parts or full form, without having to pay us. (`royalty-free' usage) o You may not pretend that you wrote this software. If you use it, or only parts of it, in a program, you must acknowledge somewhere in your documentation that you have used the FreeType code. (`credits') We specifically permit and encourage the inclusion of this software, with or without modifications, in commercial products. We disclaim all warranties covering The FreeType Project and assume no liability related to The FreeType Project. Finally, many people asked us for a preferred form for a credit/disclaimer to use in compliance with this license. We thus encourage you to use the following text: """ Portions of this software are copyright The FreeType Project (www.freetype.org). All rights reserved. """ Please replace with the value from the FreeType version you actually use. Legal Terms =========== 0. Definitions -------------- Throughout this license, the terms `package', `FreeType Project', and `FreeType archive' refer to the set of files originally distributed by the authors (David Turner, Robert Wilhelm, and Werner Lemberg) as the `FreeType Project', be they named as alpha, beta or final release. `You' refers to the licensee, or person using the project, where `using' is a generic term including compiling the project's source code as well as linking it to form a `program' or `executable'. This program is referred to as `a program using the FreeType engine'. This license applies to all files distributed in the original FreeType Project, including all source code, binaries and documentation, unless otherwise stated in the file in its original, unmodified form as distributed in the original archive. If you are unsure whether or not a particular file is covered by this license, you must contact us to verify this. The FreeType Project is copyright (C) 1996-2000 by David Turner, Robert Wilhelm, and Werner Lemberg. All rights reserved except as specified below. 1. No Warranty -------------- THE FREETYPE PROJECT IS PROVIDED `AS IS' WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL ANY OF THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY DAMAGES CAUSED BY THE USE OR THE INABILITY TO USE, OF THE FREETYPE PROJECT. 2. Redistribution ----------------- This license grants a worldwide, royalty-free, perpetual and irrevocable right and license to use, execute, perform, compile, display, copy, create derivative works of, distribute and sublicense the FreeType Project (in both source and object code forms) and derivative works thereof for any purpose; and to authorize others to exercise some or all of the rights granted herein, subject to the following conditions: o Redistribution of source code must retain this license file (`FTL.TXT') unaltered; any additions, deletions or changes to the original files must be clearly indicated in accompanying documentation. The copyright notices of the unaltered, original files must be preserved in all copies of source files. o Redistribution in binary form must provide a disclaimer that states that the software is based in part of the work of the FreeType Team, in the distribution documentation. We also encourage you to put an URL to the FreeType web page in your documentation, though this isn't mandatory. These conditions apply to any software derived from or based on the FreeType Project, not just the unmodified files. If you use our work, you must acknowledge us. However, no fee need be paid to us. 3. Advertising -------------- Neither the FreeType authors and contributors nor you shall use the name of the other for commercial, advertising, or promotional purposes without specific prior written permission. We suggest, but do not require, that you use one or more of the following phrases to refer to this software in your documentation or advertising materials: `FreeType Project', `FreeType Engine', `FreeType library', or `FreeType Distribution'. As you have not signed this license, you are not required to accept it. However, as the FreeType Project is copyrighted material, only this license, or another one contracted with the authors, grants you the right to use, distribute, and modify it. Therefore, by using, distributing, or modifying the FreeType Project, you indicate that you understand and accept all the terms of this license. 4. Contacts ----------- There are two mailing lists related to FreeType: o freetype@nongnu.org Discusses general use and applications of FreeType, as well as future and wanted additions to the library and distribution. If you are looking for support, start in this list if you haven't found anything to help you in the documentation. o freetype-devel@nongnu.org Discusses bugs, as well as engine internals, design issues, specific licenses, porting, etc. Our home page can be found at http://www.freetype.org --- end of FTL.TXT --- ================================================ FILE: external/pdfium/macos-arm64/licenses/icu.txt ================================================ UNICODE LICENSE V3 COPYRIGHT AND PERMISSION NOTICE Copyright © 2016-2025 Unicode, Inc. NOTICE TO USER: Carefully read the following legal agreement. BY DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING DATA FILES, AND/OR SOFTWARE, YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE TERMS AND CONDITIONS OF THIS AGREEMENT. IF YOU DO NOT AGREE, DO NOT DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE THE DATA FILES OR SOFTWARE. Permission is hereby granted, free of charge, to any person obtaining a copy of data files and any associated documentation (the "Data Files") or software and any associated documentation (the "Software") to deal in the Data Files or Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, and/or sell copies of the Data Files or Software, and to permit persons to whom the Data Files or Software are furnished to do so, provided that either (a) this copyright and permission notice appear with all copies of the Data Files or Software, or (b) this copyright and permission notice appear in associated Documentation. THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE DATA FILES OR SOFTWARE. Except as contained in this notice, the name of a copyright holder shall not be used in advertising or otherwise to promote the sale, use or other dealings in these Data Files or Software without prior written authorization of the copyright holder. SPDX-License-Identifier: Unicode-3.0 ---------------------------------------------------------------------- Third-Party Software Licenses This section contains third-party software notices and/or additional terms for licensed third-party software components included within ICU libraries. ---------------------------------------------------------------------- ICU License - ICU 1.8.1 to ICU 57.1 COPYRIGHT AND PERMISSION NOTICE Copyright (c) 1995-2016 International Business Machines Corporation and others All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, provided that the above copyright notice(s) and this permission notice appear in all copies of the Software and that both the above copyright notice(s) and this permission notice appear in supporting documentation. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. Except as contained in this notice, the name of a copyright holder shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization of the copyright holder. All trademarks and registered trademarks mentioned herein are the property of their respective owners. ---------------------------------------------------------------------- Chinese/Japanese Word Break Dictionary Data (cjdict.txt) # The Google Chrome software developed by Google is licensed under # the BSD license. Other software included in this distribution is # provided under other licenses, as set forth below. # # The BSD License # http://opensource.org/licenses/bsd-license.php # Copyright (C) 2006-2008, Google Inc. # # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # Redistributions of source code must retain the above copyright notice, # this list of conditions and the following disclaimer. # Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided with # the distribution. # Neither the name of Google Inc. nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. # # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND # CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR # BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # # The word list in cjdict.txt are generated by combining three word lists # listed below with further processing for compound word breaking. The # frequency is generated with an iterative training against Google web # corpora. # # * Libtabe (Chinese) # - https://sourceforge.net/project/?group_id=1519 # - Its license terms and conditions are shown below. # # * IPADIC (Japanese) # - http://chasen.aist-nara.ac.jp/chasen/distribution.html # - Its license terms and conditions are shown below. # # ---------COPYING.libtabe ---- BEGIN-------------------- # # /* # * Copyright (c) 1999 TaBE Project. # * Copyright (c) 1999 Pai-Hsiang Hsiao. # * All rights reserved. # * # * Redistribution and use in source and binary forms, with or without # * modification, are permitted provided that the following conditions # * are met: # * # * . Redistributions of source code must retain the above copyright # * notice, this list of conditions and the following disclaimer. # * . Redistributions in binary form must reproduce the above copyright # * notice, this list of conditions and the following disclaimer in # * the documentation and/or other materials provided with the # * distribution. # * . Neither the name of the TaBE Project nor the names of its # * contributors may be used to endorse or promote products derived # * from this software without specific prior written permission. # * # * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # * REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES # * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR # * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, # * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED # * OF THE POSSIBILITY OF SUCH DAMAGE. # */ # # /* # * Copyright (c) 1999 Computer Systems and Communication Lab, # * Institute of Information Science, Academia # * Sinica. All rights reserved. # * # * Redistribution and use in source and binary forms, with or without # * modification, are permitted provided that the following conditions # * are met: # * # * . Redistributions of source code must retain the above copyright # * notice, this list of conditions and the following disclaimer. # * . Redistributions in binary form must reproduce the above copyright # * notice, this list of conditions and the following disclaimer in # * the documentation and/or other materials provided with the # * distribution. # * . Neither the name of the Computer Systems and Communication Lab # * nor the names of its contributors may be used to endorse or # * promote products derived from this software without specific # * prior written permission. # * # * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # * REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES # * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR # * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, # * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED # * OF THE POSSIBILITY OF SUCH DAMAGE. # */ # # Copyright 1996 Chih-Hao Tsai @ Beckman Institute, # University of Illinois # c-tsai4@uiuc.edu http://casper.beckman.uiuc.edu/~c-tsai4 # # ---------------COPYING.libtabe-----END-------------------------------- # # # ---------------COPYING.ipadic-----BEGIN------------------------------- # # Copyright 2000, 2001, 2002, 2003 Nara Institute of Science # and Technology. All Rights Reserved. # # Use, reproduction, and distribution of this software is permitted. # Any copy of this software, whether in its original form or modified, # must include both the above copyright notice and the following # paragraphs. # # Nara Institute of Science and Technology (NAIST), # the copyright holders, disclaims all warranties with regard to this # software, including all implied warranties of merchantability and # fitness, in no event shall NAIST be liable for # any special, indirect or consequential damages or any damages # whatsoever resulting from loss of use, data or profits, whether in an # action of contract, negligence or other tortuous action, arising out # of or in connection with the use or performance of this software. # # A large portion of the dictionary entries # originate from ICOT Free Software. The following conditions for ICOT # Free Software applies to the current dictionary as well. # # Each User may also freely distribute the Program, whether in its # original form or modified, to any third party or parties, PROVIDED # that the provisions of Section 3 ("NO WARRANTY") will ALWAYS appear # on, or be attached to, the Program, which is distributed substantially # in the same form as set out herein and that such intended # distribution, if actually made, will neither violate or otherwise # contravene any of the laws and regulations of the countries having # jurisdiction over the User or the intended distribution itself. # # NO WARRANTY # # The program was produced on an experimental basis in the course of the # research and development conducted during the project and is provided # to users as so produced on an experimental basis. Accordingly, the # program is provided without any warranty whatsoever, whether express, # implied, statutory or otherwise. The term "warranty" used herein # includes, but is not limited to, any warranty of the quality, # performance, merchantability and fitness for a particular purpose of # the program and the nonexistence of any infringement or violation of # any right of any third party. # # Each user of the program will agree and understand, and be deemed to # have agreed and understood, that there is no warranty whatsoever for # the program and, accordingly, the entire risk arising from or # otherwise connected with the program is assumed by the user. # # Therefore, neither ICOT, the copyright holder, or any other # organization that participated in or was otherwise related to the # development of the program and their respective officials, directors, # officers and other employees shall be held liable for any and all # damages, including, without limitation, general, special, incidental # and consequential damages, arising out of or otherwise in connection # with the use or inability to use the program or any product, material # or result produced or otherwise obtained by using the program, # regardless of whether they have been advised of, or otherwise had # knowledge of, the possibility of such damages at any time during the # project or thereafter. Each user will be deemed to have agreed to the # foregoing by his or her commencement of use of the program. The term # "use" as used herein includes, but is not limited to, the use, # modification, copying and distribution of the program and the # production of secondary products from the program. # # In the case where the program, whether in its original form or # modified, was distributed or delivered to or received by a user from # any person, organization or entity other than ICOT, unless it makes or # grants independently of ICOT any specific warranty to the user in # writing, such person, organization or entity, will also be exempted # from and not be held liable to the user for any such damages as noted # above as far as the program is concerned. # # ---------------COPYING.ipadic-----END---------------------------------- ---------------------------------------------------------------------- Lao Word Break Dictionary Data (laodict.txt) # Copyright (C) 2016 and later: Unicode, Inc. and others. # License & terms of use: http://www.unicode.org/copyright.html # Copyright (c) 2015 International Business Machines Corporation # and others. All Rights Reserved. # # Project: https://github.com/rober42539/lao-dictionary # Dictionary: https://github.com/rober42539/lao-dictionary/laodict.txt # License: https://github.com/rober42539/lao-dictionary/LICENSE.txt # (copied below) # # This file is derived from the above dictionary version of Nov 22, 2020 # ---------------------------------------------------------------------- # Copyright (C) 2013 Brian Eugene Wilson, Robert Martin Campbell. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # Redistributions of source code must retain the above copyright notice, this # list of conditions and the following disclaimer. Redistributions in binary # form must reproduce the above copyright notice, this list of conditions and # the following disclaimer in the documentation and/or other materials # provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, # INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED # OF THE POSSIBILITY OF SUCH DAMAGE. # -------------------------------------------------------------------------- ---------------------------------------------------------------------- Burmese Word Break Dictionary Data (burmesedict.txt) # Copyright (c) 2014 International Business Machines Corporation # and others. All Rights Reserved. # # This list is part of a project hosted at: # github.com/kanyawtech/myanmar-karen-word-lists # # -------------------------------------------------------------------------- # Copyright (c) 2013, LeRoy Benjamin Sharon # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: Redistributions of source code must retain the above # copyright notice, this list of conditions and the following # disclaimer. Redistributions in binary form must reproduce the # above copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # # Neither the name Myanmar Karen Word Lists, nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND # CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED # TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR # TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF # THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # -------------------------------------------------------------------------- ---------------------------------------------------------------------- Time Zone Database ICU uses the public domain data and code derived from Time Zone Database for its time zone support. The ownership of the TZ database is explained in BCP 175: Procedure for Maintaining the Time Zone Database section 7. # 7. Database Ownership # # The TZ database itself is not an IETF Contribution or an IETF # document. Rather it is a pre-existing and regularly updated work # that is in the public domain, and is intended to remain in the # public domain. Therefore, BCPs 78 [RFC5378] and 79 [RFC3979] do # not apply to the TZ Database or contributions that individuals make # to it. Should any claims be made and substantiated against the TZ # Database, the organization that is providing the IANA # Considerations defined in this RFC, under the memorandum of # understanding with the IETF, currently ICANN, may act in accordance # with all competent court orders. No ownership claims will be made # by ICANN or the IETF Trust on the database or the code. Any person # making a contribution to the database or code waives all rights to # future claims in that contribution or in the TZ Database. ---------------------------------------------------------------------- Google double-conversion Copyright 2006-2011, the V8 project authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Google Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- JSON parsing library (nlohmann/json) File: vendor/json/upstream/single_include/nlohmann/json.hpp (only for ICU4C) MIT License Copyright (c) 2013-2022 Niels Lohmann Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ---------------------------------------------------------------------- File: aclocal.m4 (only for ICU4C) Section: pkg.m4 - Macros to locate and utilise pkg-config. Copyright © 2004 Scott James Remnant . Copyright © 2012-2015 Dan Nicholson 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 2 of the License, or (at your option) 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. As a special exception to the GNU General Public License, if you distribute this file as part of a program that contains a configuration script generated by Autoconf, you may include it under the same distribution terms that you use for the rest of that program. (The condition for the exception is fulfilled because ICU4C includes a configuration script generated by Autoconf, namely the `configure` script.) ---------------------------------------------------------------------- File: config.guess (only for ICU4C) This file 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 (at your option) 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, see . As a special exception to the GNU General Public License, if you distribute this file as part of a program that contains a configuration script generated by Autoconf, you may include it under the same distribution terms that you use for the rest of that program. This Exception is an additional permission under section 7 of the GNU General Public License, version 3 ("GPLv3"). (The condition for the exception is fulfilled because ICU4C includes a configuration script generated by Autoconf, namely the `configure` script.) ---------------------------------------------------------------------- File: install-sh (only for ICU4C) Copyright 1991 by the Massachusetts Institute of Technology Permission to use, copy, modify, distribute, and sell this software and its documentation for any purpose is hereby granted without fee, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the name of M.I.T. not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. M.I.T. makes no representations about the suitability of this software for any purpose. It is provided "as is" without express or implied warranty. ================================================ FILE: external/pdfium/macos-arm64/licenses/lcms.txt ================================================ //--------------------------------------------------------------------------------- // // Little Color Management System // Copyright (c) 1998-2023 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), // to deal in the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the Software // is furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO // THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // //--------------------------------------------------------------------------------- // // Version 2.15 // ================================================ FILE: external/pdfium/macos-arm64/licenses/libjpeg_turbo.ijg ================================================ libjpeg-turbo note: This file has been modified by The libjpeg-turbo Project to include only information relevant to libjpeg-turbo, to wordsmith certain sections, and to remove impolitic language that existed in the libjpeg v8 README. It is included only for reference. Please see README.md for information specific to libjpeg-turbo. The Independent JPEG Group's JPEG software ========================================== This distribution contains a release of the Independent JPEG Group's free JPEG software. You are welcome to redistribute this software and to use it for any purpose, subject to the conditions under LEGAL ISSUES, below. This software is the work of Tom Lane, Guido Vollbeding, Philip Gladstone, Bill Allombert, Jim Boucher, Lee Crocker, Bob Friesenhahn, Ben Jackson, Julian Minguillon, Luis Ortiz, George Phillips, Davide Rossi, Ge' Weijers, and other members of the Independent JPEG Group. IJG is not affiliated with the ISO/IEC JTC1/SC29/WG1 standards committee (also known as JPEG, together with ITU-T SG16). DOCUMENTATION ROADMAP ===================== This file contains the following sections: OVERVIEW General description of JPEG and the IJG software. LEGAL ISSUES Copyright, lack of warranty, terms of distribution. REFERENCES Where to learn more about JPEG. ARCHIVE LOCATIONS Where to find newer versions of this software. FILE FORMAT WARS Software *not* to get. TO DO Plans for future IJG releases. Other documentation files in the distribution are: User documentation: doc/usage.txt Usage instructions for cjpeg, djpeg, jpegtran, rdjpgcom, and wrjpgcom. doc/*.1 Unix-style man pages for programs (same info as usage.txt). doc/wizard.txt Advanced usage instructions for JPEG wizards only. doc/change.log Version-to-version change highlights. Programmer and internal documentation: doc/libjpeg.txt How to use the JPEG library in your own programs. src/example.c Sample code for calling the JPEG library. doc/structure.txt Overview of the JPEG library's internal structure. doc/coderules.txt Coding style rules --- please read if you contribute code. Please read at least usage.txt. Some information can also be found in the JPEG FAQ (Frequently Asked Questions) article. See ARCHIVE LOCATIONS below to find out where to obtain the FAQ article. If you want to understand how the JPEG code works, we suggest reading one or more of the REFERENCES, then looking at the documentation files (in roughly the order listed) before diving into the code. OVERVIEW ======== This package contains C software to implement JPEG image encoding, decoding, and transcoding. JPEG (pronounced "jay-peg") is a standardized compression method for full-color and grayscale images. JPEG's strong suit is compressing photographic images or other types of images that have smooth color and brightness transitions between neighboring pixels. Images with sharp lines or other abrupt features may not compress well with JPEG, and a higher JPEG quality may have to be used to avoid visible compression artifacts with such images. JPEG is normally lossy, meaning that the output pixels are not necessarily identical to the input pixels. However, on photographic content and other "smooth" images, very good compression ratios can be obtained with no visible compression artifacts, and extremely high compression ratios are possible if you are willing to sacrifice image quality (by reducing the "quality" setting in the compressor.) This software implements JPEG baseline, extended-sequential, progressive, and lossless compression processes. Provision is made for supporting all variants of these processes, although some uncommon parameter settings aren't implemented yet. We have made no provision for supporting the hierarchical processes defined in the standard. We provide a set of library routines for reading and writing JPEG image files, plus two sample applications "cjpeg" and "djpeg", which use the library to perform conversion between JPEG and some other popular image file formats. The library is intended to be reused in other applications. In order to support file conversion and viewing software, we have included considerable functionality beyond the bare JPEG coding/decoding capability; for example, the color quantization modules are not strictly part of JPEG decoding, but they are essential for output to colormapped file formats. These extra functions can be compiled out of the library if not required for a particular application. We have also included "jpegtran", a utility for lossless transcoding between different JPEG processes, and "rdjpgcom" and "wrjpgcom", two simple applications for inserting and extracting textual comments in JFIF files. The emphasis in designing this software has been on achieving portability and flexibility, while also making it fast enough to be useful. In particular, the software is not intended to be read as a tutorial on JPEG. (See the REFERENCES section for introductory material.) Rather, it is intended to be reliable, portable, industrial-strength code. We do not claim to have achieved that goal in every aspect of the software, but we strive for it. We welcome the use of this software as a component of commercial products. No royalty is required, but we do ask for an acknowledgement in product documentation, as described under LEGAL ISSUES. LEGAL ISSUES ============ In plain English: 1. We don't promise that this software works. (But if you find any bugs, please let us know!) 2. You can use this software for whatever you want. You don't have to pay us. 3. You may not pretend that you wrote this software. If you use it in a program, you must acknowledge somewhere in your documentation that you've used the IJG code. In legalese: The authors make NO WARRANTY or representation, either express or implied, with respect to this software, its quality, accuracy, merchantability, or fitness for a particular purpose. This software is provided "AS IS", and you, its user, assume the entire risk as to its quality and accuracy. This software is copyright (C) 1991-2020, Thomas G. Lane, Guido Vollbeding. All Rights Reserved except as specified below. Permission is hereby granted to use, copy, modify, and distribute this software (or portions thereof) for any purpose, without fee, subject to these conditions: (1) If any part of the source code for this software is distributed, then this README file must be included, with this copyright and no-warranty notice unaltered; and any additions, deletions, or changes to the original files must be clearly indicated in accompanying documentation. (2) If only executable code is distributed, then the accompanying documentation must state that "this software is based in part on the work of the Independent JPEG Group". (3) Permission for use of this software is granted only if the user accepts full responsibility for any undesirable consequences; the authors accept NO LIABILITY for damages of any kind. These conditions apply to any software derived from or based on the IJG code, not just to the unmodified library. If you use our work, you ought to acknowledge us. Permission is NOT granted for the use of any IJG author's name or company name in advertising or publicity relating to this software or products derived from it. This software may be referred to only as "the Independent JPEG Group's software". We specifically permit and encourage the use of this software as the basis of commercial products, provided that all warranty or liability claims are assumed by the product vendor. REFERENCES ========== We recommend reading one or more of these references before trying to understand the innards of the JPEG software. The best short technical introduction to the JPEG compression algorithm is Wallace, Gregory K. "The JPEG Still Picture Compression Standard", Communications of the ACM, April 1991 (vol. 34 no. 4), pp. 30-44. (Adjacent articles in that issue discuss MPEG motion picture compression, applications of JPEG, and related topics.) If you don't have the CACM issue handy, a PDF file containing a revised version of Wallace's article is available at http://www.ijg.org/files/Wallace.JPEG.pdf. The file (actually a preprint for an article that appeared in IEEE Trans. Consumer Electronics) omits the sample images that appeared in CACM, but it includes corrections and some added material. Note: the Wallace article is copyright ACM and IEEE, and it may not be used for commercial purposes. A somewhat less technical, more leisurely introduction to JPEG can be found in "The Data Compression Book" by Mark Nelson and Jean-loup Gailly, published by M&T Books (New York), 2nd ed. 1996, ISBN 1-55851-434-1. This book provides good explanations and example C code for a multitude of compression methods including JPEG. It is an excellent source if you are comfortable reading C code but don't know much about data compression in general. The book's JPEG sample code is far from industrial-strength, but when you are ready to look at a full implementation, you've got one here... The best currently available description of JPEG is the textbook "JPEG Still Image Data Compression Standard" by William B. Pennebaker and Joan L. Mitchell, published by Van Nostrand Reinhold, 1993, ISBN 0-442-01272-1. Price US$59.95, 638 pp. The book includes the complete text of the ISO JPEG standards (DIS 10918-1 and draft DIS 10918-2). The original JPEG standard is divided into two parts, Part 1 being the actual specification, while Part 2 covers compliance testing methods. Part 1 is titled "Digital Compression and Coding of Continuous-tone Still Images, Part 1: Requirements and guidelines" and has document numbers ISO/IEC IS 10918-1, ITU-T T.81. Part 2 is titled "Digital Compression and Coding of Continuous-tone Still Images, Part 2: Compliance testing" and has document numbers ISO/IEC IS 10918-2, ITU-T T.83. The JPEG standard does not specify all details of an interchangeable file format. For the omitted details, we follow the "JFIF" conventions, revision 1.02. JFIF version 1 has been adopted as ISO/IEC 10918-5 (05/2013) and Recommendation ITU-T T.871 (05/2011): Information technology - Digital compression and coding of continuous-tone still images: JPEG File Interchange Format (JFIF). It is available as a free download in PDF file format from https://www.iso.org/standard/54989.html and http://www.itu.int/rec/T-REC-T.871. A PDF file of the older JFIF 1.02 specification is available at http://www.w3.org/Graphics/JPEG/jfif3.pdf. The TIFF 6.0 file format specification can be obtained from http://mirrors.ctan.org/graphics/tiff/TIFF6.ps.gz. The JPEG incorporation scheme found in the TIFF 6.0 spec of 3-June-92 has a number of serious problems. IJG does not recommend use of the TIFF 6.0 design (TIFF Compression tag 6). Instead, we recommend the JPEG design proposed by TIFF Technical Note #2 (Compression tag 7). Copies of this Note can be obtained from http://www.ijg.org/files/. It is expected that the next revision of the TIFF spec will replace the 6.0 JPEG design with the Note's design. Although IJG's own code does not support TIFF/JPEG, the free libtiff library uses our library to implement TIFF/JPEG per the Note. ARCHIVE LOCATIONS ================= The "official" archive site for this software is www.ijg.org. The most recent released version can always be found there in directory "files". The JPEG FAQ (Frequently Asked Questions) article is a source of some general information about JPEG. It is available at http://www.faqs.org/faqs/jpeg-faq. FILE FORMAT COMPATIBILITY ========================= This software implements ITU T.81 | ISO/IEC 10918 with some extensions from ITU T.871 | ISO/IEC 10918-5 (JPEG File Interchange Format-- see REFERENCES). Informally, the term "JPEG image" or "JPEG file" most often refers to JFIF or a subset thereof, but there are other formats containing the name "JPEG" that are incompatible with the original JPEG standard or with JFIF (for instance, JPEG 2000 and JPEG XR). This software therefore does not support these formats. Indeed, one of the original reasons for developing this free software was to help force convergence on a common, interoperable format standard for JPEG files. JFIF is a minimal or "low end" representation. TIFF/JPEG (TIFF revision 6.0 as modified by TIFF Technical Note #2) can be used for "high end" applications that need to record a lot of additional data about an image. TO DO ===== Please send bug reports, offers of help, etc. to jpeg-info@jpegclub.org. ================================================ FILE: external/pdfium/macos-arm64/licenses/libjpeg_turbo.md ================================================ libjpeg-turbo Licenses ====================== libjpeg-turbo is covered by two compatible BSD-style open source licenses: - The IJG (Independent JPEG Group) License, which is listed in [README.ijg](README.ijg) This license applies to the libjpeg API library and associated programs, including any code inherited from libjpeg and any modifications to that code. Note that the libjpeg-turbo SIMD source code bears the [zlib License](https://opensource.org/licenses/Zlib), but in the context of the overall libjpeg API library, the terms of the zlib License are subsumed by the terms of the IJG License. - The Modified (3-clause) BSD License, which is listed below This license applies to the TurboJPEG API library and associated programs, as well as the build system. Note that the TurboJPEG API library wraps the libjpeg API library, so in the context of the overall TurboJPEG API library, both the terms of the IJG License and the terms of the Modified (3-clause) BSD License apply. Complying with the libjpeg-turbo Licenses ========================================= This section provides a roll-up of the libjpeg-turbo licensing terms, to the best of our understanding. This is not a license in and of itself. It is intended solely for clarification. 1. If you are distributing a modified version of the libjpeg-turbo source, then: 1. You cannot alter or remove any existing copyright or license notices from the source. **Origin** - Clause 1 of the IJG License - Clause 1 of the Modified BSD License - Clauses 1 and 3 of the zlib License 2. You must add your own copyright notice to the header of each source file you modified, so others can tell that you modified that file. (If there is not an existing copyright header in that file, then you can simply add a notice stating that you modified the file.) **Origin** - Clause 1 of the IJG License - Clause 2 of the zlib License 3. You must include the IJG README file, and you must not alter any of the copyright or license text in that file. **Origin** - Clause 1 of the IJG License 2. If you are distributing only libjpeg-turbo binaries without the source, or if you are distributing an application that statically links with libjpeg-turbo, then: 1. Your product documentation must include a message stating: This software is based in part on the work of the Independent JPEG Group. **Origin** - Clause 2 of the IJG license 2. If your binary distribution includes or uses the TurboJPEG API, then your product documentation must include the text of the Modified BSD License (see below.) **Origin** - Clause 2 of the Modified BSD License 3. You cannot use the name of the IJG or The libjpeg-turbo Project or the contributors thereof in advertising, publicity, etc. **Origin** - IJG License - Clause 3 of the Modified BSD License 4. The IJG and The libjpeg-turbo Project do not warrant libjpeg-turbo to be free of defects, nor do we accept any liability for undesirable consequences resulting from your use of the software. **Origin** - IJG License - Modified BSD License - zlib License The Modified (3-clause) BSD License =================================== Copyright (C)2009-2024 D. R. Commander. All Rights Reserved.
Copyright (C)2015 Viktor Szathmáry. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - Neither the name of the libjpeg-turbo Project nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Why Two Licenses? ================= The zlib License could have been used instead of the Modified (3-clause) BSD License, and since the IJG License effectively subsumes the distribution conditions of the zlib License, this would have effectively placed libjpeg-turbo binary distributions under the IJG License. However, the IJG License specifically refers to the Independent JPEG Group and does not extend attribution and endorsement protections to other entities. Thus, it was desirable to choose a license that granted us the same protections for new code that were granted to the IJG for code derived from their software. ================================================ FILE: external/pdfium/macos-arm64/licenses/libopenjpeg.txt ================================================ /* * The copyright in this software is being made available under the 2-clauses * BSD License, included below. This software may be subject to other third * party and contributor rights, including patent rights, and no such rights * are granted under this license. * * Copyright (c) 2005, Herve Drolon, FreeImage Team * Copyright (c) 2008, 2011-2012, Centre National d'Etudes Spatiales (CNES), FR * Copyright (c) 2012, CS Systemes d'Information, France * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ ================================================ FILE: external/pdfium/macos-arm64/licenses/libpng.txt ================================================ COPYRIGHT NOTICE, DISCLAIMER, and LICENSE ========================================= PNG Reference Library License version 2 --------------------------------------- * Copyright (c) 1995-2019 The PNG Reference Library Authors. * Copyright (c) 2018-2019 Cosmin Truta. * Copyright (c) 2000-2002, 2004, 2006-2018 Glenn Randers-Pehrson. * Copyright (c) 1996-1997 Andreas Dilger. * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. The software is supplied "as is", without warranty of any kind, express or implied, including, without limitation, the warranties of merchantability, fitness for a particular purpose, title, and non-infringement. In no event shall the Copyright owners, or anyone distributing the software, be liable for any damages or other liability, whether in contract, tort or otherwise, arising from, out of, or in connection with the software, or the use or other dealings in the software, even if advised of the possibility of such damage. Permission is hereby granted to use, copy, modify, and distribute this software, or portions hereof, for any purpose, without fee, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated, but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This Copyright notice may not be removed or altered from any source or altered source distribution. PNG Reference Library License version 1 (for libpng 0.5 through 1.6.35) ----------------------------------------------------------------------- libpng versions 1.0.7, July 1, 2000, through 1.6.35, July 15, 2018 are Copyright (c) 2000-2002, 2004, 2006-2018 Glenn Randers-Pehrson, are derived from libpng-1.0.6, and are distributed according to the same disclaimer and license as libpng-1.0.6 with the following individuals added to the list of Contributing Authors: Simon-Pierre Cadieux Eric S. Raymond Mans Rullgard Cosmin Truta Gilles Vollant James Yu Mandar Sahastrabuddhe Google Inc. Vadim Barkov and with the following additions to the disclaimer: There is no warranty against interference with your enjoyment of the library or against infringement. There is no warranty that our efforts or the library will fulfill any of your particular purposes or needs. This library is provided with all faults, and the entire risk of satisfactory quality, performance, accuracy, and effort is with the user. Some files in the "contrib" directory and some configure-generated files that are distributed with libpng have other copyright owners, and are released under other open source licenses. libpng versions 0.97, January 1998, through 1.0.6, March 20, 2000, are Copyright (c) 1998-2000 Glenn Randers-Pehrson, are derived from libpng-0.96, and are distributed according to the same disclaimer and license as libpng-0.96, with the following individuals added to the list of Contributing Authors: Tom Lane Glenn Randers-Pehrson Willem van Schaik libpng versions 0.89, June 1996, through 0.96, May 1997, are Copyright (c) 1996-1997 Andreas Dilger, are derived from libpng-0.88, and are distributed according to the same disclaimer and license as libpng-0.88, with the following individuals added to the list of Contributing Authors: John Bowler Kevin Bracey Sam Bushell Magnus Holmgren Greg Roelofs Tom Tanner Some files in the "scripts" directory have other copyright owners, but are released under this license. libpng versions 0.5, May 1995, through 0.88, January 1996, are Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. For the purposes of this copyright and license, "Contributing Authors" is defined as the following set of individuals: Andreas Dilger Dave Martindale Guy Eric Schalnat Paul Schmidt Tim Wegner The PNG Reference Library is supplied "AS IS". The Contributing Authors and Group 42, Inc. disclaim all warranties, expressed or implied, including, without limitation, the warranties of merchantability and of fitness for any purpose. The Contributing Authors and Group 42, Inc. assume no liability for direct, indirect, incidental, special, exemplary, or consequential damages, which may result from the use of the PNG Reference Library, even if advised of the possibility of such damage. Permission is hereby granted to use, copy, modify, and distribute this source code, or portions hereof, for any purpose, without fee, subject to the following restrictions: 1. The origin of this source code must not be misrepresented. 2. Altered versions must be plainly marked as such and must not be misrepresented as being the original source. 3. This Copyright notice may not be removed or altered from any source or altered source distribution. The Contributing Authors and Group 42, Inc. specifically permit, without fee, and encourage the use of this source code as a component to supporting the PNG file format in commercial products. If you use this source code in a product, acknowledgment is not required but would be appreciated. ================================================ FILE: external/pdfium/macos-arm64/licenses/libtiff.txt ================================================ Copyright (c) 1988-1997 Sam Leffler Copyright (c) 1991-1997 Silicon Graphics, Inc. Permission to use, copy, modify, distribute, and sell this software and its documentation for any purpose is hereby granted without fee, provided that (i) the above copyright notices and this permission notice appear in all copies of the software and related documentation, and (ii) the names of Sam Leffler and Silicon Graphics may not be used in any advertising or publicity relating to the software without the specific, prior written permission of Sam Leffler and Silicon Graphics. THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ================================================ FILE: external/pdfium/macos-arm64/licenses/llvm-libc.txt ================================================ ============================================================================== The LLVM Project is under the Apache License v2.0 with LLVM Exceptions: ============================================================================== Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ---- LLVM Exceptions to the Apache 2.0 License ---- As an exception, if, as a result of your compiling your source code, portions of this Software are embedded into an Object form of such source code, you may redistribute such embedded portions in such Object form without complying with the conditions of Sections 4(a), 4(b) and 4(d) of the License. In addition, if you combine or link compiled forms of this Software with software that is licensed under the GPLv2 ("Combined Software") and if a court of competent jurisdiction determines that the patent provision (Section 3), the indemnity provision (Section 9) or other Section of the License conflicts with the conditions of the GPLv2, you may retroactively and prospectively choose to deem waived or otherwise exclude such Section(s) of the License, but only in their entirety and only with respect to the Combined Software. ============================================================================== Software from third parties included in the LLVM Project: ============================================================================== The LLVM Project contains third party software which is under different license terms. All such code will be identified clearly using at least one of two mechanisms: 1) It will be in a separate directory tree with its own `LICENSE.txt` or `LICENSE` file at the top containing the specific license and restrictions which apply to that software, or 2) It will contain specific license and restriction terms at the top of every file. ============================================================================== Legacy LLVM License (https://llvm.org/docs/DeveloperPolicy.html#legacy): ============================================================================== University of Illinois/NCSA Open Source License Copyright (c) 2007-2019 University of Illinois at Urbana-Champaign. All rights reserved. Developed by: LLVM Team University of Illinois at Urbana-Champaign http://llvm.org Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal with the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimers. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimers in the documentation and/or other materials provided with the distribution. * Neither the names of the LLVM Team, University of Illinois at Urbana-Champaign, nor the names of its contributors may be used to endorse or promote products derived from this Software without specific prior written permission. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE. ================================================ FILE: external/pdfium/macos-arm64/licenses/pdfium.txt ================================================ // Copyright 2014 The PDFium Authors // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Apache License Version 2.0, January 2004 https://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: external/pdfium/macos-arm64/licenses/simdutf.txt ================================================ Copyright 2021 The simdutf authors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: external/pdfium/macos-arm64/licenses/zlib.txt ================================================ /* zlib.h -- interface of the 'zlib' general purpose compression library version 1.3.1, January 22nd, 2024 Copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. Jean-loup Gailly Mark Adler jloup@gzip.org madler@alumni.caltech.edu The data format used by the zlib library is described by RFCs (Request for Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950 (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format). */ ================================================ FILE: external/pdfium/macos-x64/LICENSE ================================================ Copyright 2014-2025 Benoit Blanchon Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. This package also includes third-party software. See the licenses/ directory for their respective licenses. ================================================ FILE: external/pdfium/macos-x64/PDFiumConfig.cmake ================================================ # PDFium Package Configuration for CMake # # To use PDFium in your CMake project: # # 1. set the environment variable PDFium_DIR to the folder containing this file. # 2. in your CMakeLists.txt, add # find_package(PDFium) # 3. then link your executable with PDFium # target_link_libraries(my_exe pdfium) include(FindPackageHandleStandardArgs) find_path(PDFium_INCLUDE_DIR NAMES "fpdfview.h" PATHS "${CMAKE_CURRENT_LIST_DIR}" PATH_SUFFIXES "include" ) set(PDFium_VERSION "147.0.7713.0") if(WIN32) find_file(PDFium_LIBRARY NAMES "pdfium.dll" PATHS "${CMAKE_CURRENT_LIST_DIR}" PATH_SUFFIXES "bin") find_file(PDFium_IMPLIB NAMES "pdfium.dll.lib" PATHS "${CMAKE_CURRENT_LIST_DIR}" PATH_SUFFIXES "lib") add_library(pdfium SHARED IMPORTED) set_target_properties(pdfium PROPERTIES IMPORTED_LOCATION "${PDFium_LIBRARY}" IMPORTED_IMPLIB "${PDFium_IMPLIB}" INTERFACE_INCLUDE_DIRECTORIES "${PDFium_INCLUDE_DIR};${PDFium_INCLUDE_DIR}/cpp" ) find_package_handle_standard_args(PDFium REQUIRED_VARS PDFium_LIBRARY PDFium_IMPLIB PDFium_INCLUDE_DIR VERSION_VAR PDFium_VERSION ) else() find_library(PDFium_LIBRARY NAMES "pdfium" PATHS "${CMAKE_CURRENT_LIST_DIR}" PATH_SUFFIXES "lib") add_library(pdfium SHARED IMPORTED) set_target_properties(pdfium PROPERTIES IMPORTED_LOCATION "${PDFium_LIBRARY}" INTERFACE_INCLUDE_DIRECTORIES "${PDFium_INCLUDE_DIR};${PDFium_INCLUDE_DIR}/cpp" ) find_package_handle_standard_args(PDFium REQUIRED_VARS PDFium_LIBRARY PDFium_INCLUDE_DIR VERSION_VAR PDFium_VERSION ) endif() ================================================ FILE: external/pdfium/macos-x64/VERSION ================================================ MAJOR=147 MINOR=0 BUILD=7713 PATCH=0 ================================================ FILE: external/pdfium/macos-x64/args.gn ================================================ clang_use_chrome_plugins = false is_component_build = false is_debug = false pdf_enable_v8 = false pdf_enable_xfa = false pdf_is_standalone = true pdf_use_partition_alloc = false target_cpu = "x64" target_os = "mac" treat_warnings_as_errors = false ================================================ FILE: external/pdfium/macos-x64/include/cpp/fpdf_deleters.h ================================================ // Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef PUBLIC_CPP_FPDF_DELETERS_H_ #define PUBLIC_CPP_FPDF_DELETERS_H_ #include "../fpdf_annot.h" #include "../fpdf_dataavail.h" #include "../fpdf_edit.h" #include "../fpdf_formfill.h" #include "../fpdf_javascript.h" #include "../fpdf_structtree.h" #include "../fpdf_text.h" #include "../fpdf_transformpage.h" #include "../fpdfview.h" // Custom deleters for using FPDF_* types with std::unique_ptr<>. struct FPDFAnnotationDeleter { inline void operator()(FPDF_ANNOTATION annot) { FPDFPage_CloseAnnot(annot); } }; struct FPDFAvailDeleter { inline void operator()(FPDF_AVAIL avail) { FPDFAvail_Destroy(avail); } }; struct FPDFBitmapDeleter { inline void operator()(FPDF_BITMAP bitmap) { FPDFBitmap_Destroy(bitmap); } }; struct FPDFClipPathDeleter { inline void operator()(FPDF_CLIPPATH clip_path) { FPDF_DestroyClipPath(clip_path); } }; struct FPDFDocumentDeleter { inline void operator()(FPDF_DOCUMENT doc) { FPDF_CloseDocument(doc); } }; struct FPDFFontDeleter { inline void operator()(FPDF_FONT font) { FPDFFont_Close(font); } }; struct FPDFFormHandleDeleter { inline void operator()(FPDF_FORMHANDLE form) { FPDFDOC_ExitFormFillEnvironment(form); } }; struct FPDFJavaScriptActionDeleter { inline void operator()(FPDF_JAVASCRIPT_ACTION javascript) { FPDFDoc_CloseJavaScriptAction(javascript); } }; struct FPDFPageDeleter { inline void operator()(FPDF_PAGE page) { FPDF_ClosePage(page); } }; struct FPDFPageLinkDeleter { inline void operator()(FPDF_PAGELINK pagelink) { FPDFLink_CloseWebLinks(pagelink); } }; struct FPDFPageObjectDeleter { inline void operator()(FPDF_PAGEOBJECT object) { FPDFPageObj_Destroy(object); } }; struct FPDFStructTreeDeleter { inline void operator()(FPDF_STRUCTTREE tree) { FPDF_StructTree_Close(tree); } }; struct FPDFTextFindDeleter { inline void operator()(FPDF_SCHHANDLE handle) { FPDFText_FindClose(handle); } }; struct FPDFTextPageDeleter { inline void operator()(FPDF_TEXTPAGE text) { FPDFText_ClosePage(text); } }; #endif // PUBLIC_CPP_FPDF_DELETERS_H_ ================================================ FILE: external/pdfium/macos-x64/include/cpp/fpdf_scopers.h ================================================ // Copyright 2018 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef PUBLIC_CPP_FPDF_SCOPERS_H_ #define PUBLIC_CPP_FPDF_SCOPERS_H_ #include #include #include "fpdf_deleters.h" // Versions of FPDF types that clean up the object at scope exit. using ScopedFPDFAnnotation = std::unique_ptr::type, FPDFAnnotationDeleter>; using ScopedFPDFAvail = std::unique_ptr::type, FPDFAvailDeleter>; using ScopedFPDFBitmap = std::unique_ptr::type, FPDFBitmapDeleter>; using ScopedFPDFClipPath = std::unique_ptr::type, FPDFClipPathDeleter>; using ScopedFPDFDocument = std::unique_ptr::type, FPDFDocumentDeleter>; using ScopedFPDFFont = std::unique_ptr::type, FPDFFontDeleter>; using ScopedFPDFFormHandle = std::unique_ptr::type, FPDFFormHandleDeleter>; using ScopedFPDFJavaScriptAction = std::unique_ptr::type, FPDFJavaScriptActionDeleter>; using ScopedFPDFPage = std::unique_ptr::type, FPDFPageDeleter>; using ScopedFPDFPageLink = std::unique_ptr::type, FPDFPageLinkDeleter>; using ScopedFPDFPageObject = std::unique_ptr::type, FPDFPageObjectDeleter>; using ScopedFPDFStructTree = std::unique_ptr::type, FPDFStructTreeDeleter>; using ScopedFPDFTextFind = std::unique_ptr::type, FPDFTextFindDeleter>; using ScopedFPDFTextPage = std::unique_ptr::type, FPDFTextPageDeleter>; #endif // PUBLIC_CPP_FPDF_SCOPERS_H_ ================================================ FILE: external/pdfium/macos-x64/include/fpdf_annot.h ================================================ // Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef PUBLIC_FPDF_ANNOT_H_ #define PUBLIC_FPDF_ANNOT_H_ #include // NOLINTNEXTLINE(build/include) #include "fpdfview.h" // NOLINTNEXTLINE(build/include) #include "fpdf_formfill.h" #ifdef __cplusplus extern "C" { #endif // __cplusplus #define FPDF_ANNOT_UNKNOWN 0 #define FPDF_ANNOT_TEXT 1 #define FPDF_ANNOT_LINK 2 #define FPDF_ANNOT_FREETEXT 3 #define FPDF_ANNOT_LINE 4 #define FPDF_ANNOT_SQUARE 5 #define FPDF_ANNOT_CIRCLE 6 #define FPDF_ANNOT_POLYGON 7 #define FPDF_ANNOT_POLYLINE 8 #define FPDF_ANNOT_HIGHLIGHT 9 #define FPDF_ANNOT_UNDERLINE 10 #define FPDF_ANNOT_SQUIGGLY 11 #define FPDF_ANNOT_STRIKEOUT 12 #define FPDF_ANNOT_STAMP 13 #define FPDF_ANNOT_CARET 14 #define FPDF_ANNOT_INK 15 #define FPDF_ANNOT_POPUP 16 #define FPDF_ANNOT_FILEATTACHMENT 17 #define FPDF_ANNOT_SOUND 18 #define FPDF_ANNOT_MOVIE 19 #define FPDF_ANNOT_WIDGET 20 #define FPDF_ANNOT_SCREEN 21 #define FPDF_ANNOT_PRINTERMARK 22 #define FPDF_ANNOT_TRAPNET 23 #define FPDF_ANNOT_WATERMARK 24 #define FPDF_ANNOT_THREED 25 #define FPDF_ANNOT_RICHMEDIA 26 #define FPDF_ANNOT_XFAWIDGET 27 #define FPDF_ANNOT_REDACT 28 // Refer to PDF Reference (6th edition) table 8.16 for all annotation flags. #define FPDF_ANNOT_FLAG_NONE 0 #define FPDF_ANNOT_FLAG_INVISIBLE (1 << 0) #define FPDF_ANNOT_FLAG_HIDDEN (1 << 1) #define FPDF_ANNOT_FLAG_PRINT (1 << 2) #define FPDF_ANNOT_FLAG_NOZOOM (1 << 3) #define FPDF_ANNOT_FLAG_NOROTATE (1 << 4) #define FPDF_ANNOT_FLAG_NOVIEW (1 << 5) #define FPDF_ANNOT_FLAG_READONLY (1 << 6) #define FPDF_ANNOT_FLAG_LOCKED (1 << 7) #define FPDF_ANNOT_FLAG_TOGGLENOVIEW (1 << 8) #define FPDF_ANNOT_APPEARANCEMODE_NORMAL 0 #define FPDF_ANNOT_APPEARANCEMODE_ROLLOVER 1 #define FPDF_ANNOT_APPEARANCEMODE_DOWN 2 #define FPDF_ANNOT_APPEARANCEMODE_COUNT 3 // Refer to PDF Reference version 1.7 table 8.70 for field flags common to all // interactive form field types. #define FPDF_FORMFLAG_NONE 0 #define FPDF_FORMFLAG_READONLY (1 << 0) #define FPDF_FORMFLAG_REQUIRED (1 << 1) #define FPDF_FORMFLAG_NOEXPORT (1 << 2) // Refer to PDF Reference version 1.7 table 8.77 for field flags specific to // interactive form text fields. #define FPDF_FORMFLAG_TEXT_MULTILINE (1 << 12) #define FPDF_FORMFLAG_TEXT_PASSWORD (1 << 13) // Refer to PDF Reference version 1.7 table 8.79 for field flags specific to // interactive form choice fields. #define FPDF_FORMFLAG_CHOICE_COMBO (1 << 17) #define FPDF_FORMFLAG_CHOICE_EDIT (1 << 18) #define FPDF_FORMFLAG_CHOICE_MULTI_SELECT (1 << 21) // Additional actions type of form field: // K, on key stroke, JavaScript action. // F, on format, JavaScript action. // V, on validate, JavaScript action. // C, on calculate, JavaScript action. #define FPDF_ANNOT_AACTION_KEY_STROKE 12 #define FPDF_ANNOT_AACTION_FORMAT 13 #define FPDF_ANNOT_AACTION_VALIDATE 14 #define FPDF_ANNOT_AACTION_CALCULATE 15 typedef enum FPDFANNOT_COLORTYPE { FPDFANNOT_COLORTYPE_Color = 0, FPDFANNOT_COLORTYPE_InteriorColor } FPDFANNOT_COLORTYPE; // Experimental API. // Check if an annotation subtype is currently supported for creation. // Currently supported subtypes: // - circle // - fileattachment // - freetext // - highlight // - ink // - link // - popup // - square, // - squiggly // - stamp // - strikeout // - text // - underline // // subtype - the subtype to be checked. // // Returns true if this subtype supported. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_IsSupportedSubtype(FPDF_ANNOTATION_SUBTYPE subtype); // Experimental API. // Create an annotation in |page| of the subtype |subtype|. If the specified // subtype is illegal or unsupported, then a new annotation will not be created. // Must call FPDFPage_CloseAnnot() when the annotation returned by this // function is no longer needed. // // page - handle to a page. // subtype - the subtype of the new annotation. // // Returns a handle to the new annotation object, or NULL on failure. FPDF_EXPORT FPDF_ANNOTATION FPDF_CALLCONV FPDFPage_CreateAnnot(FPDF_PAGE page, FPDF_ANNOTATION_SUBTYPE subtype); // Experimental API. // Get the number of annotations in |page|. // // page - handle to a page. // // Returns the number of annotations in |page|. FPDF_EXPORT int FPDF_CALLCONV FPDFPage_GetAnnotCount(FPDF_PAGE page); // Experimental API. // Get annotation in |page| at |index|. Must call FPDFPage_CloseAnnot() when the // annotation returned by this function is no longer needed. // // page - handle to a page. // index - the index of the annotation. // // Returns a handle to the annotation object, or NULL on failure. FPDF_EXPORT FPDF_ANNOTATION FPDF_CALLCONV FPDFPage_GetAnnot(FPDF_PAGE page, int index); // Experimental API. // Get the index of |annot| in |page|. This is the opposite of // FPDFPage_GetAnnot(). // // page - handle to the page that the annotation is on. // annot - handle to an annotation. // // Returns the index of |annot|, or -1 on failure. FPDF_EXPORT int FPDF_CALLCONV FPDFPage_GetAnnotIndex(FPDF_PAGE page, FPDF_ANNOTATION annot); // Experimental API. // Close an annotation. Must be called when the annotation returned by // FPDFPage_CreateAnnot() or FPDFPage_GetAnnot() is no longer needed. This // function does not remove the annotation from the document. // // annot - handle to an annotation. FPDF_EXPORT void FPDF_CALLCONV FPDFPage_CloseAnnot(FPDF_ANNOTATION annot); // Experimental API. // Remove the annotation in |page| at |index|. // // page - handle to a page. // index - the index of the annotation. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_RemoveAnnot(FPDF_PAGE page, int index); // Experimental API. // Get the subtype of an annotation. // // annot - handle to an annotation. // // Returns the annotation subtype. FPDF_EXPORT FPDF_ANNOTATION_SUBTYPE FPDF_CALLCONV FPDFAnnot_GetSubtype(FPDF_ANNOTATION annot); // Experimental API. // Check if an annotation subtype is currently supported for object extraction, // update, and removal. // Currently supported subtypes: ink and stamp. // // subtype - the subtype to be checked. // // Returns true if this subtype supported. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_IsObjectSupportedSubtype(FPDF_ANNOTATION_SUBTYPE subtype); // Experimental API. // Update |obj| in |annot|. |obj| must be in |annot| already and must have // been retrieved by FPDFAnnot_GetObject(). Currently, only ink and stamp // annotations are supported by this API. Also note that only path, image, and // text objects have APIs for modification; see FPDFPath_*(), FPDFText_*(), and // FPDFImageObj_*(). // // annot - handle to an annotation. // obj - handle to the object that |annot| needs to update. // // Return true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_UpdateObject(FPDF_ANNOTATION annot, FPDF_PAGEOBJECT obj); // Experimental API. // Add a new InkStroke, represented by an array of points, to the InkList of // |annot|. The API creates an InkList if one doesn't already exist in |annot|. // This API works only for ink annotations. Please refer to ISO 32000-1:2008 // spec, section 12.5.6.13. // // annot - handle to an annotation. // points - pointer to a FS_POINTF array representing input points. // point_count - number of elements in |points| array. This should not exceed // the maximum value that can be represented by an int32_t). // // Returns the 0-based index at which the new InkStroke is added in the InkList // of the |annot|. Returns -1 on failure. FPDF_EXPORT int FPDF_CALLCONV FPDFAnnot_AddInkStroke(FPDF_ANNOTATION annot, const FS_POINTF* points, size_t point_count); // Experimental API. // Removes an InkList in |annot|. // This API works only for ink annotations. // // annot - handle to an annotation. // // Return true on successful removal of /InkList entry from context of the // non-null ink |annot|. Returns false on failure. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_RemoveInkList(FPDF_ANNOTATION annot); // Experimental API. // Add |obj| to |annot|. |obj| must have been created by // FPDFPageObj_CreateNew{Path|Rect}() or FPDFPageObj_New{Text|Image}Obj(), and // will be owned by |annot|. Note that an |obj| cannot belong to more than one // |annot|. Currently, only ink and stamp annotations are supported by this API. // Also note that only path, image, and text objects have APIs for creation. // // annot - handle to an annotation. // obj - handle to the object that is to be added to |annot|. // // Return true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_AppendObject(FPDF_ANNOTATION annot, FPDF_PAGEOBJECT obj); // Experimental API. // Get the total number of objects in |annot|, including path objects, text // objects, external objects, image objects, and shading objects. // // annot - handle to an annotation. // // Returns the number of objects in |annot|. FPDF_EXPORT int FPDF_CALLCONV FPDFAnnot_GetObjectCount(FPDF_ANNOTATION annot); // Experimental API. // Get the object in |annot| at |index|. // // annot - handle to an annotation. // index - the index of the object. // // Return a handle to the object, or NULL on failure. FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV FPDFAnnot_GetObject(FPDF_ANNOTATION annot, int index); // Experimental API. // Remove the object in |annot| at |index|. // // annot - handle to an annotation. // index - the index of the object to be removed. // // Return true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_RemoveObject(FPDF_ANNOTATION annot, int index); // Experimental API. // Set the color of an annotation. Fails when called on annotations with // appearance streams already defined; instead use // FPDFPageObj_Set{Stroke|Fill}Color(). // // annot - handle to an annotation. // type - type of the color to be set. // R, G, B - buffer to hold the RGB value of the color. Ranges from 0 to 255. // A - buffer to hold the opacity. Ranges from 0 to 255. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetColor(FPDF_ANNOTATION annot, FPDFANNOT_COLORTYPE type, unsigned int R, unsigned int G, unsigned int B, unsigned int A); // Experimental API. // Get the color of an annotation. If no color is specified, default to yellow // for highlight annotation, black for all else. Fails when called on // annotations with appearance streams already defined; instead use // FPDFPageObj_Get{Stroke|Fill}Color(). // // annot - handle to an annotation. // type - type of the color requested. // R, G, B - buffer to hold the RGB value of the color. Ranges from 0 to 255. // A - buffer to hold the opacity. Ranges from 0 to 255. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_GetColor(FPDF_ANNOTATION annot, FPDFANNOT_COLORTYPE type, unsigned int* R, unsigned int* G, unsigned int* B, unsigned int* A); // Experimental API. // Check if the annotation is of a type that has attachment points // (i.e. quadpoints). Quadpoints are the vertices of the rectangle that // encompasses the texts affected by the annotation. They provide the // coordinates in the page where the annotation is attached. Only text markup // annotations (i.e. highlight, strikeout, squiggly, and underline) and link // annotations have quadpoints. // // annot - handle to an annotation. // // Returns true if the annotation is of a type that has quadpoints, false // otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_HasAttachmentPoints(FPDF_ANNOTATION annot); // Experimental API. // Replace the attachment points (i.e. quadpoints) set of an annotation at // |quad_index|. This index needs to be within the result of // FPDFAnnot_CountAttachmentPoints(). // If the annotation's appearance stream is defined and this annotation is of a // type with quadpoints, then update the bounding box too if the new quadpoints // define a bigger one. // // annot - handle to an annotation. // quad_index - index of the set of quadpoints. // quad_points - the quadpoints to be set. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetAttachmentPoints(FPDF_ANNOTATION annot, size_t quad_index, const FS_QUADPOINTSF* quad_points); // Experimental API. // Append to the list of attachment points (i.e. quadpoints) of an annotation. // If the annotation's appearance stream is defined and this annotation is of a // type with quadpoints, then update the bounding box too if the new quadpoints // define a bigger one. // // annot - handle to an annotation. // quad_points - the quadpoints to be set. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_AppendAttachmentPoints(FPDF_ANNOTATION annot, const FS_QUADPOINTSF* quad_points); // Experimental API. // Get the number of sets of quadpoints of an annotation. // // annot - handle to an annotation. // // Returns the number of sets of quadpoints, or 0 on failure. FPDF_EXPORT size_t FPDF_CALLCONV FPDFAnnot_CountAttachmentPoints(FPDF_ANNOTATION annot); // Experimental API. // Get the attachment points (i.e. quadpoints) of an annotation. // // annot - handle to an annotation. // quad_index - index of the set of quadpoints. // quad_points - receives the quadpoints; must not be NULL. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_GetAttachmentPoints(FPDF_ANNOTATION annot, size_t quad_index, FS_QUADPOINTSF* quad_points); // Experimental API. // Set the annotation rectangle defining the location of the annotation. If the // annotation's appearance stream is defined and this annotation is of a type // without quadpoints, then update the bounding box too if the new rectangle // defines a bigger one. // // annot - handle to an annotation. // rect - the annotation rectangle to be set. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetRect(FPDF_ANNOTATION annot, const FS_RECTF* rect); // Experimental API. // Get the annotation rectangle defining the location of the annotation. // // annot - handle to an annotation. // rect - receives the rectangle; must not be NULL. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_GetRect(FPDF_ANNOTATION annot, FS_RECTF* rect); // Experimental API. // Get the vertices of a polygon or polyline annotation. |buffer| is an array of // points of the annotation. If |length| is less than the returned length, or // |annot| or |buffer| is NULL, |buffer| will not be modified. // // annot - handle to an annotation, as returned by e.g. FPDFPage_GetAnnot() // buffer - buffer for holding the points. // length - length of the buffer in points. // // Returns the number of points if the annotation is of type polygon or // polyline, 0 otherwise. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFAnnot_GetVertices(FPDF_ANNOTATION annot, FS_POINTF* buffer, unsigned long length); // Experimental API. // Get the number of paths in the ink list of an ink annotation. // // annot - handle to an annotation, as returned by e.g. FPDFPage_GetAnnot() // // Returns the number of paths in the ink list if the annotation is of type ink, // 0 otherwise. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFAnnot_GetInkListCount(FPDF_ANNOTATION annot); // Experimental API. // Get a path in the ink list of an ink annotation. |buffer| is an array of // points of the path. If |length| is less than the returned length, or |annot| // or |buffer| is NULL, |buffer| will not be modified. // // annot - handle to an annotation, as returned by e.g. FPDFPage_GetAnnot() // path_index - index of the path // buffer - buffer for holding the points. // length - length of the buffer in points. // // Returns the number of points of the path if the annotation is of type ink, 0 // otherwise. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFAnnot_GetInkListPath(FPDF_ANNOTATION annot, unsigned long path_index, FS_POINTF* buffer, unsigned long length); // Experimental API. // Get the starting and ending coordinates of a line annotation. // // annot - handle to an annotation, as returned by e.g. FPDFPage_GetAnnot() // start - starting point // end - ending point // // Returns true if the annotation is of type line, |start| and |end| are not // NULL, false otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_GetLine(FPDF_ANNOTATION annot, FS_POINTF* start, FS_POINTF* end); // Experimental API. // Set the characteristics of the annotation's border (rounded rectangle). // // annot - handle to an annotation // horizontal_radius - horizontal corner radius, in default user space units // vertical_radius - vertical corner radius, in default user space units // border_width - border width, in default user space units // // Returns true if setting the border for |annot| succeeds, false otherwise. // // If |annot| contains an appearance stream that overrides the border values, // then the appearance stream will be removed on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetBorder(FPDF_ANNOTATION annot, float horizontal_radius, float vertical_radius, float border_width); // Experimental API. // Get the characteristics of the annotation's border (rounded rectangle). // // annot - handle to an annotation // horizontal_radius - horizontal corner radius, in default user space units // vertical_radius - vertical corner radius, in default user space units // border_width - border width, in default user space units // // Returns true if |horizontal_radius|, |vertical_radius| and |border_width| are // not NULL, false otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_GetBorder(FPDF_ANNOTATION annot, float* horizontal_radius, float* vertical_radius, float* border_width); // Experimental API. // Get the JavaScript of an event of the annotation's additional actions. // |buffer| is only modified if |buflen| is large enough to hold the whole // JavaScript string. If |buflen| is smaller, the total size of the JavaScript // is still returned, but nothing is copied. If there is no JavaScript for // |event| in |annot|, an empty string is written to |buf| and 2 is returned, // denoting the size of the null terminator in the buffer. On other errors, // nothing is written to |buffer| and 0 is returned. // // hHandle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment(). // annot - handle to an interactive form annotation. // event - event type, one of the FPDF_ANNOT_AACTION_* values. // buffer - buffer for holding the value string, encoded in UTF-16LE. // buflen - length of the buffer in bytes. // // Returns the length of the string value in bytes, including the 2-byte // null terminator. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFAnnot_GetFormAdditionalActionJavaScript(FPDF_FORMHANDLE hHandle, FPDF_ANNOTATION annot, int event, FPDF_WCHAR* buffer, unsigned long buflen); // Experimental API. // Check if |annot|'s dictionary has |key| as a key. // // annot - handle to an annotation. // key - the key to look for, encoded in UTF-8. // // Returns true if |key| exists. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_HasKey(FPDF_ANNOTATION annot, FPDF_BYTESTRING key); // Experimental API. // Get the type of the value corresponding to |key| in |annot|'s dictionary. // // annot - handle to an annotation. // key - the key to look for, encoded in UTF-8. // // Returns the type of the dictionary value. FPDF_EXPORT FPDF_OBJECT_TYPE FPDF_CALLCONV FPDFAnnot_GetValueType(FPDF_ANNOTATION annot, FPDF_BYTESTRING key); // Experimental API. // Set the string value corresponding to |key| in |annot|'s dictionary, // overwriting the existing value if any. The value type would be // FPDF_OBJECT_STRING after this function call succeeds. // // annot - handle to an annotation. // key - the key to the dictionary entry to be set, encoded in UTF-8. // value - the string value to be set, encoded in UTF-16LE. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetStringValue(FPDF_ANNOTATION annot, FPDF_BYTESTRING key, FPDF_WIDESTRING value); // Experimental API. // Get the string value corresponding to |key| in |annot|'s dictionary. |buffer| // is only modified if |buflen| is longer than the length of contents. Note that // if |key| does not exist in the dictionary or if |key|'s corresponding value // in the dictionary is not a string (i.e. the value is not of type // FPDF_OBJECT_STRING or FPDF_OBJECT_NAME), then an empty string would be copied // to |buffer| and the return value would be 2. On other errors, nothing would // be added to |buffer| and the return value would be 0. // // annot - handle to an annotation. // key - the key to the requested dictionary entry, encoded in UTF-8. // buffer - buffer for holding the value string, encoded in UTF-16LE. // buflen - length of the buffer in bytes. // // Returns the length of the string value in bytes. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFAnnot_GetStringValue(FPDF_ANNOTATION annot, FPDF_BYTESTRING key, FPDF_WCHAR* buffer, unsigned long buflen); // Experimental API. // Get the float value corresponding to |key| in |annot|'s dictionary. Writes // value to |value| and returns True if |key| exists in the dictionary and // |key|'s corresponding value is a number (FPDF_OBJECT_NUMBER), False // otherwise. // // annot - handle to an annotation. // key - the key to the requested dictionary entry, encoded in UTF-8. // value - receives the value, must not be NULL. // // Returns True if value found, False otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_GetNumberValue(FPDF_ANNOTATION annot, FPDF_BYTESTRING key, float* value); // Experimental API. // Set the AP (appearance string) in |annot|'s dictionary for a given // |appearanceMode|. // // annot - handle to an annotation. // appearanceMode - the appearance mode (normal, rollover or down) for which // to get the AP. // value - the string value to be set, encoded in UTF-16LE. If // nullptr is passed, the AP is cleared for that mode. If the // mode is Normal, APs for all modes are cleared. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetAP(FPDF_ANNOTATION annot, FPDF_ANNOT_APPEARANCEMODE appearanceMode, FPDF_WIDESTRING value); // Experimental API. // Get the AP (appearance string) from |annot|'s dictionary for a given // |appearanceMode|. // |buffer| is only modified if |buflen| is large enough to hold the whole AP // string. If |buflen| is smaller, the total size of the AP is still returned, // but nothing is copied. // If there is no appearance stream for |annot| in |appearanceMode|, an empty // string is written to |buf| and 2 is returned. // On other errors, nothing is written to |buffer| and 0 is returned. // // annot - handle to an annotation. // appearanceMode - the appearance mode (normal, rollover or down) for which // to get the AP. // buffer - buffer for holding the value string, encoded in UTF-16LE. // buflen - length of the buffer in bytes. // // Returns the length of the string value in bytes. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFAnnot_GetAP(FPDF_ANNOTATION annot, FPDF_ANNOT_APPEARANCEMODE appearanceMode, FPDF_WCHAR* buffer, unsigned long buflen); // Experimental API. // Get the annotation corresponding to |key| in |annot|'s dictionary. Common // keys for linking annotations include "IRT" and "Popup". Must call // FPDFPage_CloseAnnot() when the annotation returned by this function is no // longer needed. // // annot - handle to an annotation. // key - the key to the requested dictionary entry, encoded in UTF-8. // // Returns a handle to the linked annotation object, or NULL on failure. FPDF_EXPORT FPDF_ANNOTATION FPDF_CALLCONV FPDFAnnot_GetLinkedAnnot(FPDF_ANNOTATION annot, FPDF_BYTESTRING key); // Experimental API. // Get the annotation flags of |annot|. // // annot - handle to an annotation. // // Returns the annotation flags. FPDF_EXPORT int FPDF_CALLCONV FPDFAnnot_GetFlags(FPDF_ANNOTATION annot); // Experimental API. // Set the |annot|'s flags to be of the value |flags|. // // annot - handle to an annotation. // flags - the flag values to be set. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetFlags(FPDF_ANNOTATION annot, int flags); // Experimental API. // Get the annotation flags of |annot|. // // hHandle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment(). // annot - handle to an interactive form annotation. // // Returns the annotation flags specific to interactive forms. FPDF_EXPORT int FPDF_CALLCONV FPDFAnnot_GetFormFieldFlags(FPDF_FORMHANDLE handle, FPDF_ANNOTATION annot); // Experimental API. // Sets the form field flags for an interactive form annotation. // // handle - the handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment(). // annot - handle to an interactive form annotation. // flags - the form field flags to be set. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetFormFieldFlags(FPDF_FORMHANDLE handle, FPDF_ANNOTATION annot, int flags); // Experimental API. // Retrieves an interactive form annotation whose rectangle contains a given // point on a page. Must call FPDFPage_CloseAnnot() when the annotation returned // is no longer needed. // // // hHandle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment(). // page - handle to the page, returned by FPDF_LoadPage function. // point - position in PDF "user space". // // Returns the interactive form annotation whose rectangle contains the given // coordinates on the page. If there is no such annotation, return NULL. FPDF_EXPORT FPDF_ANNOTATION FPDF_CALLCONV FPDFAnnot_GetFormFieldAtPoint(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, const FS_POINTF* point); // Experimental API. // Gets the name of |annot|, which is an interactive form annotation. // |buffer| is only modified if |buflen| is longer than the length of contents. // In case of error, nothing will be added to |buffer| and the return value will // be 0. Note that return value of empty string is 2 for "\0\0". // // hHandle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment(). // annot - handle to an interactive form annotation. // buffer - buffer for holding the name string, encoded in UTF-16LE. // buflen - length of the buffer in bytes. // // Returns the length of the string value in bytes. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFAnnot_GetFormFieldName(FPDF_FORMHANDLE hHandle, FPDF_ANNOTATION annot, FPDF_WCHAR* buffer, unsigned long buflen); // Experimental API. // Gets the alternate name of |annot|, which is an interactive form annotation. // |buffer| is only modified if |buflen| is longer than the length of contents. // In case of error, nothing will be added to |buffer| and the return value will // be 0. Note that return value of empty string is 2 for "\0\0". // // hHandle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment(). // annot - handle to an interactive form annotation. // buffer - buffer for holding the alternate name string, encoded in // UTF-16LE. // buflen - length of the buffer in bytes. // // Returns the length of the string value in bytes. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFAnnot_GetFormFieldAlternateName(FPDF_FORMHANDLE hHandle, FPDF_ANNOTATION annot, FPDF_WCHAR* buffer, unsigned long buflen); // Experimental API. // Gets the form field type of |annot|, which is an interactive form annotation. // // hHandle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment(). // annot - handle to an interactive form annotation. // // Returns the type of the form field (one of the FPDF_FORMFIELD_* values) on // success. Returns -1 on error. // See field types in fpdf_formfill.h. FPDF_EXPORT int FPDF_CALLCONV FPDFAnnot_GetFormFieldType(FPDF_FORMHANDLE hHandle, FPDF_ANNOTATION annot); // Experimental API. // Gets the value of |annot|, which is an interactive form annotation. // |buffer| is only modified if |buflen| is longer than the length of contents. // In case of error, nothing will be added to |buffer| and the return value will // be 0. Note that return value of empty string is 2 for "\0\0". // // hHandle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment(). // annot - handle to an interactive form annotation. // buffer - buffer for holding the value string, encoded in UTF-16LE. // buflen - length of the buffer in bytes. // // Returns the length of the string value in bytes. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFAnnot_GetFormFieldValue(FPDF_FORMHANDLE hHandle, FPDF_ANNOTATION annot, FPDF_WCHAR* buffer, unsigned long buflen); // Experimental API. // Get the number of options in the |annot|'s "Opt" dictionary. Intended for // use with listbox and combobox widget annotations. // // hHandle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment. // annot - handle to an annotation. // // Returns the number of options in "Opt" dictionary on success. Return value // will be -1 if annotation does not have an "Opt" dictionary or other error. FPDF_EXPORT int FPDF_CALLCONV FPDFAnnot_GetOptionCount(FPDF_FORMHANDLE hHandle, FPDF_ANNOTATION annot); // Experimental API. // Get the string value for the label of the option at |index| in |annot|'s // "Opt" dictionary. Intended for use with listbox and combobox widget // annotations. |buffer| is only modified if |buflen| is longer than the length // of contents. If index is out of range or in case of other error, nothing // will be added to |buffer| and the return value will be 0. Note that // return value of empty string is 2 for "\0\0". // // hHandle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment. // annot - handle to an annotation. // index - numeric index of the option in the "Opt" array // buffer - buffer for holding the value string, encoded in UTF-16LE. // buflen - length of the buffer in bytes. // // Returns the length of the string value in bytes. // If |annot| does not have an "Opt" array, |index| is out of range or if any // other error occurs, returns 0. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFAnnot_GetOptionLabel(FPDF_FORMHANDLE hHandle, FPDF_ANNOTATION annot, int index, FPDF_WCHAR* buffer, unsigned long buflen); // Experimental API. // Determine whether or not the option at |index| in |annot|'s "Opt" dictionary // is selected. Intended for use with listbox and combobox widget annotations. // // handle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment. // annot - handle to an annotation. // index - numeric index of the option in the "Opt" array. // // Returns true if the option at |index| in |annot|'s "Opt" dictionary is // selected, false otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_IsOptionSelected(FPDF_FORMHANDLE handle, FPDF_ANNOTATION annot, int index); // Experimental API. // Get the float value of the font size for an |annot| with variable text. // If 0, the font is to be auto-sized: its size is computed as a function of // the height of the annotation rectangle. // // hHandle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment. // annot - handle to an annotation. // value - Required. Float which will be set to font size on success. // // Returns true if the font size was set in |value|, false on error or if // |value| not provided. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_GetFontSize(FPDF_FORMHANDLE hHandle, FPDF_ANNOTATION annot, float* value); // Experimental API. // Set the text color of an annotation. // // handle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment. // annot - handle to an annotation. // R - the red component for the text color. // G - the green component for the text color. // B - the blue component for the text color. // // Returns true if successful. // // Currently supported subtypes: freetext. // The range for the color components is 0 to 255. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetFontColor(FPDF_FORMHANDLE handle, FPDF_ANNOTATION annot, unsigned int R, unsigned int G, unsigned int B); // Experimental API. // Get the RGB value of the font color for an |annot| with variable text. // // hHandle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment. // annot - handle to an annotation. // R, G, B - buffer to hold the RGB value of the color. Ranges from 0 to 255. // // Returns true if the font color was set, false on error or if the font // color was not provided. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_GetFontColor(FPDF_FORMHANDLE hHandle, FPDF_ANNOTATION annot, unsigned int* R, unsigned int* G, unsigned int* B); // Experimental API. // Determine if |annot| is a form widget that is checked. Intended for use with // checkbox and radio button widgets. // // hHandle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment. // annot - handle to an annotation. // // Returns true if |annot| is a form widget and is checked, false otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_IsChecked(FPDF_FORMHANDLE hHandle, FPDF_ANNOTATION annot); // Experimental API. // Set the list of focusable annotation subtypes. Annotations of subtype // FPDF_ANNOT_WIDGET are by default focusable. New subtypes set using this API // will override the existing subtypes. // // hHandle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment. // subtypes - list of annotation subtype which can be tabbed over. // count - total number of annotation subtype in list. // Returns true if list of annotation subtype is set successfully, false // otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetFocusableSubtypes(FPDF_FORMHANDLE hHandle, const FPDF_ANNOTATION_SUBTYPE* subtypes, size_t count); // Experimental API. // Get the count of focusable annotation subtypes as set by host // for a |hHandle|. // // hHandle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment. // Returns the count of focusable annotation subtypes or -1 on error. // Note : Annotations of type FPDF_ANNOT_WIDGET are by default focusable. FPDF_EXPORT int FPDF_CALLCONV FPDFAnnot_GetFocusableSubtypesCount(FPDF_FORMHANDLE hHandle); // Experimental API. // Get the list of focusable annotation subtype as set by host. // // hHandle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment. // subtypes - receives the list of annotation subtype which can be tabbed // over. Caller must have allocated |subtypes| more than or // equal to the count obtained from // FPDFAnnot_GetFocusableSubtypesCount() API. // count - size of |subtypes|. // Returns true on success and set list of annotation subtype to |subtypes|, // false otherwise. // Note : Annotations of type FPDF_ANNOT_WIDGET are by default focusable. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_GetFocusableSubtypes(FPDF_FORMHANDLE hHandle, FPDF_ANNOTATION_SUBTYPE* subtypes, size_t count); // Experimental API. // Gets FPDF_LINK object for |annot|. Intended to use for link annotations. // // annot - handle to an annotation. // // Returns FPDF_LINK from the FPDF_ANNOTATION and NULL on failure, // if the input annot is NULL or input annot's subtype is not link. FPDF_EXPORT FPDF_LINK FPDF_CALLCONV FPDFAnnot_GetLink(FPDF_ANNOTATION annot); // Experimental API. // Gets the count of annotations in the |annot|'s control group. // A group of interactive form annotations is collectively called a form // control group. Here, |annot|, an interactive form annotation, should be // either a radio button or a checkbox. // // hHandle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment. // annot - handle to an annotation. // // Returns number of controls in its control group or -1 on error. FPDF_EXPORT int FPDF_CALLCONV FPDFAnnot_GetFormControlCount(FPDF_FORMHANDLE hHandle, FPDF_ANNOTATION annot); // Experimental API. // Gets the index of |annot| in |annot|'s control group. // A group of interactive form annotations is collectively called a form // control group. Here, |annot|, an interactive form annotation, should be // either a radio button or a checkbox. // // hHandle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment. // annot - handle to an annotation. // // Returns index of a given |annot| in its control group or -1 on error. FPDF_EXPORT int FPDF_CALLCONV FPDFAnnot_GetFormControlIndex(FPDF_FORMHANDLE hHandle, FPDF_ANNOTATION annot); // Experimental API. // Gets the export value of |annot| which is an interactive form annotation. // Intended for use with radio button and checkbox widget annotations. // |buffer| is only modified if |buflen| is longer than the length of contents. // In case of error, nothing will be added to |buffer| and the return value // will be 0. Note that return value of empty string is 2 for "\0\0". // // hHandle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment(). // annot - handle to an interactive form annotation. // buffer - buffer for holding the value string, encoded in UTF-16LE. // buflen - length of the buffer in bytes. // // Returns the length of the string value in bytes. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFAnnot_GetFormFieldExportValue(FPDF_FORMHANDLE hHandle, FPDF_ANNOTATION annot, FPDF_WCHAR* buffer, unsigned long buflen); // Experimental API. // Add a URI action to |annot|, overwriting the existing action, if any. // // annot - handle to a link annotation. // uri - the URI to be set, encoded in 7-bit ASCII. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetURI(FPDF_ANNOTATION annot, const char* uri); // Experimental API. // Get the attachment from |annot|. // // annot - handle to a file annotation. // // Returns the handle to the attachment object, or NULL on failure. FPDF_EXPORT FPDF_ATTACHMENT FPDF_CALLCONV FPDFAnnot_GetFileAttachment(FPDF_ANNOTATION annot); // Experimental API. // Add an embedded file with |name| to |annot|. // // annot - handle to a file annotation. // name - name of the new attachment. // // Returns a handle to the new attachment object, or NULL on failure. FPDF_EXPORT FPDF_ATTACHMENT FPDF_CALLCONV FPDFAnnot_AddFileAttachment(FPDF_ANNOTATION annot, FPDF_WIDESTRING name); #ifdef __cplusplus } // extern "C" #endif // __cplusplus #endif // PUBLIC_FPDF_ANNOT_H_ ================================================ FILE: external/pdfium/macos-x64/include/fpdf_attachment.h ================================================ // Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef PUBLIC_FPDF_ATTACHMENT_H_ #define PUBLIC_FPDF_ATTACHMENT_H_ // NOLINTNEXTLINE(build/include) #include "fpdfview.h" #ifdef __cplusplus extern "C" { #endif // __cplusplus // Experimental API. // Get the number of embedded files in |document|. // // document - handle to a document. // // Returns the number of embedded files in |document|. FPDF_EXPORT int FPDF_CALLCONV FPDFDoc_GetAttachmentCount(FPDF_DOCUMENT document); // Experimental API. // Add an embedded file with |name| in |document|. If |name| is empty, or if // |name| is the name of a existing embedded file in |document|, or if // |document|'s embedded file name tree is too deep (i.e. |document| has too // many embedded files already), then a new attachment will not be added. // // document - handle to a document. // name - name of the new attachment. // // Returns a handle to the new attachment object, or NULL on failure. FPDF_EXPORT FPDF_ATTACHMENT FPDF_CALLCONV FPDFDoc_AddAttachment(FPDF_DOCUMENT document, FPDF_WIDESTRING name); // Experimental API. // Get the embedded attachment at |index| in |document|. Note that the returned // attachment handle is only valid while |document| is open. // // document - handle to a document. // index - the index of the requested embedded file. // // Returns the handle to the attachment object, or NULL on failure. FPDF_EXPORT FPDF_ATTACHMENT FPDF_CALLCONV FPDFDoc_GetAttachment(FPDF_DOCUMENT document, int index); // Experimental API. // Delete the embedded attachment at |index| in |document|. Note that this does // not remove the attachment data from the PDF file; it simply removes the // file's entry in the embedded files name tree so that it does not appear in // the attachment list. This behavior may change in the future. // // document - handle to a document. // index - the index of the embedded file to be deleted. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFDoc_DeleteAttachment(FPDF_DOCUMENT document, int index); // Experimental API. // Get the name of the |attachment| file. |buffer| is only modified if |buflen| // is longer than the length of the file name. On errors, |buffer| is unmodified // and the returned length is 0. // // attachment - handle to an attachment. // buffer - buffer for holding the file name, encoded in UTF-16LE. // buflen - length of the buffer in bytes. // // Returns the length of the file name in bytes. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFAttachment_GetName(FPDF_ATTACHMENT attachment, FPDF_WCHAR* buffer, unsigned long buflen); // Experimental API. // Check if the params dictionary of |attachment| has |key| as a key. // // attachment - handle to an attachment. // key - the key to look for, encoded in UTF-8. // // Returns true if |key| exists. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAttachment_HasKey(FPDF_ATTACHMENT attachment, FPDF_BYTESTRING key); // Experimental API. // Get the type of the value corresponding to |key| in the params dictionary of // the embedded |attachment|. // // attachment - handle to an attachment. // key - the key to look for, encoded in UTF-8. // // Returns the type of the dictionary value. FPDF_EXPORT FPDF_OBJECT_TYPE FPDF_CALLCONV FPDFAttachment_GetValueType(FPDF_ATTACHMENT attachment, FPDF_BYTESTRING key); // Experimental API. // Set the string value corresponding to |key| in the params dictionary of the // embedded file |attachment|, overwriting the existing value if any. The value // type should be FPDF_OBJECT_STRING after this function call succeeds. // // attachment - handle to an attachment. // key - the key to the dictionary entry, encoded in UTF-8. // value - the string value to be set, encoded in UTF-16LE. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAttachment_SetStringValue(FPDF_ATTACHMENT attachment, FPDF_BYTESTRING key, FPDF_WIDESTRING value); // Experimental API. // Get the string value corresponding to |key| in the params dictionary of the // embedded file |attachment|. |buffer| is only modified if |buflen| is longer // than the length of the string value. Note that if |key| does not exist in the // dictionary or if |key|'s corresponding value in the dictionary is not a // string (i.e. the value is not of type FPDF_OBJECT_STRING or // FPDF_OBJECT_NAME), then an empty string would be copied to |buffer| and the // return value would be 2. On other errors, nothing would be added to |buffer| // and the return value would be 0. // // attachment - handle to an attachment. // key - the key to the requested string value, encoded in UTF-8. // buffer - buffer for holding the string value encoded in UTF-16LE. // buflen - length of the buffer in bytes. // // Returns the length of the dictionary value string in bytes. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFAttachment_GetStringValue(FPDF_ATTACHMENT attachment, FPDF_BYTESTRING key, FPDF_WCHAR* buffer, unsigned long buflen); // Experimental API. // Set the file data of |attachment|, overwriting the existing file data if any. // The creation date and checksum will be updated, while all other dictionary // entries will be deleted. Note that only contents with |len| smaller than // INT_MAX is supported. // // attachment - handle to an attachment. // contents - buffer holding the file data to write to |attachment|. // len - length of file data in bytes. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAttachment_SetFile(FPDF_ATTACHMENT attachment, FPDF_DOCUMENT document, const void* contents, unsigned long len); // Experimental API. // Get the file data of |attachment|. // When the attachment file data is readable, true is returned, and |out_buflen| // is updated to indicate the file data size. |buffer| is only modified if // |buflen| is non-null and long enough to contain the entire file data. Callers // must check both the return value and the input |buflen| is no less than the // returned |out_buflen| before using the data. // // Otherwise, when the attachment file data is unreadable or when |out_buflen| // is null, false is returned and |buffer| and |out_buflen| remain unmodified. // // attachment - handle to an attachment. // buffer - buffer for holding the file data from |attachment|. // buflen - length of the buffer in bytes. // out_buflen - pointer to the variable that will receive the minimum buffer // size to contain the file data of |attachment|. // // Returns true on success, false otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAttachment_GetFile(FPDF_ATTACHMENT attachment, void* buffer, unsigned long buflen, unsigned long* out_buflen); // Experimental API. // Get the MIME type (Subtype) of the embedded file |attachment|. |buffer| is // only modified if |buflen| is longer than the length of the MIME type string. // If the Subtype is not found or if there is no file stream, an empty string // would be copied to |buffer| and the return value would be 2. On other errors, // nothing would be added to |buffer| and the return value would be 0. // // attachment - handle to an attachment. // buffer - buffer for holding the MIME type string encoded in UTF-16LE. // buflen - length of the buffer in bytes. // // Returns the length of the MIME type string in bytes. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFAttachment_GetSubtype(FPDF_ATTACHMENT attachment, FPDF_WCHAR* buffer, unsigned long buflen); #ifdef __cplusplus } // extern "C" #endif // __cplusplus #endif // PUBLIC_FPDF_ATTACHMENT_H_ ================================================ FILE: external/pdfium/macos-x64/include/fpdf_catalog.h ================================================ // Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef PUBLIC_FPDF_CATALOG_H_ #define PUBLIC_FPDF_CATALOG_H_ // NOLINTNEXTLINE(build/include) #include "fpdfview.h" #ifdef __cplusplus extern "C" { #endif // __cplusplus // Experimental API. // // Determine if |document| represents a tagged PDF. // // For the definition of tagged PDF, See (see 10.7 "Tagged PDF" in PDF // Reference 1.7). // // document - handle to a document. // // Returns |true| iff |document| is a tagged PDF. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFCatalog_IsTagged(FPDF_DOCUMENT document); // Experimental API. // Gets the language of |document| from the catalog's /Lang entry. // // document - handle to a document. // buffer - a buffer for the language string. May be NULL. // buflen - the length of the buffer, in bytes. May be 0. // // Returns the number of bytes in the language string, including the // trailing NUL character. The number of bytes is returned regardless of the // |buffer| and |buflen| parameters. // // Regardless of the platform, the |buffer| is always in UTF-16LE // encoding. The string is terminated by a UTF16 NUL character. If // |buflen| is less than the required length, or |buffer| is NULL, // |buffer| will not be modified. // // If |document| has no /Lang entry, an empty string is written to |buffer| and // 2 is returned. On error, nothing is written to |buffer| and 0 is returned. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFCatalog_GetLanguage(FPDF_DOCUMENT document, FPDF_WCHAR* buffer, unsigned long buflen); // Experimental API. // Sets the language of |document| to |language|. // // document - handle to a document. // language - the language to set to. // // Returns TRUE on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFCatalog_SetLanguage(FPDF_DOCUMENT document, FPDF_WIDESTRING language); #ifdef __cplusplus } // extern "C" #endif // __cplusplus #endif // PUBLIC_FPDF_CATALOG_H_ ================================================ FILE: external/pdfium/macos-x64/include/fpdf_dataavail.h ================================================ // Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #ifndef PUBLIC_FPDF_DATAAVAIL_H_ #define PUBLIC_FPDF_DATAAVAIL_H_ #include // NOLINTNEXTLINE(build/include) #include "fpdfview.h" #define PDF_LINEARIZATION_UNKNOWN -1 #define PDF_NOT_LINEARIZED 0 #define PDF_LINEARIZED 1 #define PDF_DATA_ERROR -1 #define PDF_DATA_NOTAVAIL 0 #define PDF_DATA_AVAIL 1 #define PDF_FORM_ERROR -1 #define PDF_FORM_NOTAVAIL 0 #define PDF_FORM_AVAIL 1 #define PDF_FORM_NOTEXIST 2 #ifdef __cplusplus extern "C" { #endif // __cplusplus // Interface for checking whether sections of the file are available. typedef struct _FX_FILEAVAIL { // Version number of the interface. Must be 1. int version; // Reports if the specified data section is currently available. A section is // available if all bytes in the section are available. // // Interface Version: 1 // Implementation Required: Yes // // pThis - pointer to the interface structure. // offset - the offset of the data section in the file. // size - the size of the data section. // // Returns true if the specified data section at |offset| of |size| // is available. FPDF_BOOL (*IsDataAvail)(struct _FX_FILEAVAIL* pThis, size_t offset, size_t size); } FX_FILEAVAIL; // Create a document availability provider. // // file_avail - pointer to file availability interface. // file - pointer to a file access interface. // // Returns a handle to the document availability provider, or NULL on error. // // FPDFAvail_Destroy() must be called when done with the availability provider. FPDF_EXPORT FPDF_AVAIL FPDF_CALLCONV FPDFAvail_Create(FX_FILEAVAIL* file_avail, FPDF_FILEACCESS* file); // Destroy the |avail| document availability provider. // // avail - handle to document availability provider to be destroyed. FPDF_EXPORT void FPDF_CALLCONV FPDFAvail_Destroy(FPDF_AVAIL avail); // Download hints interface. Used to receive hints for further downloading. typedef struct _FX_DOWNLOADHINTS { // Version number of the interface. Must be 1. int version; // Add a section to be downloaded. // // Interface Version: 1 // Implementation Required: Yes // // pThis - pointer to the interface structure. // offset - the offset of the hint reported to be downloaded. // size - the size of the hint reported to be downloaded. // // The |offset| and |size| of the section may not be unique. Part of the // section might be already available. The download manager must deal with // overlapping sections. void (*AddSegment)(struct _FX_DOWNLOADHINTS* pThis, size_t offset, size_t size); } FX_DOWNLOADHINTS; // Checks if the document is ready for loading, if not, gets download hints. // // avail - handle to document availability provider. // hints - pointer to a download hints interface. // // Returns one of: // PDF_DATA_ERROR: A common error is returned. Data availability unknown. // PDF_DATA_NOTAVAIL: Data not yet available. // PDF_DATA_AVAIL: Data available. // // Applications should call this function whenever new data arrives, and process // all the generated download hints, if any, until the function returns // |PDF_DATA_ERROR| or |PDF_DATA_AVAIL|. // if hints is nullptr, the function just check current document availability. // // Once all data is available, call FPDFAvail_GetDocument() to get a document // handle. FPDF_EXPORT int FPDF_CALLCONV FPDFAvail_IsDocAvail(FPDF_AVAIL avail, FX_DOWNLOADHINTS* hints); // Get document from the availability provider. // // avail - handle to document availability provider. // password - password for decrypting the PDF file. Optional. // // Returns a handle to the document. // // When FPDFAvail_IsDocAvail() returns TRUE, call FPDFAvail_GetDocument() to // retrieve the document handle. // See the comments for FPDF_LoadDocument() regarding the encoding for // |password|. FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV FPDFAvail_GetDocument(FPDF_AVAIL avail, FPDF_BYTESTRING password); // Get the page number for the first available page in a linearized PDF. // // doc - document handle. // // Returns the zero-based index for the first available page. // // For most linearized PDFs, the first available page will be the first page, // however, some PDFs might make another page the first available page. // For non-linearized PDFs, this function will always return zero. FPDF_EXPORT int FPDF_CALLCONV FPDFAvail_GetFirstPageNum(FPDF_DOCUMENT doc); // Check if |page_index| is ready for loading, if not, get the // |FX_DOWNLOADHINTS|. // // avail - handle to document availability provider. // page_index - index number of the page. Zero for the first page. // hints - pointer to a download hints interface. Populated if // |page_index| is not available. // // Returns one of: // PDF_DATA_ERROR: A common error is returned. Data availability unknown. // PDF_DATA_NOTAVAIL: Data not yet available. // PDF_DATA_AVAIL: Data available. // // This function can be called only after FPDFAvail_GetDocument() is called. // Applications should call this function whenever new data arrives and process // all the generated download |hints|, if any, until this function returns // |PDF_DATA_ERROR| or |PDF_DATA_AVAIL|. Applications can then perform page // loading. // if hints is nullptr, the function just check current availability of // specified page. FPDF_EXPORT int FPDF_CALLCONV FPDFAvail_IsPageAvail(FPDF_AVAIL avail, int page_index, FX_DOWNLOADHINTS* hints); // Check if form data is ready for initialization, if not, get the // |FX_DOWNLOADHINTS|. // // avail - handle to document availability provider. // hints - pointer to a download hints interface. Populated if form is not // ready for initialization. // // Returns one of: // PDF_FORM_ERROR: A common eror, in general incorrect parameters. // PDF_FORM_NOTAVAIL: Data not available. // PDF_FORM_AVAIL: Data available. // PDF_FORM_NOTEXIST: No form data. // // This function can be called only after FPDFAvail_GetDocument() is called. // The application should call this function whenever new data arrives and // process all the generated download |hints|, if any, until the function // |PDF_FORM_ERROR|, |PDF_FORM_AVAIL| or |PDF_FORM_NOTEXIST|. // if hints is nullptr, the function just check current form availability. // // Applications can then perform page loading. It is recommend to call // FPDFDOC_InitFormFillEnvironment() when |PDF_FORM_AVAIL| is returned. FPDF_EXPORT int FPDF_CALLCONV FPDFAvail_IsFormAvail(FPDF_AVAIL avail, FX_DOWNLOADHINTS* hints); // Check whether a document is a linearized PDF. // // avail - handle to document availability provider. // // Returns one of: // PDF_LINEARIZED // PDF_NOT_LINEARIZED // PDF_LINEARIZATION_UNKNOWN // // FPDFAvail_IsLinearized() will return |PDF_LINEARIZED| or |PDF_NOT_LINEARIZED| // when we have 1k of data. If the files size less than 1k, it returns // |PDF_LINEARIZATION_UNKNOWN| as there is insufficient information to determine // if the PDF is linearlized. FPDF_EXPORT int FPDF_CALLCONV FPDFAvail_IsLinearized(FPDF_AVAIL avail); #ifdef __cplusplus } // extern "C" #endif // __cplusplus #endif // PUBLIC_FPDF_DATAAVAIL_H_ ================================================ FILE: external/pdfium/macos-x64/include/fpdf_doc.h ================================================ // Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #ifndef PUBLIC_FPDF_DOC_H_ #define PUBLIC_FPDF_DOC_H_ // NOLINTNEXTLINE(build/include) #include "fpdfview.h" #ifdef __cplusplus extern "C" { #endif // __cplusplus // Unsupported action type. #define PDFACTION_UNSUPPORTED 0 // Go to a destination within current document. #define PDFACTION_GOTO 1 // Go to a destination within another document. #define PDFACTION_REMOTEGOTO 2 // URI, including web pages and other Internet resources. #define PDFACTION_URI 3 // Launch an application or open a file. #define PDFACTION_LAUNCH 4 // Go to a destination in an embedded file. #define PDFACTION_EMBEDDEDGOTO 5 // View destination fit types. See pdfmark reference v9, page 48. #define PDFDEST_VIEW_UNKNOWN_MODE 0 #define PDFDEST_VIEW_XYZ 1 #define PDFDEST_VIEW_FIT 2 #define PDFDEST_VIEW_FITH 3 #define PDFDEST_VIEW_FITV 4 #define PDFDEST_VIEW_FITR 5 #define PDFDEST_VIEW_FITB 6 #define PDFDEST_VIEW_FITBH 7 #define PDFDEST_VIEW_FITBV 8 // The file identifier entry type. See section 14.4 "File Identifiers" of the // ISO 32000-1:2008 spec. typedef enum { FILEIDTYPE_PERMANENT = 0, FILEIDTYPE_CHANGING = 1 } FPDF_FILEIDTYPE; // Get the first child of |bookmark|, or the first top-level bookmark item. // // document - handle to the document. // bookmark - handle to the current bookmark. Pass NULL for the first top // level item. // // Returns a handle to the first child of |bookmark| or the first top-level // bookmark item. NULL if no child or top-level bookmark found. // Note that another name for the bookmarks is the document outline, as // described in ISO 32000-1:2008, section 12.3.3. FPDF_EXPORT FPDF_BOOKMARK FPDF_CALLCONV FPDFBookmark_GetFirstChild(FPDF_DOCUMENT document, FPDF_BOOKMARK bookmark); // Get the next sibling of |bookmark|. // // document - handle to the document. // bookmark - handle to the current bookmark. // // Returns a handle to the next sibling of |bookmark|, or NULL if this is the // last bookmark at this level. // // Note that the caller is responsible for handling circular bookmark // references, as may arise from malformed documents. FPDF_EXPORT FPDF_BOOKMARK FPDF_CALLCONV FPDFBookmark_GetNextSibling(FPDF_DOCUMENT document, FPDF_BOOKMARK bookmark); // Get the title of |bookmark|. // // bookmark - handle to the bookmark. // buffer - buffer for the title. May be NULL. // buflen - the length of the buffer in bytes. May be 0. // // Returns the number of bytes in the title, including the terminating NUL // character. The number of bytes is returned regardless of the |buffer| and // |buflen| parameters. // // Regardless of the platform, the |buffer| is always in UTF-16LE encoding. The // string is terminated by a UTF16 NUL character. If |buflen| is less than the // required length, or |buffer| is NULL, |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFBookmark_GetTitle(FPDF_BOOKMARK bookmark, void* buffer, unsigned long buflen); // Experimental API. // Get the number of chlidren of |bookmark|. // // bookmark - handle to the bookmark. // // Returns a signed integer that represents the number of sub-items the given // bookmark has. If the value is positive, child items shall be shown by default // (open state). If the value is negative, child items shall be hidden by // default (closed state). Please refer to PDF 32000-1:2008, Table 153. // Returns 0 if the bookmark has no children or is invalid. FPDF_EXPORT int FPDF_CALLCONV FPDFBookmark_GetCount(FPDF_BOOKMARK bookmark); // Find the bookmark with |title| in |document|. // // document - handle to the document. // title - the UTF-16LE encoded Unicode title for which to search. // // Returns the handle to the bookmark, or NULL if |title| can't be found. // // FPDFBookmark_Find() will always return the first bookmark found even if // multiple bookmarks have the same |title|. FPDF_EXPORT FPDF_BOOKMARK FPDF_CALLCONV FPDFBookmark_Find(FPDF_DOCUMENT document, FPDF_WIDESTRING title); // Get the destination associated with |bookmark|. // // document - handle to the document. // bookmark - handle to the bookmark. // // Returns the handle to the destination data, or NULL if no destination is // associated with |bookmark|. FPDF_EXPORT FPDF_DEST FPDF_CALLCONV FPDFBookmark_GetDest(FPDF_DOCUMENT document, FPDF_BOOKMARK bookmark); // Get the action associated with |bookmark|. // // bookmark - handle to the bookmark. // // Returns the handle to the action data, or NULL if no action is associated // with |bookmark|. // If this function returns a valid handle, it is valid as long as |bookmark| is // valid. // If this function returns NULL, FPDFBookmark_GetDest() should be called to get // the |bookmark| destination data. FPDF_EXPORT FPDF_ACTION FPDF_CALLCONV FPDFBookmark_GetAction(FPDF_BOOKMARK bookmark); // Get the type of |action|. // // action - handle to the action. // // Returns one of: // PDFACTION_UNSUPPORTED // PDFACTION_GOTO // PDFACTION_REMOTEGOTO // PDFACTION_URI // PDFACTION_LAUNCH FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFAction_GetType(FPDF_ACTION action); // Get the destination of |action|. // // document - handle to the document. // action - handle to the action. |action| must be a |PDFACTION_GOTO| or // |PDFACTION_REMOTEGOTO|. // // Returns a handle to the destination data, or NULL on error, typically // because the arguments were bad or the action was of the wrong type. // // In the case of |PDFACTION_REMOTEGOTO|, you must first call // FPDFAction_GetFilePath(), then load the document at that path, then pass // the document handle from that document as |document| to FPDFAction_GetDest(). FPDF_EXPORT FPDF_DEST FPDF_CALLCONV FPDFAction_GetDest(FPDF_DOCUMENT document, FPDF_ACTION action); // Get the file path of |action|. // // action - handle to the action. |action| must be a |PDFACTION_LAUNCH| or // |PDFACTION_REMOTEGOTO|. // buffer - a buffer for output the path string. May be NULL. // buflen - the length of the buffer, in bytes. May be 0. // // Returns the number of bytes in the file path, including the trailing NUL // character, or 0 on error, typically because the arguments were bad or the // action was of the wrong type. // // Regardless of the platform, the |buffer| is always in UTF-8 encoding. // If |buflen| is less than the returned length, or |buffer| is NULL, |buffer| // will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFAction_GetFilePath(FPDF_ACTION action, void* buffer, unsigned long buflen); // Get the URI path of |action|. // // document - handle to the document. // action - handle to the action. Must be a |PDFACTION_URI|. // buffer - a buffer for the path string. May be NULL. // buflen - the length of the buffer, in bytes. May be 0. // // Returns the number of bytes in the URI path, including the trailing NUL // character, or 0 on error, typically because the arguments were bad or the // action was of the wrong type. // // The |buffer| may contain badly encoded data. The caller should validate the // output. e.g. Check to see if it is UTF-8. // // If |buflen| is less than the returned length, or |buffer| is NULL, |buffer| // will not be modified. // // Historically, the documentation for this API claimed |buffer| is always // encoded in 7-bit ASCII, but did not actually enforce it. // https://pdfium.googlesource.com/pdfium.git/+/d609e84cee2e14a18333247485af91df48a40592 // added that enforcement, but that did not work well for real world PDFs that // used UTF-8. As of this writing, this API reverted back to its original // behavior prior to commit d609e84cee. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFAction_GetURIPath(FPDF_DOCUMENT document, FPDF_ACTION action, void* buffer, unsigned long buflen); // Get the page index of |dest|. // // document - handle to the document. // dest - handle to the destination. // // Returns the 0-based page index containing |dest|. Returns -1 on error. FPDF_EXPORT int FPDF_CALLCONV FPDFDest_GetDestPageIndex(FPDF_DOCUMENT document, FPDF_DEST dest); // Experimental API. // Get the view (fit type) specified by |dest|. // // dest - handle to the destination. // pNumParams - receives the number of view parameters, which is at most 4. // pParams - buffer to write the view parameters. Must be at least 4 // FS_FLOATs long. // Returns one of the PDFDEST_VIEW_* constants, PDFDEST_VIEW_UNKNOWN_MODE if // |dest| does not specify a view. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFDest_GetView(FPDF_DEST dest, unsigned long* pNumParams, FS_FLOAT* pParams); // Get the (x, y, zoom) location of |dest| in the destination page, if the // destination is in [page /XYZ x y zoom] syntax. // // dest - handle to the destination. // hasXVal - out parameter; true if the x value is not null // hasYVal - out parameter; true if the y value is not null // hasZoomVal - out parameter; true if the zoom value is not null // x - out parameter; the x coordinate, in page coordinates. // y - out parameter; the y coordinate, in page coordinates. // zoom - out parameter; the zoom value. // Returns TRUE on successfully reading the /XYZ value. // // Note the [x, y, zoom] values are only set if the corresponding hasXVal, // hasYVal or hasZoomVal flags are true. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFDest_GetLocationInPage(FPDF_DEST dest, FPDF_BOOL* hasXVal, FPDF_BOOL* hasYVal, FPDF_BOOL* hasZoomVal, FS_FLOAT* x, FS_FLOAT* y, FS_FLOAT* zoom); // Find a link at point (|x|,|y|) on |page|. // // page - handle to the document page. // x - the x coordinate, in the page coordinate system. // y - the y coordinate, in the page coordinate system. // // Returns a handle to the link, or NULL if no link found at the given point. // // You can convert coordinates from screen coordinates to page coordinates using // FPDF_DeviceToPage(). FPDF_EXPORT FPDF_LINK FPDF_CALLCONV FPDFLink_GetLinkAtPoint(FPDF_PAGE page, double x, double y); // Find the Z-order of link at point (|x|,|y|) on |page|. // // page - handle to the document page. // x - the x coordinate, in the page coordinate system. // y - the y coordinate, in the page coordinate system. // // Returns the Z-order of the link, or -1 if no link found at the given point. // Larger Z-order numbers are closer to the front. // // You can convert coordinates from screen coordinates to page coordinates using // FPDF_DeviceToPage(). FPDF_EXPORT int FPDF_CALLCONV FPDFLink_GetLinkZOrderAtPoint(FPDF_PAGE page, double x, double y); // Get destination info for |link|. // // document - handle to the document. // link - handle to the link. // // Returns a handle to the destination, or NULL if there is no destination // associated with the link. In this case, you should call FPDFLink_GetAction() // to retrieve the action associated with |link|. FPDF_EXPORT FPDF_DEST FPDF_CALLCONV FPDFLink_GetDest(FPDF_DOCUMENT document, FPDF_LINK link); // Get action info for |link|. // // link - handle to the link. // // Returns a handle to the action associated to |link|, or NULL if no action. // If this function returns a valid handle, it is valid as long as |link| is // valid. FPDF_EXPORT FPDF_ACTION FPDF_CALLCONV FPDFLink_GetAction(FPDF_LINK link); // Enumerates all the link annotations in |page|. // // page - handle to the page. // start_pos - the start position, should initially be 0 and is updated with // the next start position on return. // link_annot - the link handle for |startPos|. // // Returns TRUE on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFLink_Enumerate(FPDF_PAGE page, int* start_pos, FPDF_LINK* link_annot); // Experimental API. // Gets FPDF_ANNOTATION object for |link_annot|. // // page - handle to the page in which FPDF_LINK object is present. // link_annot - handle to link annotation. // // Returns FPDF_ANNOTATION from the FPDF_LINK and NULL on failure, // if the input link annot or page is NULL. FPDF_EXPORT FPDF_ANNOTATION FPDF_CALLCONV FPDFLink_GetAnnot(FPDF_PAGE page, FPDF_LINK link_annot); // Get the rectangle for |link_annot|. // // link_annot - handle to the link annotation. // rect - the annotation rectangle. // // Returns true on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFLink_GetAnnotRect(FPDF_LINK link_annot, FS_RECTF* rect); // Get the count of quadrilateral points to the |link_annot|. // // link_annot - handle to the link annotation. // // Returns the count of quadrilateral points. FPDF_EXPORT int FPDF_CALLCONV FPDFLink_CountQuadPoints(FPDF_LINK link_annot); // Get the quadrilateral points for the specified |quad_index| in |link_annot|. // // link_annot - handle to the link annotation. // quad_index - the specified quad point index. // quad_points - receives the quadrilateral points. // // Returns true on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFLink_GetQuadPoints(FPDF_LINK link_annot, int quad_index, FS_QUADPOINTSF* quad_points); // Experimental API // Gets an additional-action from |page|. // // page - handle to the page, as returned by FPDF_LoadPage(). // aa_type - the type of the page object's addtional-action, defined // in public/fpdf_formfill.h // // Returns the handle to the action data, or NULL if there is no // additional-action of type |aa_type|. // If this function returns a valid handle, it is valid as long as |page| is // valid. FPDF_EXPORT FPDF_ACTION FPDF_CALLCONV FPDF_GetPageAAction(FPDF_PAGE page, int aa_type); // Experimental API. // Get the file identifer defined in the trailer of |document|. // // document - handle to the document. // id_type - the file identifier type to retrieve. // buffer - a buffer for the file identifier. May be NULL. // buflen - the length of the buffer, in bytes. May be 0. // // Returns the number of bytes in the file identifier, including the NUL // terminator. // // The |buffer| is always a byte string. The |buffer| is followed by a NUL // terminator. If |buflen| is less than the returned length, or |buffer| is // NULL, |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetFileIdentifier(FPDF_DOCUMENT document, FPDF_FILEIDTYPE id_type, void* buffer, unsigned long buflen); // Get meta-data |tag| content from |document|. // // document - handle to the document. // tag - the tag to retrieve. The tag can be one of: // Title, Author, Subject, Keywords, Creator, Producer, // CreationDate, or ModDate. // For detailed explanations of these tags and their respective // values, please refer to PDF Reference 1.6, section 10.2.1, // 'Document Information Dictionary'. // buffer - a buffer for the tag. May be NULL. // buflen - the length of the buffer, in bytes. May be 0. // // Returns the number of bytes in the tag, including trailing zeros. // // The |buffer| is always encoded in UTF-16LE. The |buffer| is followed by two // bytes of zeros indicating the end of the string. If |buflen| is less than // the returned length, or |buffer| is NULL, |buffer| will not be modified. // // For linearized files, FPDFAvail_IsFormAvail must be called before this, and // it must have returned PDF_FORM_AVAIL or PDF_FORM_NOTEXIST. Before that, there // is no guarantee the metadata has been loaded. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetMetaText(FPDF_DOCUMENT document, FPDF_BYTESTRING tag, void* buffer, unsigned long buflen); // Get the page label for |page_index| from |document|. // // document - handle to the document. // page_index - the 0-based index of the page. // buffer - a buffer for the page label. May be NULL. // buflen - the length of the buffer, in bytes. May be 0. // // Returns the number of bytes in the page label, including trailing zeros. // // The |buffer| is always encoded in UTF-16LE. The |buffer| is followed by two // bytes of zeros indicating the end of the string. If |buflen| is less than // the returned length, or |buffer| is NULL, |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetPageLabel(FPDF_DOCUMENT document, int page_index, void* buffer, unsigned long buflen); #ifdef __cplusplus } // extern "C" #endif // __cplusplus #endif // PUBLIC_FPDF_DOC_H_ ================================================ FILE: external/pdfium/macos-x64/include/fpdf_edit.h ================================================ // Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #ifndef PUBLIC_FPDF_EDIT_H_ #define PUBLIC_FPDF_EDIT_H_ #include // NOLINTNEXTLINE(build/include_directory) #include "fpdfview.h" #define FPDF_ARGB(a, r, g, b) \ ((uint32_t)(((uint32_t)(b)&0xff) | (((uint32_t)(g)&0xff) << 8) | \ (((uint32_t)(r)&0xff) << 16) | (((uint32_t)(a)&0xff) << 24))) #define FPDF_GetBValue(argb) ((uint8_t)(argb)) #define FPDF_GetGValue(argb) ((uint8_t)(((uint16_t)(argb)) >> 8)) #define FPDF_GetRValue(argb) ((uint8_t)((argb) >> 16)) #define FPDF_GetAValue(argb) ((uint8_t)((argb) >> 24)) // Refer to PDF Reference version 1.7 table 4.12 for all color space families. #define FPDF_COLORSPACE_UNKNOWN 0 #define FPDF_COLORSPACE_DEVICEGRAY 1 #define FPDF_COLORSPACE_DEVICERGB 2 #define FPDF_COLORSPACE_DEVICECMYK 3 #define FPDF_COLORSPACE_CALGRAY 4 #define FPDF_COLORSPACE_CALRGB 5 #define FPDF_COLORSPACE_LAB 6 #define FPDF_COLORSPACE_ICCBASED 7 #define FPDF_COLORSPACE_SEPARATION 8 #define FPDF_COLORSPACE_DEVICEN 9 #define FPDF_COLORSPACE_INDEXED 10 #define FPDF_COLORSPACE_PATTERN 11 // The page object constants. #define FPDF_PAGEOBJ_UNKNOWN 0 #define FPDF_PAGEOBJ_TEXT 1 #define FPDF_PAGEOBJ_PATH 2 #define FPDF_PAGEOBJ_IMAGE 3 #define FPDF_PAGEOBJ_SHADING 4 #define FPDF_PAGEOBJ_FORM 5 // The path segment constants. #define FPDF_SEGMENT_UNKNOWN -1 #define FPDF_SEGMENT_LINETO 0 #define FPDF_SEGMENT_BEZIERTO 1 #define FPDF_SEGMENT_MOVETO 2 #define FPDF_FILLMODE_NONE 0 #define FPDF_FILLMODE_ALTERNATE 1 #define FPDF_FILLMODE_WINDING 2 #define FPDF_FONT_TYPE1 1 #define FPDF_FONT_TRUETYPE 2 #define FPDF_LINECAP_BUTT 0 #define FPDF_LINECAP_ROUND 1 #define FPDF_LINECAP_PROJECTING_SQUARE 2 #define FPDF_LINEJOIN_MITER 0 #define FPDF_LINEJOIN_ROUND 1 #define FPDF_LINEJOIN_BEVEL 2 // See FPDF_SetPrintMode() for descriptions. #define FPDF_PRINTMODE_EMF 0 #define FPDF_PRINTMODE_TEXTONLY 1 #define FPDF_PRINTMODE_POSTSCRIPT2 2 #define FPDF_PRINTMODE_POSTSCRIPT3 3 #define FPDF_PRINTMODE_POSTSCRIPT2_PASSTHROUGH 4 #define FPDF_PRINTMODE_POSTSCRIPT3_PASSTHROUGH 5 #define FPDF_PRINTMODE_EMF_IMAGE_MASKS 6 #define FPDF_PRINTMODE_POSTSCRIPT3_TYPE42 7 #define FPDF_PRINTMODE_POSTSCRIPT3_TYPE42_PASSTHROUGH 8 typedef struct FPDF_IMAGEOBJ_METADATA { // The image width in pixels. unsigned int width; // The image height in pixels. unsigned int height; // The image's horizontal pixel-per-inch. float horizontal_dpi; // The image's vertical pixel-per-inch. float vertical_dpi; // The number of bits used to represent each pixel. unsigned int bits_per_pixel; // The image's colorspace. See above for the list of FPDF_COLORSPACE_*. int colorspace; // The image's marked content ID. Useful for pairing with associated alt-text. // A value of -1 indicates no ID. int marked_content_id; } FPDF_IMAGEOBJ_METADATA; #ifdef __cplusplus extern "C" { #endif // __cplusplus // Create a new PDF document. // // Returns a handle to a new document, or NULL on failure. FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV FPDF_CreateNewDocument(); // Create a new PDF page. // // document - handle to document. // page_index - suggested 0-based index of the page to create. If it is larger // than document's current last index(L), the created page index // is the next available index -- L+1. // width - the page width in points. // height - the page height in points. // // Returns the handle to the new page or NULL on failure. // // The page should be closed with FPDF_ClosePage() when finished as // with any other page in the document. FPDF_EXPORT FPDF_PAGE FPDF_CALLCONV FPDFPage_New(FPDF_DOCUMENT document, int page_index, double width, double height); // Delete the page at |page_index|. // // document - handle to document. // page_index - the index of the page to delete. FPDF_EXPORT void FPDF_CALLCONV FPDFPage_Delete(FPDF_DOCUMENT document, int page_index); // Experimental API. // Move the given pages to a new index position. // // page_indices - the ordered list of pages to move. No duplicates allowed. // page_indices_len - the number of elements in |page_indices| // dest_page_index - the new index position to which the pages in // |page_indices| are moved. // // Returns TRUE on success. If it returns FALSE, the document may be left in an // indeterminate state. // // Example: The PDF document starts out with pages [A, B, C, D], with indices // [0, 1, 2, 3]. // // > Move(doc, [3, 2], 2, 1); // returns true // > // The document has pages [A, D, C, B]. // > // > Move(doc, [0, 4, 3], 3, 1); // returns false // > // Returned false because index 4 is out of range. // > // > Move(doc, [0, 3, 1], 3, 2); // returns false // > // Returned false because index 2 is out of range for 3 page indices. // > // > Move(doc, [2, 2], 2, 0); // returns false // > // Returned false because [2, 2] contains duplicates. // FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_MovePages(FPDF_DOCUMENT document, const int* page_indices, unsigned long page_indices_len, int dest_page_index); // Get the rotation of |page|. // // page - handle to a page // // Returns one of the following indicating the page rotation: // 0 - No rotation. // 1 - Rotated 90 degrees clockwise. // 2 - Rotated 180 degrees clockwise. // 3 - Rotated 270 degrees clockwise. FPDF_EXPORT int FPDF_CALLCONV FPDFPage_GetRotation(FPDF_PAGE page); // Set rotation for |page|. // // page - handle to a page. // rotate - the rotation value, one of: // 0 - No rotation. // 1 - Rotated 90 degrees clockwise. // 2 - Rotated 180 degrees clockwise. // 3 - Rotated 270 degrees clockwise. FPDF_EXPORT void FPDF_CALLCONV FPDFPage_SetRotation(FPDF_PAGE page, int rotate); // Insert |page_object| into |page|. // // page - handle to a page // page_object - handle to a page object. The |page_object| will be // automatically freed. FPDF_EXPORT void FPDF_CALLCONV FPDFPage_InsertObject(FPDF_PAGE page, FPDF_PAGEOBJECT page_object); // Insert |page_object| into |page| at the specified |index|. // // page - handle to a page // page_object - handle to a page object as previously obtained by // FPDFPageObj_CreateNew{Path|Rect}() or // FPDFPageObj_New{Text|Image}Obj(). Ownership of the object // is transferred back to PDFium. // index - the index position to insert the object at. If index equals // the current object count, the object will be appended to the // end. If index is greater than the object count, the function // will fail and return false. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_InsertObjectAtIndex(FPDF_PAGE page, FPDF_PAGEOBJECT page_object, size_t index); // Experimental API. // Remove |page_object| from |page|. // // page - handle to a page // page_object - handle to a page object to be removed. // // Returns TRUE on success. // // Ownership is transferred to the caller. Call FPDFPageObj_Destroy() to free // it. // Note that when removing a |page_object| of type FPDF_PAGEOBJ_TEXT, all // FPDF_TEXTPAGE handles for |page| are no longer valid. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_RemoveObject(FPDF_PAGE page, FPDF_PAGEOBJECT page_object); // Get number of page objects inside |page|. // // page - handle to a page. // // Returns the number of objects in |page|. FPDF_EXPORT int FPDF_CALLCONV FPDFPage_CountObjects(FPDF_PAGE page); // Get object in |page| at |index|. // // page - handle to a page. // index - the index of a page object. // // Returns the handle to the page object, or NULL on failed. FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV FPDFPage_GetObject(FPDF_PAGE page, int index); // Checks if |page| contains transparency. // // page - handle to a page. // // Returns TRUE if |page| contains transparency. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_HasTransparency(FPDF_PAGE page); // Generate the content of |page|. // // page - handle to a page. // // Returns TRUE on success. // // Before you save the page to a file, or reload the page, you must call // |FPDFPage_GenerateContent| or any changes to |page| will be lost. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_GenerateContent(FPDF_PAGE page); // Destroy |page_object| by releasing its resources. |page_object| must have // been created by FPDFPageObj_CreateNew{Path|Rect}() or // FPDFPageObj_New{Text|Image}Obj(). This function must be called on // newly-created objects if they are not added to a page through // FPDFPage_InsertObject() or to an annotation through FPDFAnnot_AppendObject(). // // page_object - handle to a page object. FPDF_EXPORT void FPDF_CALLCONV FPDFPageObj_Destroy(FPDF_PAGEOBJECT page_object); // Checks if |page_object| contains transparency. // // page_object - handle to a page object. // // Returns TRUE if |page_object| contains transparency. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_HasTransparency(FPDF_PAGEOBJECT page_object); // Get type of |page_object|. // // page_object - handle to a page object. // // Returns one of the FPDF_PAGEOBJ_* values on success, FPDF_PAGEOBJ_UNKNOWN on // error. FPDF_EXPORT int FPDF_CALLCONV FPDFPageObj_GetType(FPDF_PAGEOBJECT page_object); // Experimental API. // Gets active state for |page_object| within page. // // page_object - handle to a page object. // active - pointer to variable that will receive if the page object is // active. This is a required parameter. Not filled if FALSE // is returned. // // For page objects where |active| is filled with FALSE, the |page_object| is // treated as if it wasn't in the document even though it is still held // internally. // // Returns TRUE if the operation succeeded, FALSE if it failed. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_GetIsActive(FPDF_PAGEOBJECT page_object, FPDF_BOOL* active); // Experimental API. // Sets if |page_object| is active within page. // // page_object - handle to a page object. // active - a boolean specifying if the object is active. // // Returns TRUE on success. // // Page objects all start in the active state by default, and remain in that // state unless this function is called. // // When |active| is false, this makes the |page_object| be treated as if it // wasn't in the document even though it is still held internally. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_SetIsActive(FPDF_PAGEOBJECT page_object, FPDF_BOOL active); // Transform |page_object| by the given matrix. // // page_object - handle to a page object. // a - matrix value. // b - matrix value. // c - matrix value. // d - matrix value. // e - matrix value. // f - matrix value. // // The matrix is composed as: // |a c e| // |b d f| // and can be used to scale, rotate, shear and translate the |page_object|. FPDF_EXPORT void FPDF_CALLCONV FPDFPageObj_Transform(FPDF_PAGEOBJECT page_object, double a, double b, double c, double d, double e, double f); // Experimental API. // Transform |page_object| by the given matrix. // // page_object - handle to a page object. // matrix - the transform matrix. // // Returns TRUE on success. // // This can be used to scale, rotate, shear and translate the |page_object|. // It is an improved version of FPDFPageObj_Transform() that does not do // unnecessary double to float conversions, and only uses 1 parameter for the // matrix. It also returns whether the operation succeeded or not. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_TransformF(FPDF_PAGEOBJECT page_object, const FS_MATRIX* matrix); // Experimental API. // Get the transform matrix of a page object. // // page_object - handle to a page object. // matrix - pointer to struct to receive the matrix value. // // The matrix is composed as: // |a c e| // |b d f| // and used to scale, rotate, shear and translate the page object. // // For page objects outside form objects, the matrix values are relative to the // page that contains it. // For page objects inside form objects, the matrix values are relative to the // form that contains it. // // Returns TRUE on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_GetMatrix(FPDF_PAGEOBJECT page_object, FS_MATRIX* matrix); // Experimental API. // Set the transform matrix of a page object. // // page_object - handle to a page object. // matrix - pointer to struct with the matrix value. // // The matrix is composed as: // |a c e| // |b d f| // and can be used to scale, rotate, shear and translate the page object. // // Returns TRUE on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_SetMatrix(FPDF_PAGEOBJECT page_object, const FS_MATRIX* matrix); // Transform all annotations in |page|. // // page - handle to a page. // a - matrix value. // b - matrix value. // c - matrix value. // d - matrix value. // e - matrix value. // f - matrix value. // // The matrix is composed as: // |a c e| // |b d f| // and can be used to scale, rotate, shear and translate the |page| annotations. FPDF_EXPORT void FPDF_CALLCONV FPDFPage_TransformAnnots(FPDF_PAGE page, double a, double b, double c, double d, double e, double f); // Create a new image object. // // document - handle to a document. // // Returns a handle to a new image object. FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV FPDFPageObj_NewImageObj(FPDF_DOCUMENT document); // Experimental API. // Get the marked content ID for the object. // // page_object - handle to a page object. // // Returns the page object's marked content ID, or -1 on error. FPDF_EXPORT int FPDF_CALLCONV FPDFPageObj_GetMarkedContentID(FPDF_PAGEOBJECT page_object); // Experimental API. // Get number of content marks in |page_object|. // // page_object - handle to a page object. // // Returns the number of content marks in |page_object|, or -1 in case of // failure. FPDF_EXPORT int FPDF_CALLCONV FPDFPageObj_CountMarks(FPDF_PAGEOBJECT page_object); // Experimental API. // Get content mark in |page_object| at |index|. // // page_object - handle to a page object. // index - the index of a page object. // // Returns the handle to the content mark, or NULL on failure. The handle is // still owned by the library, and it should not be freed directly. It becomes // invalid if the page object is destroyed, either directly or indirectly by // unloading the page. FPDF_EXPORT FPDF_PAGEOBJECTMARK FPDF_CALLCONV FPDFPageObj_GetMark(FPDF_PAGEOBJECT page_object, unsigned long index); // Experimental API. // Add a new content mark to a |page_object|. // // page_object - handle to a page object. // name - the name (tag) of the mark. // // Returns the handle to the content mark, or NULL on failure. The handle is // still owned by the library, and it should not be freed directly. It becomes // invalid if the page object is destroyed, either directly or indirectly by // unloading the page. FPDF_EXPORT FPDF_PAGEOBJECTMARK FPDF_CALLCONV FPDFPageObj_AddMark(FPDF_PAGEOBJECT page_object, FPDF_BYTESTRING name); // Experimental API. // Removes a content |mark| from a |page_object|. // The mark handle will be invalid after the removal. // // page_object - handle to a page object. // mark - handle to a content mark in that object to remove. // // Returns TRUE if the operation succeeded, FALSE if it failed. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_RemoveMark(FPDF_PAGEOBJECT page_object, FPDF_PAGEOBJECTMARK mark); // Experimental API. // Get the name of a content mark. // // mark - handle to a content mark. // buffer - buffer for holding the returned name in UTF-16LE. This is only // modified if |buflen| is large enough to store the name. // Optional, pass null to just retrieve the size of the buffer // needed. // buflen - length of the buffer in bytes. // out_buflen - pointer to variable that will receive the minimum buffer size // in bytes to contain the name. This is a required parameter. // Not filled if FALSE is returned. // // Returns TRUE if the operation succeeded, FALSE if it failed. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObjMark_GetName(FPDF_PAGEOBJECTMARK mark, FPDF_WCHAR* buffer, unsigned long buflen, unsigned long* out_buflen); // Experimental API. // Get the number of key/value pair parameters in |mark|. // // mark - handle to a content mark. // // Returns the number of key/value pair parameters |mark|, or -1 in case of // failure. FPDF_EXPORT int FPDF_CALLCONV FPDFPageObjMark_CountParams(FPDF_PAGEOBJECTMARK mark); // Experimental API. // Get the key of a property in a content mark. // // mark - handle to a content mark. // index - index of the property. // buffer - buffer for holding the returned key in UTF-16LE. This is only // modified if |buflen| is large enough to store the key. // Optional, pass null to just retrieve the size of the buffer // needed. // buflen - length of the buffer in bytes. // out_buflen - pointer to variable that will receive the minimum buffer size // in bytes to contain the name. This is a required parameter. // Not filled if FALSE is returned. // // Returns TRUE if the operation was successful, FALSE otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObjMark_GetParamKey(FPDF_PAGEOBJECTMARK mark, unsigned long index, FPDF_WCHAR* buffer, unsigned long buflen, unsigned long* out_buflen); // Experimental API. // Get the type of the value of a property in a content mark by key. // // mark - handle to a content mark. // key - string key of the property. // // Returns the type of the value, or FPDF_OBJECT_UNKNOWN in case of failure. FPDF_EXPORT FPDF_OBJECT_TYPE FPDF_CALLCONV FPDFPageObjMark_GetParamValueType(FPDF_PAGEOBJECTMARK mark, FPDF_BYTESTRING key); // Experimental API. // Get the value of a number property in a content mark by key as int. // FPDFPageObjMark_GetParamValueType() should have returned FPDF_OBJECT_NUMBER // for this property. // // mark - handle to a content mark. // key - string key of the property. // out_value - pointer to variable that will receive the value. Not filled if // false is returned. // // Returns TRUE if the key maps to a number value, FALSE otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObjMark_GetParamIntValue(FPDF_PAGEOBJECTMARK mark, FPDF_BYTESTRING key, int* out_value); // Experimental API. // Get the value of a number property in a content mark by key as float. // FPDFPageObjMark_GetParamValueType() should have returned FPDF_OBJECT_NUMBER // for this property. // // mark - handle to a content mark. // key - string key of the property. // out_value - pointer to variable that will receive the value. Not filled if // false is returned. // // Returns TRUE if the key maps to a number value, FALSE otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObjMark_GetParamFloatValue(FPDF_PAGEOBJECTMARK mark, FPDF_BYTESTRING key, float* out_value); // Experimental API. // Get the value of a string property in a content mark by key. // // mark - handle to a content mark. // key - string key of the property. // buffer - buffer for holding the returned value in UTF-16LE. This is // only modified if |buflen| is large enough to store the value. // Optional, pass null to just retrieve the size of the buffer // needed. // buflen - length of the buffer in bytes. // out_buflen - pointer to variable that will receive the minimum buffer size // in bytes to contain the name. This is a required parameter. // Not filled if FALSE is returned. // // Returns TRUE if the key maps to a string/blob value, FALSE otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObjMark_GetParamStringValue(FPDF_PAGEOBJECTMARK mark, FPDF_BYTESTRING key, FPDF_WCHAR* buffer, unsigned long buflen, unsigned long* out_buflen); // Experimental API. // Get the value of a blob property in a content mark by key. // // mark - handle to a content mark. // key - string key of the property. // buffer - buffer for holding the returned value. This is only modified // if |buflen| is large enough to store the value. // Optional, pass null to just retrieve the size of the buffer // needed. // buflen - length of the buffer in bytes. // out_buflen - pointer to variable that will receive the minimum buffer size // in bytes to contain the name. This is a required parameter. // Not filled if FALSE is returned. // // Returns TRUE if the key maps to a string/blob value, FALSE otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObjMark_GetParamBlobValue(FPDF_PAGEOBJECTMARK mark, FPDF_BYTESTRING key, unsigned char* buffer, unsigned long buflen, unsigned long* out_buflen); // Experimental API. // Set the value of an int property in a content mark by key. If a parameter // with key |key| exists, its value is set to |value|. Otherwise, it is added as // a new parameter. // // document - handle to the document. // page_object - handle to the page object with the mark. // mark - handle to a content mark. // key - string key of the property. // value - int value to set. // // Returns TRUE if the operation succeeded, FALSE otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObjMark_SetIntParam(FPDF_DOCUMENT document, FPDF_PAGEOBJECT page_object, FPDF_PAGEOBJECTMARK mark, FPDF_BYTESTRING key, int value); // Experimental API. // Set the value of a float property in a content mark by key. If a parameter // with key |key| exists, its value is set to |value|. Otherwise, it is added as // a new parameter. // // document - handle to the document. // page_object - handle to the page object with the mark. // mark - handle to a content mark. // key - string key of the property. // value - float value to set. // // Returns TRUE if the operation succeeded, FALSE otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObjMark_SetFloatParam(FPDF_DOCUMENT document, FPDF_PAGEOBJECT page_object, FPDF_PAGEOBJECTMARK mark, FPDF_BYTESTRING key, float value); // Experimental API. // Set the value of a string property in a content mark by key. If a parameter // with key |key| exists, its value is set to |value|. Otherwise, it is added as // a new parameter. // // document - handle to the document. // page_object - handle to the page object with the mark. // mark - handle to a content mark. // key - string key of the property. // value - string value to set. // // Returns TRUE if the operation succeeded, FALSE otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObjMark_SetStringParam(FPDF_DOCUMENT document, FPDF_PAGEOBJECT page_object, FPDF_PAGEOBJECTMARK mark, FPDF_BYTESTRING key, FPDF_BYTESTRING value); // Experimental API. // Set the value of a blob property in a content mark by key. If a parameter // with key |key| exists, its value is set to |value|. Otherwise, it is added as // a new parameter. // // document - handle to the document. // page_object - handle to the page object with the mark. // mark - handle to a content mark. // key - string key of the property. // value - pointer to blob value to set. // value_len - size in bytes of |value|. // // Returns TRUE if the operation succeeded, FALSE otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObjMark_SetBlobParam(FPDF_DOCUMENT document, FPDF_PAGEOBJECT page_object, FPDF_PAGEOBJECTMARK mark, FPDF_BYTESTRING key, const unsigned char* value, unsigned long value_len); // Experimental API. // Removes a property from a content mark by key. // // page_object - handle to the page object with the mark. // mark - handle to a content mark. // key - string key of the property. // // Returns TRUE if the operation succeeded, FALSE otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObjMark_RemoveParam(FPDF_PAGEOBJECT page_object, FPDF_PAGEOBJECTMARK mark, FPDF_BYTESTRING key); // Load an image from a JPEG image file and then set it into |image_object|. // // pages - pointer to the start of all loaded pages, may be NULL. // count - number of |pages|, may be 0. // image_object - handle to an image object. // file_access - file access handler which specifies the JPEG image file. // // Returns TRUE on success. // // The image object might already have an associated image, which is shared and // cached by the loaded pages. In that case, we need to clear the cached image // for all the loaded pages. Pass |pages| and page count (|count|) to this API // to clear the image cache. If the image is not previously shared, or NULL is a // valid |pages| value. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFImageObj_LoadJpegFile(FPDF_PAGE* pages, int count, FPDF_PAGEOBJECT image_object, FPDF_FILEACCESS* file_access); // Load an image from a JPEG image file and then set it into |image_object|. // // pages - pointer to the start of all loaded pages, may be NULL. // count - number of |pages|, may be 0. // image_object - handle to an image object. // file_access - file access handler which specifies the JPEG image file. // // Returns TRUE on success. // // The image object might already have an associated image, which is shared and // cached by the loaded pages. In that case, we need to clear the cached image // for all the loaded pages. Pass |pages| and page count (|count|) to this API // to clear the image cache. If the image is not previously shared, or NULL is a // valid |pages| value. This function loads the JPEG image inline, so the image // content is copied to the file. This allows |file_access| and its associated // data to be deleted after this function returns. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFImageObj_LoadJpegFileInline(FPDF_PAGE* pages, int count, FPDF_PAGEOBJECT image_object, FPDF_FILEACCESS* file_access); // TODO(thestig): Start deprecating this once FPDFPageObj_SetMatrix() is stable. // // Set the transform matrix of |image_object|. // // image_object - handle to an image object. // a - matrix value. // b - matrix value. // c - matrix value. // d - matrix value. // e - matrix value. // f - matrix value. // // The matrix is composed as: // |a c e| // |b d f| // and can be used to scale, rotate, shear and translate the |image_object|. // // Returns TRUE on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFImageObj_SetMatrix(FPDF_PAGEOBJECT image_object, double a, double b, double c, double d, double e, double f); // Set |bitmap| to |image_object|. // // pages - pointer to the start of all loaded pages, may be NULL. // count - number of |pages|, may be 0. // image_object - handle to an image object. // bitmap - handle of the bitmap. // // Returns TRUE on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFImageObj_SetBitmap(FPDF_PAGE* pages, int count, FPDF_PAGEOBJECT image_object, FPDF_BITMAP bitmap); // Get a bitmap rasterization of |image_object|. FPDFImageObj_GetBitmap() only // operates on |image_object| and does not take the associated image mask into // account. It also ignores the matrix for |image_object|. // The returned bitmap will be owned by the caller, and FPDFBitmap_Destroy() // must be called on the returned bitmap when it is no longer needed. // // image_object - handle to an image object. // // Returns the bitmap. FPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV FPDFImageObj_GetBitmap(FPDF_PAGEOBJECT image_object); // Experimental API. // Get a bitmap rasterization of |image_object| that takes the image mask and // image matrix into account. To render correctly, the caller must provide the // |document| associated with |image_object|. If there is a |page| associated // with |image_object|, the caller should provide that as well. // The returned bitmap will be owned by the caller, and FPDFBitmap_Destroy() // must be called on the returned bitmap when it is no longer needed. // // document - handle to a document associated with |image_object|. // page - handle to an optional page associated with |image_object|. // image_object - handle to an image object. // // Returns the bitmap or NULL on failure. FPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV FPDFImageObj_GetRenderedBitmap(FPDF_DOCUMENT document, FPDF_PAGE page, FPDF_PAGEOBJECT image_object); // Get the decoded image data of |image_object|. The decoded data is the // uncompressed image data, i.e. the raw image data after having all filters // applied. |buffer| is only modified if |buflen| is longer than the length of // the decoded image data. // // image_object - handle to an image object. // buffer - buffer for holding the decoded image data. // buflen - length of the buffer in bytes. // // Returns the length of the decoded image data. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFImageObj_GetImageDataDecoded(FPDF_PAGEOBJECT image_object, void* buffer, unsigned long buflen); // Get the raw image data of |image_object|. The raw data is the image data as // stored in the PDF without applying any filters. |buffer| is only modified if // |buflen| is longer than the length of the raw image data. // // image_object - handle to an image object. // buffer - buffer for holding the raw image data. // buflen - length of the buffer in bytes. // // Returns the length of the raw image data. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFImageObj_GetImageDataRaw(FPDF_PAGEOBJECT image_object, void* buffer, unsigned long buflen); // Get the number of filters (i.e. decoders) of the image in |image_object|. // // image_object - handle to an image object. // // Returns the number of |image_object|'s filters. FPDF_EXPORT int FPDF_CALLCONV FPDFImageObj_GetImageFilterCount(FPDF_PAGEOBJECT image_object); // Get the filter at |index| of |image_object|'s list of filters. Note that the // filters need to be applied in order, i.e. the first filter should be applied // first, then the second, etc. |buffer| is only modified if |buflen| is longer // than the length of the filter string. // // image_object - handle to an image object. // index - the index of the filter requested. // buffer - buffer for holding filter string, encoded in UTF-8. // buflen - length of the buffer. // // Returns the length of the filter string. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFImageObj_GetImageFilter(FPDF_PAGEOBJECT image_object, int index, void* buffer, unsigned long buflen); // Get the image metadata of |image_object|, including dimension, DPI, bits per // pixel, and colorspace. If the |image_object| is not an image object or if it // does not have an image, then the return value will be false. Otherwise, // failure to retrieve any specific parameter would result in its value being 0. // // image_object - handle to an image object. // page - handle to the page that |image_object| is on. Required for // retrieving the image's bits per pixel and colorspace. // metadata - receives the image metadata; must not be NULL. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFImageObj_GetImageMetadata(FPDF_PAGEOBJECT image_object, FPDF_PAGE page, FPDF_IMAGEOBJ_METADATA* metadata); // Experimental API. // Get the image size in pixels. Faster method to get only image size. // // image_object - handle to an image object. // width - receives the image width in pixels; must not be NULL. // height - receives the image height in pixels; must not be NULL. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFImageObj_GetImagePixelSize(FPDF_PAGEOBJECT image_object, unsigned int* width, unsigned int* height); // Experimental API. // Get ICC profile decoded data of |image_object|. If the |image_object| is not // an image object or if it does not have an image, then the return value will // be false. It also returns false if the |image_object| has no ICC profile. // |buffer| is only modified if ICC profile exists and |buflen| is longer than // the length of the ICC profile decoded data. // // image_object - handle to an image object; must not be NULL. // page - handle to the page containing |image_object|; must not be // NULL. Required for retrieving the image's colorspace. // buffer - Buffer to receive ICC profile data; may be NULL if querying // required size via |out_buflen|. // buflen - Length of the buffer in bytes. Ignored if |buffer| is NULL. // out_buflen - Pointer to receive the ICC profile data size in bytes; must // not be NULL. Will be set if this API returns true. // // Returns true if |out_buflen| is not null and an ICC profile exists for the // given |image_object|. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFImageObj_GetIccProfileDataDecoded(FPDF_PAGEOBJECT image_object, FPDF_PAGE page, uint8_t* buffer, size_t buflen, size_t* out_buflen); // Create a new path object at an initial position. // // x - initial horizontal position. // y - initial vertical position. // // Returns a handle to a new path object. FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV FPDFPageObj_CreateNewPath(float x, float y); // Create a closed path consisting of a rectangle. // // x - horizontal position for the left boundary of the rectangle. // y - vertical position for the bottom boundary of the rectangle. // w - width of the rectangle. // h - height of the rectangle. // // Returns a handle to the new path object. FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV FPDFPageObj_CreateNewRect(float x, float y, float w, float h); // Get the bounding box of |page_object|. // // page_object - handle to a page object. // left - pointer where the left coordinate will be stored // bottom - pointer where the bottom coordinate will be stored // right - pointer where the right coordinate will be stored // top - pointer where the top coordinate will be stored // // On success, returns TRUE and fills in the 4 coordinates. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_GetBounds(FPDF_PAGEOBJECT page_object, float* left, float* bottom, float* right, float* top); // Experimental API. // Get the quad points that bounds |page_object|. // // page_object - handle to a page object. // quad_points - pointer where the quadrilateral points will be stored. // // On success, returns TRUE and fills in |quad_points|. // // Similar to FPDFPageObj_GetBounds(), this returns the bounds of a page // object. When the object is rotated by a non-multiple of 90 degrees, this API // returns a tighter bound that cannot be represented with just the 4 sides of // a rectangle. // // Currently only works the following |page_object| types: FPDF_PAGEOBJ_TEXT and // FPDF_PAGEOBJ_IMAGE. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_GetRotatedBounds(FPDF_PAGEOBJECT page_object, FS_QUADPOINTSF* quad_points); // Set the blend mode of |page_object|. // // page_object - handle to a page object. // blend_mode - string containing the blend mode. // // Blend mode can be one of following: Color, ColorBurn, ColorDodge, Darken, // Difference, Exclusion, HardLight, Hue, Lighten, Luminosity, Multiply, Normal, // Overlay, Saturation, Screen, SoftLight FPDF_EXPORT void FPDF_CALLCONV FPDFPageObj_SetBlendMode(FPDF_PAGEOBJECT page_object, FPDF_BYTESTRING blend_mode); // Set the stroke RGBA of a page object. Range of values: 0 - 255. // // page_object - the handle to the page object. // R - the red component for the object's stroke color. // G - the green component for the object's stroke color. // B - the blue component for the object's stroke color. // A - the stroke alpha for the object. // // Returns TRUE on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_SetStrokeColor(FPDF_PAGEOBJECT page_object, unsigned int R, unsigned int G, unsigned int B, unsigned int A); // Get the stroke RGBA of a page object. Range of values: 0 - 255. // // page_object - the handle to the page object. // R - the red component of the path stroke color. // G - the green component of the object's stroke color. // B - the blue component of the object's stroke color. // A - the stroke alpha of the object. // // Returns TRUE on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_GetStrokeColor(FPDF_PAGEOBJECT page_object, unsigned int* R, unsigned int* G, unsigned int* B, unsigned int* A); // Set the stroke width of a page object. // // path - the handle to the page object. // width - the width of the stroke. // // Returns TRUE on success FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_SetStrokeWidth(FPDF_PAGEOBJECT page_object, float width); // Get the stroke width of a page object. // // path - the handle to the page object. // width - the width of the stroke. // // Returns TRUE on success FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_GetStrokeWidth(FPDF_PAGEOBJECT page_object, float* width); // Get the line join of |page_object|. // // page_object - handle to a page object. // // Returns the line join, or -1 on failure. // Line join can be one of following: FPDF_LINEJOIN_MITER, FPDF_LINEJOIN_ROUND, // FPDF_LINEJOIN_BEVEL FPDF_EXPORT int FPDF_CALLCONV FPDFPageObj_GetLineJoin(FPDF_PAGEOBJECT page_object); // Set the line join of |page_object|. // // page_object - handle to a page object. // line_join - line join // // Line join can be one of following: FPDF_LINEJOIN_MITER, FPDF_LINEJOIN_ROUND, // FPDF_LINEJOIN_BEVEL FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_SetLineJoin(FPDF_PAGEOBJECT page_object, int line_join); // Get the line cap of |page_object|. // // page_object - handle to a page object. // // Returns the line cap, or -1 on failure. // Line cap can be one of following: FPDF_LINECAP_BUTT, FPDF_LINECAP_ROUND, // FPDF_LINECAP_PROJECTING_SQUARE FPDF_EXPORT int FPDF_CALLCONV FPDFPageObj_GetLineCap(FPDF_PAGEOBJECT page_object); // Set the line cap of |page_object|. // // page_object - handle to a page object. // line_cap - line cap // // Line cap can be one of following: FPDF_LINECAP_BUTT, FPDF_LINECAP_ROUND, // FPDF_LINECAP_PROJECTING_SQUARE FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_SetLineCap(FPDF_PAGEOBJECT page_object, int line_cap); // Set the fill RGBA of a page object. Range of values: 0 - 255. // // page_object - the handle to the page object. // R - the red component for the object's fill color. // G - the green component for the object's fill color. // B - the blue component for the object's fill color. // A - the fill alpha for the object. // // Returns TRUE on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_SetFillColor(FPDF_PAGEOBJECT page_object, unsigned int R, unsigned int G, unsigned int B, unsigned int A); // Get the fill RGBA of a page object. Range of values: 0 - 255. // // page_object - the handle to the page object. // R - the red component of the object's fill color. // G - the green component of the object's fill color. // B - the blue component of the object's fill color. // A - the fill alpha of the object. // // Returns TRUE on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_GetFillColor(FPDF_PAGEOBJECT page_object, unsigned int* R, unsigned int* G, unsigned int* B, unsigned int* A); // Experimental API. // Get the line dash |phase| of |page_object|. // // page_object - handle to a page object. // phase - pointer where the dashing phase will be stored. // // Returns TRUE on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_GetDashPhase(FPDF_PAGEOBJECT page_object, float* phase); // Experimental API. // Set the line dash phase of |page_object|. // // page_object - handle to a page object. // phase - line dash phase. // // Returns TRUE on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_SetDashPhase(FPDF_PAGEOBJECT page_object, float phase); // Experimental API. // Get the line dash array of |page_object|. // // page_object - handle to a page object. // // Returns the line dash array size or -1 on failure. FPDF_EXPORT int FPDF_CALLCONV FPDFPageObj_GetDashCount(FPDF_PAGEOBJECT page_object); // Experimental API. // Get the line dash array of |page_object|. // // page_object - handle to a page object. // dash_array - pointer where the dashing array will be stored. // dash_count - number of elements in |dash_array|. // // Returns TRUE on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_GetDashArray(FPDF_PAGEOBJECT page_object, float* dash_array, size_t dash_count); // Experimental API. // Set the line dash array of |page_object|. // // page_object - handle to a page object. // dash_array - the dash array. // dash_count - number of elements in |dash_array|. // phase - the line dash phase. // // Returns TRUE on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_SetDashArray(FPDF_PAGEOBJECT page_object, const float* dash_array, size_t dash_count, float phase); // Get number of segments inside |path|. // // path - handle to a path. // // A segment is a command, created by e.g. FPDFPath_MoveTo(), // FPDFPath_LineTo() or FPDFPath_BezierTo(). // // Returns the number of objects in |path| or -1 on failure. FPDF_EXPORT int FPDF_CALLCONV FPDFPath_CountSegments(FPDF_PAGEOBJECT path); // Get segment in |path| at |index|. // // path - handle to a path. // index - the index of a segment. // // Returns the handle to the segment, or NULL on faiure. FPDF_EXPORT FPDF_PATHSEGMENT FPDF_CALLCONV FPDFPath_GetPathSegment(FPDF_PAGEOBJECT path, int index); // Get coordinates of |segment|. // // segment - handle to a segment. // x - the horizontal position of the segment. // y - the vertical position of the segment. // // Returns TRUE on success, otherwise |x| and |y| is not set. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPathSegment_GetPoint(FPDF_PATHSEGMENT segment, float* x, float* y); // Get type of |segment|. // // segment - handle to a segment. // // Returns one of the FPDF_SEGMENT_* values on success, // FPDF_SEGMENT_UNKNOWN on error. FPDF_EXPORT int FPDF_CALLCONV FPDFPathSegment_GetType(FPDF_PATHSEGMENT segment); // Gets if the |segment| closes the current subpath of a given path. // // segment - handle to a segment. // // Returns close flag for non-NULL segment, FALSE otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPathSegment_GetClose(FPDF_PATHSEGMENT segment); // Move a path's current point. // // path - the handle to the path object. // x - the horizontal position of the new current point. // y - the vertical position of the new current point. // // Note that no line will be created between the previous current point and the // new one. // // Returns TRUE on success FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_MoveTo(FPDF_PAGEOBJECT path, float x, float y); // Add a line between the current point and a new point in the path. // // path - the handle to the path object. // x - the horizontal position of the new point. // y - the vertical position of the new point. // // The path's current point is changed to (x, y). // // Returns TRUE on success FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_LineTo(FPDF_PAGEOBJECT path, float x, float y); // Add a cubic Bezier curve to the given path, starting at the current point. // // path - the handle to the path object. // x1 - the horizontal position of the first Bezier control point. // y1 - the vertical position of the first Bezier control point. // x2 - the horizontal position of the second Bezier control point. // y2 - the vertical position of the second Bezier control point. // x3 - the horizontal position of the ending point of the Bezier curve. // y3 - the vertical position of the ending point of the Bezier curve. // // Returns TRUE on success FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_BezierTo(FPDF_PAGEOBJECT path, float x1, float y1, float x2, float y2, float x3, float y3); // Close the current subpath of a given path. // // path - the handle to the path object. // // This will add a line between the current point and the initial point of the // subpath, thus terminating the current subpath. // // Returns TRUE on success FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_Close(FPDF_PAGEOBJECT path); // Set the drawing mode of a path. // // path - the handle to the path object. // fillmode - the filling mode to be set: one of the FPDF_FILLMODE_* flags. // stroke - a boolean specifying if the path should be stroked or not. // // Returns TRUE on success FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_SetDrawMode(FPDF_PAGEOBJECT path, int fillmode, FPDF_BOOL stroke); // Get the drawing mode of a path. // // path - the handle to the path object. // fillmode - the filling mode of the path: one of the FPDF_FILLMODE_* flags. // stroke - a boolean specifying if the path is stroked or not. // // Returns TRUE on success FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_GetDrawMode(FPDF_PAGEOBJECT path, int* fillmode, FPDF_BOOL* stroke); // Create a new text object using one of the standard PDF fonts. // // document - handle to the document. // font - string containing the font name, without spaces. // font_size - the font size for the new text object. // // Returns a handle to a new text object, or NULL on failure FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV FPDFPageObj_NewTextObj(FPDF_DOCUMENT document, FPDF_BYTESTRING font, float font_size); // Set the text for a text object. If it had text, it will be replaced. // // text_object - handle to the text object. // text - the UTF-16LE encoded string containing the text to be added. // // Returns TRUE on success FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFText_SetText(FPDF_PAGEOBJECT text_object, FPDF_WIDESTRING text); // Experimental API. // Set the text using charcodes for a text object. If it had text, it will be // replaced. // // text_object - handle to the text object. // charcodes - pointer to an array of charcodes to be added. // count - number of elements in |charcodes|. // // Returns TRUE on success FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFText_SetCharcodes(FPDF_PAGEOBJECT text_object, const uint32_t* charcodes, size_t count); // Returns a font object loaded from a stream of data. The font is loaded // into the document. Various font data structures, such as the ToUnicode data, // are auto-generated based on the inputs. // // document - handle to the document. // data - the stream of font data, which will be copied by the font object. // size - the size of the font data, in bytes. // font_type - FPDF_FONT_TYPE1 or FPDF_FONT_TRUETYPE depending on the font type. // cid - a boolean specifying if the font is a CID font or not. // // The loaded font can be closed using FPDFFont_Close(). // // Returns NULL on failure FPDF_EXPORT FPDF_FONT FPDF_CALLCONV FPDFText_LoadFont(FPDF_DOCUMENT document, const uint8_t* data, uint32_t size, int font_type, FPDF_BOOL cid); // Experimental API. // Loads one of the standard 14 fonts per PDF spec 1.7 page 416. The preferred // way of using font style is using a dash to separate the name from the style, // for example 'Helvetica-BoldItalic'. // // document - handle to the document. // font - string containing the font name, without spaces. // // The loaded font can be closed using FPDFFont_Close(). // // Returns NULL on failure. FPDF_EXPORT FPDF_FONT FPDF_CALLCONV FPDFText_LoadStandardFont(FPDF_DOCUMENT document, FPDF_BYTESTRING font); // Experimental API. // Returns a font object loaded from a stream of data for a type 2 CID font. The // font is loaded into the document. Unlike FPDFText_LoadFont(), the ToUnicode // data and the CIDToGIDMap data are caller provided, instead of auto-generated. // // document - handle to the document. // font_data - the stream of font data, which will be copied by // the font object. // font_data_size - the size of the font data, in bytes. // to_unicode_cmap - the ToUnicode data. // cid_to_gid_map_data - the stream of CIDToGIDMap data. // cid_to_gid_map_data_size - the size of the CIDToGIDMap data, in bytes. // // The loaded font can be closed using FPDFFont_Close(). // // Returns NULL on failure. FPDF_EXPORT FPDF_FONT FPDF_CALLCONV FPDFText_LoadCidType2Font(FPDF_DOCUMENT document, const uint8_t* font_data, uint32_t font_data_size, FPDF_BYTESTRING to_unicode_cmap, const uint8_t* cid_to_gid_map_data, uint32_t cid_to_gid_map_data_size); // Get the font size of a text object. // // text - handle to a text. // size - pointer to the font size of the text object, measured in points // (about 1/72 inch) // // Returns TRUE on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFTextObj_GetFontSize(FPDF_PAGEOBJECT text, float* size); // Close a loaded PDF font. // // font - Handle to the loaded font. FPDF_EXPORT void FPDF_CALLCONV FPDFFont_Close(FPDF_FONT font); // Create a new text object using a loaded font. // // document - handle to the document. // font - handle to the font object. // font_size - the font size for the new text object. // // Returns a handle to a new text object, or NULL on failure FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV FPDFPageObj_CreateTextObj(FPDF_DOCUMENT document, FPDF_FONT font, float font_size); // Get the text rendering mode of a text object. // // text - the handle to the text object. // // Returns one of the known FPDF_TEXT_RENDERMODE enum values on success, // FPDF_TEXTRENDERMODE_UNKNOWN on error. FPDF_EXPORT FPDF_TEXT_RENDERMODE FPDF_CALLCONV FPDFTextObj_GetTextRenderMode(FPDF_PAGEOBJECT text); // Experimental API. // Set the text rendering mode of a text object. // // text - the handle to the text object. // render_mode - the FPDF_TEXT_RENDERMODE enum value to be set (cannot set to // FPDF_TEXTRENDERMODE_UNKNOWN). // // Returns TRUE on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFTextObj_SetTextRenderMode(FPDF_PAGEOBJECT text, FPDF_TEXT_RENDERMODE render_mode); // Get the text of a text object. // // text_object - the handle to the text object. // text_page - the handle to the text page. // buffer - the address of a buffer that receives the text. // length - the size, in bytes, of |buffer|. // // Returns the number of bytes in the text (including the trailing NUL // character) on success, 0 on error. // // Regardless of the platform, the |buffer| is always in UTF-16LE encoding. // If |length| is less than the returned length, or |buffer| is NULL, |buffer| // will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFTextObj_GetText(FPDF_PAGEOBJECT text_object, FPDF_TEXTPAGE text_page, FPDF_WCHAR* buffer, unsigned long length); // Experimental API. // Get a bitmap rasterization of |text_object|. To render correctly, the caller // must provide the |document| associated with |text_object|. If there is a // |page| associated with |text_object|, the caller should provide that as well. // The returned bitmap will be owned by the caller, and FPDFBitmap_Destroy() // must be called on the returned bitmap when it is no longer needed. // // document - handle to a document associated with |text_object|. // page - handle to an optional page associated with |text_object|. // text_object - handle to a text object. // scale - the scaling factor, which must be greater than 0. // // Returns the bitmap or NULL on failure. FPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV FPDFTextObj_GetRenderedBitmap(FPDF_DOCUMENT document, FPDF_PAGE page, FPDF_PAGEOBJECT text_object, float scale); // Experimental API. // Get the font of a text object. // // text - the handle to the text object. // // Returns a handle to the font object held by |text| which retains ownership. FPDF_EXPORT FPDF_FONT FPDF_CALLCONV FPDFTextObj_GetFont(FPDF_PAGEOBJECT text); // Experimental API. // Get the base name of a font. // // font - the handle to the font object. // buffer - the address of a buffer that receives the base font name. // length - the size, in bytes, of |buffer|. // // Returns the number of bytes in the base name (including the trailing NUL // character) on success, 0 on error. The base name is typically the font's // PostScript name. See descriptions of "BaseFont" in ISO 32000-1:2008 spec. // // Regardless of the platform, the |buffer| is always in UTF-8 encoding. // If |length| is less than the returned length, or |buffer| is NULL, |buffer| // will not be modified. FPDF_EXPORT size_t FPDF_CALLCONV FPDFFont_GetBaseFontName(FPDF_FONT font, char* buffer, size_t length); // Experimental API. // Get the family name of a font. // // font - the handle to the font object. // buffer - the address of a buffer that receives the font name. // length - the size, in bytes, of |buffer|. // // Returns the number of bytes in the family name (including the trailing NUL // character) on success, 0 on error. // // Regardless of the platform, the |buffer| is always in UTF-8 encoding. // If |length| is less than the returned length, or |buffer| is NULL, |buffer| // will not be modified. FPDF_EXPORT size_t FPDF_CALLCONV FPDFFont_GetFamilyName(FPDF_FONT font, char* buffer, size_t length); // Experimental API. // Get the decoded data from the |font| object. // // font - The handle to the font object. (Required) // buffer - The address of a buffer that receives the font data. // buflen - Length of the buffer. // out_buflen - Pointer to variable that will receive the minimum buffer size // to contain the font data. Not filled if the return value is // FALSE. (Required) // // Returns TRUE on success. In which case, |out_buflen| will be filled, and // |buffer| will be filled if it is large enough. Returns FALSE if any of the // required parameters are null. // // The decoded data is the uncompressed font data. i.e. the raw font data after // having all stream filters applied, when the data is embedded. // // If the font is not embedded, then this API will instead return the data for // the substitution font it is using. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFFont_GetFontData(FPDF_FONT font, uint8_t* buffer, size_t buflen, size_t* out_buflen); // Experimental API. // Get whether |font| is embedded or not. // // font - the handle to the font object. // // Returns 1 if the font is embedded, 0 if it not, and -1 on failure. FPDF_EXPORT int FPDF_CALLCONV FPDFFont_GetIsEmbedded(FPDF_FONT font); // Experimental API. // Get the descriptor flags of a font. // // font - the handle to the font object. // // Returns the bit flags specifying various characteristics of the font as // defined in ISO 32000-1:2008, table 123, -1 on failure. FPDF_EXPORT int FPDF_CALLCONV FPDFFont_GetFlags(FPDF_FONT font); // Experimental API. // Get the font weight of a font. // // font - the handle to the font object. // // Returns the font weight, -1 on failure. // Typical values are 400 (normal) and 700 (bold). FPDF_EXPORT int FPDF_CALLCONV FPDFFont_GetWeight(FPDF_FONT font); // Experimental API. // Get the italic angle of a font. // // font - the handle to the font object. // angle - pointer where the italic angle will be stored // // The italic angle of a |font| is defined as degrees counterclockwise // from vertical. For a font that slopes to the right, this will be negative. // // Returns TRUE on success; |angle| unmodified on failure. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFFont_GetItalicAngle(FPDF_FONT font, int* angle); // Experimental API. // Get ascent distance of a font. // // font - the handle to the font object. // font_size - the size of the |font|. // ascent - pointer where the font ascent will be stored // // Ascent is the maximum distance in points above the baseline reached by the // glyphs of the |font|. One point is 1/72 inch (around 0.3528 mm). // // Returns TRUE on success; |ascent| unmodified on failure. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFFont_GetAscent(FPDF_FONT font, float font_size, float* ascent); // Experimental API. // Get descent distance of a font. // // font - the handle to the font object. // font_size - the size of the |font|. // descent - pointer where the font descent will be stored // // Descent is the maximum distance in points below the baseline reached by the // glyphs of the |font|. One point is 1/72 inch (around 0.3528 mm). // // Returns TRUE on success; |descent| unmodified on failure. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFFont_GetDescent(FPDF_FONT font, float font_size, float* descent); // Experimental API. // Get the width of a glyph in a font. // // font - the handle to the font object. // glyph - the glyph. // font_size - the size of the font. // width - pointer where the glyph width will be stored // // Glyph width is the distance from the end of the prior glyph to the next // glyph. This will be the vertical distance for vertical writing. // // Returns TRUE on success; |width| unmodified on failure. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFFont_GetGlyphWidth(FPDF_FONT font, uint32_t glyph, float font_size, float* width); // Experimental API. // Get the glyphpath describing how to draw a font glyph. // // font - the handle to the font object. // glyph - the glyph being drawn. // font_size - the size of the font. // // Returns the handle to the segment, or NULL on faiure. FPDF_EXPORT FPDF_GLYPHPATH FPDF_CALLCONV FPDFFont_GetGlyphPath(FPDF_FONT font, uint32_t glyph, float font_size); // Experimental API. // Get number of segments inside glyphpath. // // glyphpath - handle to a glyph path. // // Returns the number of objects in |glyphpath| or -1 on failure. FPDF_EXPORT int FPDF_CALLCONV FPDFGlyphPath_CountGlyphSegments(FPDF_GLYPHPATH glyphpath); // Experimental API. // Get segment in glyphpath at index. // // glyphpath - handle to a glyph path. // index - the index of a segment. // // Returns the handle to the segment, or NULL on faiure. FPDF_EXPORT FPDF_PATHSEGMENT FPDF_CALLCONV FPDFGlyphPath_GetGlyphPathSegment(FPDF_GLYPHPATH glyphpath, int index); // Get number of page objects inside |form_object|. // // form_object - handle to a form object. // // Returns the number of objects in |form_object| on success, -1 on error. FPDF_EXPORT int FPDF_CALLCONV FPDFFormObj_CountObjects(FPDF_PAGEOBJECT form_object); // Get page object in |form_object| at |index|. // // form_object - handle to a form object. // index - the 0-based index of a page object. // // Returns the handle to the page object, or NULL on error. FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV FPDFFormObj_GetObject(FPDF_PAGEOBJECT form_object, unsigned long index); // Experimental API. // // Remove |page_object| from |form_object|. // // form_object - handle to a form object. // page_object - handle to a page object to be removed from the form. // // Returns TRUE on success. // // Ownership of the removed |page_object| is transferred to the caller. // Call FPDFPageObj_Destroy() on the removed page_object to free it. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFFormObj_RemoveObject(FPDF_PAGEOBJECT form_object, FPDF_PAGEOBJECT page_object); #ifdef __cplusplus } // extern "C" #endif // __cplusplus #endif // PUBLIC_FPDF_EDIT_H_ ================================================ FILE: external/pdfium/macos-x64/include/fpdf_ext.h ================================================ // Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #ifndef PUBLIC_FPDF_EXT_H_ #define PUBLIC_FPDF_EXT_H_ #include // NOLINTNEXTLINE(build/include) #include "fpdfview.h" #ifdef __cplusplus extern "C" { #endif // __cplusplus // Unsupported XFA form. #define FPDF_UNSP_DOC_XFAFORM 1 // Unsupported portable collection. #define FPDF_UNSP_DOC_PORTABLECOLLECTION 2 // Unsupported attachment. #define FPDF_UNSP_DOC_ATTACHMENT 3 // Unsupported security. #define FPDF_UNSP_DOC_SECURITY 4 // Unsupported shared review. #define FPDF_UNSP_DOC_SHAREDREVIEW 5 // Unsupported shared form, acrobat. #define FPDF_UNSP_DOC_SHAREDFORM_ACROBAT 6 // Unsupported shared form, filesystem. #define FPDF_UNSP_DOC_SHAREDFORM_FILESYSTEM 7 // Unsupported shared form, email. #define FPDF_UNSP_DOC_SHAREDFORM_EMAIL 8 // Unsupported 3D annotation. #define FPDF_UNSP_ANNOT_3DANNOT 11 // Unsupported movie annotation. #define FPDF_UNSP_ANNOT_MOVIE 12 // Unsupported sound annotation. #define FPDF_UNSP_ANNOT_SOUND 13 // Unsupported screen media annotation. #define FPDF_UNSP_ANNOT_SCREEN_MEDIA 14 // Unsupported screen rich media annotation. #define FPDF_UNSP_ANNOT_SCREEN_RICHMEDIA 15 // Unsupported attachment annotation. #define FPDF_UNSP_ANNOT_ATTACHMENT 16 // Unsupported signature annotation. #define FPDF_UNSP_ANNOT_SIG 17 // Interface for unsupported feature notifications. typedef struct _UNSUPPORT_INFO { // Version number of the interface. Must be 1. int version; // Unsupported object notification function. // Interface Version: 1 // Implementation Required: Yes // // pThis - pointer to the interface structure. // nType - the type of unsupported object. One of the |FPDF_UNSP_*| entries. void (*FSDK_UnSupport_Handler)(struct _UNSUPPORT_INFO* pThis, int nType); } UNSUPPORT_INFO; // Setup an unsupported object handler. // // unsp_info - Pointer to an UNSUPPORT_INFO structure. // // Returns TRUE on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FSDK_SetUnSpObjProcessHandler(UNSUPPORT_INFO* unsp_info); // Set replacement function for calls to time(). // // This API is intended to be used only for testing, thus may cause PDFium to // behave poorly in production environments. // // func - Function pointer to alternate implementation of time(), or // NULL to restore to actual time() call itself. FPDF_EXPORT void FPDF_CALLCONV FSDK_SetTimeFunction(time_t (*func)()); // Set replacement function for calls to localtime(). // // This API is intended to be used only for testing, thus may cause PDFium to // behave poorly in production environments. // // func - Function pointer to alternate implementation of localtime(), or // NULL to restore to actual localtime() call itself. FPDF_EXPORT void FPDF_CALLCONV FSDK_SetLocaltimeFunction(struct tm* (*func)(const time_t*)); // Unknown page mode. #define PAGEMODE_UNKNOWN -1 // Document outline, and thumbnails hidden. #define PAGEMODE_USENONE 0 // Document outline visible. #define PAGEMODE_USEOUTLINES 1 // Thumbnail images visible. #define PAGEMODE_USETHUMBS 2 // Full-screen mode, no menu bar, window controls, or other decorations visible. #define PAGEMODE_FULLSCREEN 3 // Optional content group panel visible. #define PAGEMODE_USEOC 4 // Attachments panel visible. #define PAGEMODE_USEATTACHMENTS 5 // Get the document's PageMode. // // doc - Handle to document. // // Returns one of the |PAGEMODE_*| flags defined above. // // The page mode defines how the document should be initially displayed. FPDF_EXPORT int FPDF_CALLCONV FPDFDoc_GetPageMode(FPDF_DOCUMENT document); #ifdef __cplusplus } // extern "C" #endif // __cplusplus #endif // PUBLIC_FPDF_EXT_H_ ================================================ FILE: external/pdfium/macos-x64/include/fpdf_flatten.h ================================================ // Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #ifndef PUBLIC_FPDF_FLATTEN_H_ #define PUBLIC_FPDF_FLATTEN_H_ // NOLINTNEXTLINE(build/include) #include "fpdfview.h" // Flatten operation failed. #define FLATTEN_FAIL 0 // Flatten operation succeed. #define FLATTEN_SUCCESS 1 // Nothing to be flattened. #define FLATTEN_NOTHINGTODO 2 // Flatten for normal display. #define FLAT_NORMALDISPLAY 0 // Flatten for print. #define FLAT_PRINT 1 #ifdef __cplusplus extern "C" { #endif // __cplusplus // Flatten annotations and form fields into the page contents. // // page - handle to the page. // nFlag - One of the |FLAT_*| values denoting the page usage. // // Returns one of the |FLATTEN_*| values. // // Currently, all failures return |FLATTEN_FAIL| with no indication of the // cause. FPDF_EXPORT int FPDF_CALLCONV FPDFPage_Flatten(FPDF_PAGE page, int nFlag); #ifdef __cplusplus } // extern "C" #endif // __cplusplus #endif // PUBLIC_FPDF_FLATTEN_H_ ================================================ FILE: external/pdfium/macos-x64/include/fpdf_formfill.h ================================================ // Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #ifndef PUBLIC_FPDF_FORMFILL_H_ #define PUBLIC_FPDF_FORMFILL_H_ // clang-format off // NOLINTNEXTLINE(build/include_directory) #include "fpdfview.h" // These values are return values for a public API, so should not be changed // other than the count when adding new values. #define FORMTYPE_NONE 0 // Document contains no forms #define FORMTYPE_ACRO_FORM 1 // Forms are specified using AcroForm spec #define FORMTYPE_XFA_FULL 2 // Forms are specified using entire XFA spec #define FORMTYPE_XFA_FOREGROUND 3 // Forms are specified using the XFAF subset // of XFA spec #define FORMTYPE_COUNT 4 // The number of form types #define JSPLATFORM_ALERT_BUTTON_OK 0 // OK button #define JSPLATFORM_ALERT_BUTTON_OKCANCEL 1 // OK & Cancel buttons #define JSPLATFORM_ALERT_BUTTON_YESNO 2 // Yes & No buttons #define JSPLATFORM_ALERT_BUTTON_YESNOCANCEL 3 // Yes, No & Cancel buttons #define JSPLATFORM_ALERT_BUTTON_DEFAULT JSPLATFORM_ALERT_BUTTON_OK #define JSPLATFORM_ALERT_ICON_ERROR 0 // Error #define JSPLATFORM_ALERT_ICON_WARNING 1 // Warning #define JSPLATFORM_ALERT_ICON_QUESTION 2 // Question #define JSPLATFORM_ALERT_ICON_STATUS 3 // Status #define JSPLATFORM_ALERT_ICON_ASTERISK 4 // Asterisk #define JSPLATFORM_ALERT_ICON_DEFAULT JSPLATFORM_ALERT_ICON_ERROR #define JSPLATFORM_ALERT_RETURN_OK 1 // OK #define JSPLATFORM_ALERT_RETURN_CANCEL 2 // Cancel #define JSPLATFORM_ALERT_RETURN_NO 3 // No #define JSPLATFORM_ALERT_RETURN_YES 4 // Yes #define JSPLATFORM_BEEP_ERROR 0 // Error #define JSPLATFORM_BEEP_WARNING 1 // Warning #define JSPLATFORM_BEEP_QUESTION 2 // Question #define JSPLATFORM_BEEP_STATUS 3 // Status #define JSPLATFORM_BEEP_DEFAULT 4 // Default // Exported Functions #ifdef __cplusplus extern "C" { #endif typedef struct _IPDF_JsPlatform { // Version number of the interface. Currently must be 2. int version; // Version 1. // Method: app_alert // Pop up a dialog to show warning or hint. // Interface Version: // 1 // Implementation Required: // yes // Parameters: // pThis - Pointer to the interface structure itself. // Msg - A string containing the message to be displayed. // Title - The title of the dialog. // Type - The type of button group, one of the // JSPLATFORM_ALERT_BUTTON_* values above. // nIcon - The type of the icon, one of the // JSPLATFORM_ALERT_ICON_* above. // Return Value: // Option selected by user in dialogue, one of the // JSPLATFORM_ALERT_RETURN_* values above. int (*app_alert)(struct _IPDF_JsPlatform* pThis, FPDF_WIDESTRING Msg, FPDF_WIDESTRING Title, int Type, int Icon); // Method: app_beep // Causes the system to play a sound. // Interface Version: // 1 // Implementation Required: // yes // Parameters: // pThis - Pointer to the interface structure itself // nType - The sound type, see JSPLATFORM_BEEP_TYPE_* // above. // Return Value: // None void (*app_beep)(struct _IPDF_JsPlatform* pThis, int nType); // Method: app_response // Displays a dialog box containing a question and an entry field for // the user to reply to the question. // Interface Version: // 1 // Implementation Required: // yes // Parameters: // pThis - Pointer to the interface structure itself // Question - The question to be posed to the user. // Title - The title of the dialog box. // Default - A default value for the answer to the question. If // not specified, no default value is presented. // cLabel - A short string to appear in front of and on the // same line as the edit text field. // bPassword - If true, indicates that the user's response should // be shown as asterisks (*) or bullets (?) to mask // the response, which might be sensitive information. // response - A string buffer allocated by PDFium, to receive the // user's response. // length - The length of the buffer in bytes. Currently, it is // always 2048. // Return Value: // Number of bytes the complete user input would actually require, not // including trailing zeros, regardless of the value of the length // parameter or the presence of the response buffer. // Comments: // No matter on what platform, the response buffer should be always // written using UTF-16LE encoding. If a response buffer is // present and the size of the user input exceeds the capacity of the // buffer as specified by the length parameter, only the // first "length" bytes of the user input are to be written to the // buffer. int (*app_response)(struct _IPDF_JsPlatform* pThis, FPDF_WIDESTRING Question, FPDF_WIDESTRING Title, FPDF_WIDESTRING Default, FPDF_WIDESTRING cLabel, FPDF_BOOL bPassword, void* response, int length); // Method: Doc_getFilePath // Get the file path of the current document. // Interface Version: // 1 // Implementation Required: // yes // Parameters: // pThis - Pointer to the interface structure itself // filePath - The string buffer to receive the file path. Can // be NULL. // length - The length of the buffer, number of bytes. Can // be 0. // Return Value: // Number of bytes the filePath consumes, including trailing zeros. // Comments: // The filePath should always be provided in the local encoding. // The return value always indicated number of bytes required for // the buffer, even when there is no buffer specified, or the buffer // size is less than required. In this case, the buffer will not // be modified. int (*Doc_getFilePath)(struct _IPDF_JsPlatform* pThis, void* filePath, int length); // Method: Doc_mail // Mails the data buffer as an attachment to all recipients, with or // without user interaction. // Interface Version: // 1 // Implementation Required: // yes // Parameters: // pThis - Pointer to the interface structure itself // mailData - Pointer to the data buffer to be sent. Can be NULL. // length - The size,in bytes, of the buffer pointed by // mailData parameter. Can be 0. // bUI - If true, the rest of the parameters are used in a // compose-new-message window that is displayed to the // user. If false, the cTo parameter is required and // all others are optional. // To - A semicolon-delimited list of recipients for the // message. // Subject - The subject of the message. The length limit is // 64 KB. // CC - A semicolon-delimited list of CC recipients for // the message. // BCC - A semicolon-delimited list of BCC recipients for // the message. // Msg - The content of the message. The length limit is // 64 KB. // Return Value: // None. // Comments: // If the parameter mailData is NULL or length is 0, the current // document will be mailed as an attachment to all recipients. void (*Doc_mail)(struct _IPDF_JsPlatform* pThis, void* mailData, int length, FPDF_BOOL bUI, FPDF_WIDESTRING To, FPDF_WIDESTRING Subject, FPDF_WIDESTRING CC, FPDF_WIDESTRING BCC, FPDF_WIDESTRING Msg); // Method: Doc_print // Prints all or a specific number of pages of the document. // Interface Version: // 1 // Implementation Required: // yes // Parameters: // pThis - Pointer to the interface structure itself. // bUI - If true, will cause a UI to be presented to the // user to obtain printing information and confirm // the action. // nStart - A 0-based index that defines the start of an // inclusive range of pages. // nEnd - A 0-based index that defines the end of an // inclusive page range. // bSilent - If true, suppresses the cancel dialog box while // the document is printing. The default is false. // bShrinkToFit - If true, the page is shrunk (if necessary) to // fit within the imageable area of the printed page. // bPrintAsImage - If true, print pages as an image. // bReverse - If true, print from nEnd to nStart. // bAnnotations - If true (the default), annotations are // printed. // Return Value: // None. void (*Doc_print)(struct _IPDF_JsPlatform* pThis, FPDF_BOOL bUI, int nStart, int nEnd, FPDF_BOOL bSilent, FPDF_BOOL bShrinkToFit, FPDF_BOOL bPrintAsImage, FPDF_BOOL bReverse, FPDF_BOOL bAnnotations); // Method: Doc_submitForm // Send the form data to a specified URL. // Interface Version: // 1 // Implementation Required: // yes // Parameters: // pThis - Pointer to the interface structure itself // formData - Pointer to the data buffer to be sent. // length - The size,in bytes, of the buffer pointed by // formData parameter. // URL - The URL to send to. // Return Value: // None. void (*Doc_submitForm)(struct _IPDF_JsPlatform* pThis, void* formData, int length, FPDF_WIDESTRING URL); // Method: Doc_gotoPage // Jump to a specified page. // Interface Version: // 1 // Implementation Required: // yes // Parameters: // pThis - Pointer to the interface structure itself // nPageNum - The specified page number, zero for the first page. // Return Value: // None. void (*Doc_gotoPage)(struct _IPDF_JsPlatform* pThis, int nPageNum); // Method: Field_browse // Show a file selection dialog, and return the selected file path. // Interface Version: // 1 // Implementation Required: // yes // Parameters: // pThis - Pointer to the interface structure itself. // filePath - Pointer to the data buffer to receive the file // path. Can be NULL. // length - The length of the buffer, in bytes. Can be 0. // Return Value: // Number of bytes the filePath consumes, including trailing zeros. // Comments: // The filePath should always be provided in local encoding. int (*Field_browse)(struct _IPDF_JsPlatform* pThis, void* filePath, int length); // Pointer for embedder-specific data. Unused by PDFium, and despite // its name, can be any data the embedder desires, though traditionally // a FPDF_FORMFILLINFO interface. void* m_pFormfillinfo; // Version 2. void* m_isolate; // Unused in v3, retain for compatibility. unsigned int m_v8EmbedderSlot; // Unused in v3, retain for compatibility. // Version 3. // Version 3 moves m_Isolate and m_v8EmbedderSlot to FPDF_LIBRARY_CONFIG. } IPDF_JSPLATFORM; // Flags for Cursor type #define FXCT_ARROW 0 #define FXCT_NESW 1 #define FXCT_NWSE 2 #define FXCT_VBEAM 3 #define FXCT_HBEAM 4 #define FXCT_HAND 5 // Function signature for the callback function passed to the FFI_SetTimer // method. // Parameters: // idEvent - Identifier of the timer. // Return value: // None. typedef void (*TimerCallback)(int idEvent); // Declares of a struct type to the local system time. typedef struct _FPDF_SYSTEMTIME { unsigned short wYear; // years since 1900 unsigned short wMonth; // months since January - [0,11] unsigned short wDayOfWeek; // days since Sunday - [0,6] unsigned short wDay; // day of the month - [1,31] unsigned short wHour; // hours since midnight - [0,23] unsigned short wMinute; // minutes after the hour - [0,59] unsigned short wSecond; // seconds after the minute - [0,59] unsigned short wMilliseconds; // milliseconds after the second - [0,999] } FPDF_SYSTEMTIME; #ifdef PDF_ENABLE_XFA // Pageview event flags #define FXFA_PAGEVIEWEVENT_POSTADDED 1 // After a new pageview is added. #define FXFA_PAGEVIEWEVENT_POSTREMOVED 3 // After a pageview is removed. // Definitions for Right Context Menu Features Of XFA Fields #define FXFA_MENU_COPY 1 #define FXFA_MENU_CUT 2 #define FXFA_MENU_SELECTALL 4 #define FXFA_MENU_UNDO 8 #define FXFA_MENU_REDO 16 #define FXFA_MENU_PASTE 32 // Definitions for File Type. #define FXFA_SAVEAS_XML 1 #define FXFA_SAVEAS_XDP 2 #endif // PDF_ENABLE_XFA typedef struct _FPDF_FORMFILLINFO { // Version number of the interface. // Version 1 contains stable interfaces. Version 2 has additional // experimental interfaces. // When PDFium is built without the XFA module, version can be 1 or 2. // With version 1, only stable interfaces are called. With version 2, // additional experimental interfaces are also called. // When PDFium is built with the XFA module, version must be 2. // All the XFA related interfaces are experimental. If PDFium is built with // the XFA module and version 1 then none of the XFA related interfaces // would be called. When PDFium is built with XFA module then the version // must be 2. int version; // Version 1. // Method: Release // Give the implementation a chance to release any resources after the // interface is no longer used. // Interface Version: // 1 // Implementation Required: // No // Comments: // Called by PDFium during the final cleanup process. // Parameters: // pThis - Pointer to the interface structure itself // Return Value: // None void (*Release)(struct _FPDF_FORMFILLINFO* pThis); // Method: FFI_Invalidate // Invalidate the client area within the specified rectangle. // Interface Version: // 1 // Implementation Required: // yes // Parameters: // pThis - Pointer to the interface structure itself. // page - Handle to the page. Returned by FPDF_LoadPage(). // left - Left position of the client area in PDF page // coordinates. // top - Top position of the client area in PDF page // coordinates. // right - Right position of the client area in PDF page // coordinates. // bottom - Bottom position of the client area in PDF page // coordinates. // Return Value: // None. // Comments: // All positions are measured in PDF "user space". // Implementation should call FPDF_RenderPageBitmap() for repainting // the specified page area. void (*FFI_Invalidate)(struct _FPDF_FORMFILLINFO* pThis, FPDF_PAGE page, double left, double top, double right, double bottom); // Method: FFI_OutputSelectedRect // When the user selects text in form fields with the mouse, this // callback function will be invoked with the selected areas. // Interface Version: // 1 // Implementation Required: // No // Parameters: // pThis - Pointer to the interface structure itself. // page - Handle to the page. Returned by FPDF_LoadPage()/ // left - Left position of the client area in PDF page // coordinates. // top - Top position of the client area in PDF page // coordinates. // right - Right position of the client area in PDF page // coordinates. // bottom - Bottom position of the client area in PDF page // coordinates. // Return Value: // None. // Comments: // This callback function is useful for implementing special text // selection effects. An implementation should first record the // returned rectangles, then draw them one by one during the next // painting period. Lastly, it should remove all the recorded // rectangles when finished painting. void (*FFI_OutputSelectedRect)(struct _FPDF_FORMFILLINFO* pThis, FPDF_PAGE page, double left, double top, double right, double bottom); // Method: FFI_SetCursor // Set the Cursor shape. // Interface Version: // 1 // Implementation Required: // yes // Parameters: // pThis - Pointer to the interface structure itself. // nCursorType - Cursor type, see Flags for Cursor type for details. // Return value: // None. void (*FFI_SetCursor)(struct _FPDF_FORMFILLINFO* pThis, int nCursorType); // Method: FFI_SetTimer // This method installs a system timer. An interval value is specified, // and every time that interval elapses, the system must call into the // callback function with the timer ID as returned by this function. // Interface Version: // 1 // Implementation Required: // yes // Parameters: // pThis - Pointer to the interface structure itself. // uElapse - Specifies the time-out value, in milliseconds. // lpTimerFunc - A pointer to the callback function-TimerCallback. // Return value: // The timer identifier of the new timer if the function is successful. // An application passes this value to the FFI_KillTimer method to kill // the timer. Nonzero if it is successful; otherwise, it is zero. int (*FFI_SetTimer)(struct _FPDF_FORMFILLINFO* pThis, int uElapse, TimerCallback lpTimerFunc); // Method: FFI_KillTimer // This method uninstalls a system timer, as set by an earlier call to // FFI_SetTimer. // Interface Version: // 1 // Implementation Required: // yes // Parameters: // pThis - Pointer to the interface structure itself. // nTimerID - The timer ID returned by FFI_SetTimer function. // Return value: // None. void (*FFI_KillTimer)(struct _FPDF_FORMFILLINFO* pThis, int nTimerID); // Method: FFI_GetLocalTime // This method receives the current local time on the system. // Interface Version: // 1 // Implementation Required: // yes // Parameters: // pThis - Pointer to the interface structure itself. // Return value: // The local time. See FPDF_SYSTEMTIME above for details. // Note: Unused. FPDF_SYSTEMTIME (*FFI_GetLocalTime)(struct _FPDF_FORMFILLINFO* pThis); // Method: FFI_OnChange // This method will be invoked to notify the implementation when the // value of any FormField on the document had been changed. // Interface Version: // 1 // Implementation Required: // no // Parameters: // pThis - Pointer to the interface structure itself. // Return value: // None. void (*FFI_OnChange)(struct _FPDF_FORMFILLINFO* pThis); // Method: FFI_GetPage // This method receives the page handle associated with a specified // page index. // Interface Version: // 1 // Implementation Required: // yes // Parameters: // pThis - Pointer to the interface structure itself. // document - Handle to document. Returned by FPDF_LoadDocument(). // nPageIndex - Index number of the page. 0 for the first page. // Return value: // Handle to the page, as previously returned to the implementation by // FPDF_LoadPage(). // Comments: // The implementation is expected to keep track of the page handles it // receives from PDFium, and their mappings to page numbers. In some // cases, the document-level JavaScript action may refer to a page // which hadn't been loaded yet. To successfully run the Javascript // action, the implementation needs to load the page. FPDF_PAGE (*FFI_GetPage)(struct _FPDF_FORMFILLINFO* pThis, FPDF_DOCUMENT document, int nPageIndex); // Method: FFI_GetCurrentPage // This method receives the handle to the current page. // Interface Version: // 1 // Implementation Required: // Yes when V8 support is present, otherwise unused. // Parameters: // pThis - Pointer to the interface structure itself. // document - Handle to document. Returned by FPDF_LoadDocument(). // Return value: // Handle to the page. Returned by FPDF_LoadPage(). // Comments: // PDFium doesn't keep keep track of the "current page" (e.g. the one // that is most visible on screen), so it must ask the embedder for // this information. FPDF_PAGE (*FFI_GetCurrentPage)(struct _FPDF_FORMFILLINFO* pThis, FPDF_DOCUMENT document); // Method: FFI_GetRotation // This method receives currently rotation of the page view. // Interface Version: // 1 // Implementation Required: // yes // Parameters: // pThis - Pointer to the interface structure itself. // page - Handle to page, as returned by FPDF_LoadPage(). // Return value: // A number to indicate the page rotation in 90 degree increments // in a clockwise direction: // 0 - 0 degrees // 1 - 90 degrees // 2 - 180 degrees // 3 - 270 degrees // Note: Unused. int (*FFI_GetRotation)(struct _FPDF_FORMFILLINFO* pThis, FPDF_PAGE page); // Method: FFI_ExecuteNamedAction // This method will execute a named action. // Interface Version: // 1 // Implementation Required: // yes // Parameters: // pThis - Pointer to the interface structure itself. // namedAction - A byte string which indicates the named action, // terminated by 0. // Return value: // None. // Comments: // See ISO 32000-1:2008, section 12.6.4.11 for descriptions of the // standard named actions, but note that a document may supply any // name of its choosing. void (*FFI_ExecuteNamedAction)(struct _FPDF_FORMFILLINFO* pThis, FPDF_BYTESTRING namedAction); // Method: FFI_SetTextFieldFocus // Called when a text field is getting or losing focus. // Interface Version: // 1 // Implementation Required: // no // Parameters: // pThis - Pointer to the interface structure itself. // value - The string value of the form field, in UTF-16LE // format. // valueLen - The length of the string value. This is the // number of characters, not bytes. // is_focus - True if the form field is getting focus, false // if the form field is losing focus. // Return value: // None. // Comments: // Only supports text fields and combobox fields. void (*FFI_SetTextFieldFocus)(struct _FPDF_FORMFILLINFO* pThis, FPDF_WIDESTRING value, FPDF_DWORD valueLen, FPDF_BOOL is_focus); // Method: FFI_DoURIAction // Ask the implementation to navigate to a uniform resource identifier. // Interface Version: // 1 // Implementation Required: // No // Parameters: // pThis - Pointer to the interface structure itself. // bsURI - A byte string which indicates the uniform // resource identifier, terminated by 0. // Return value: // None. // Comments: // If the embedder is version 2 or higher and have implementation for // FFI_DoURIActionWithKeyboardModifier, then // FFI_DoURIActionWithKeyboardModifier takes precedence over // FFI_DoURIAction. // See the URI actions description of <> // for more details. void (*FFI_DoURIAction)(struct _FPDF_FORMFILLINFO* pThis, FPDF_BYTESTRING bsURI); // Method: FFI_DoGoToAction // This action changes the view to a specified destination. // Interface Version: // 1 // Implementation Required: // No // Parameters: // pThis - Pointer to the interface structure itself. // nPageIndex - The index of the PDF page. // zoomMode - The zoom mode for viewing page. See below. // fPosArray - The float array which carries the position info. // sizeofArray - The size of float array. // PDFZoom values: // - XYZ = 1 // - FITPAGE = 2 // - FITHORZ = 3 // - FITVERT = 4 // - FITRECT = 5 // - FITBBOX = 6 // - FITBHORZ = 7 // - FITBVERT = 8 // Return value: // None. // Comments: // See the Destinations description of <> // in 8.2.1 for more details. void (*FFI_DoGoToAction)(struct _FPDF_FORMFILLINFO* pThis, int nPageIndex, int zoomMode, float* fPosArray, int sizeofArray); // Pointer to IPDF_JSPLATFORM interface. // Unused if PDFium is built without V8 support. Otherwise, if NULL, then // JavaScript will be prevented from executing while rendering the document. IPDF_JSPLATFORM* m_pJsPlatform; // Version 2 - Experimental. // Whether the XFA module is disabled when built with the XFA module. // Interface Version: // Ignored if |version| < 2. FPDF_BOOL xfa_disabled; // Method: FFI_DisplayCaret // This method will show the caret at specified position. // Interface Version: // Ignored if |version| < 2. // Implementation Required: // Required for XFA, otherwise set to NULL. // Parameters: // pThis - Pointer to the interface structure itself. // page - Handle to page. Returned by FPDF_LoadPage(). // left - Left position of the client area in PDF page // coordinates. // top - Top position of the client area in PDF page // coordinates. // right - Right position of the client area in PDF page // coordinates. // bottom - Bottom position of the client area in PDF page // coordinates. // Return value: // None. void (*FFI_DisplayCaret)(struct _FPDF_FORMFILLINFO* pThis, FPDF_PAGE page, FPDF_BOOL bVisible, double left, double top, double right, double bottom); // Method: FFI_GetCurrentPageIndex // This method will get the current page index. // Interface Version: // Ignored if |version| < 2. // Implementation Required: // Required for XFA, otherwise set to NULL. // Parameters: // pThis - Pointer to the interface structure itself. // document - Handle to document from FPDF_LoadDocument(). // Return value: // The index of current page. int (*FFI_GetCurrentPageIndex)(struct _FPDF_FORMFILLINFO* pThis, FPDF_DOCUMENT document); // Method: FFI_SetCurrentPage // This method will set the current page. // Interface Version: // Ignored if |version| < 2. // Implementation Required: // Required for XFA, otherwise set to NULL. // Parameters: // pThis - Pointer to the interface structure itself. // document - Handle to document from FPDF_LoadDocument(). // iCurPage - The index of the PDF page. // Return value: // None. void (*FFI_SetCurrentPage)(struct _FPDF_FORMFILLINFO* pThis, FPDF_DOCUMENT document, int iCurPage); // Method: FFI_GotoURL // This method will navigate to the specified URL. // Interface Version: // Ignored if |version| < 2. // Implementation Required: // Required for XFA, otherwise set to NULL. // Parameters: // pThis - Pointer to the interface structure itself. // document - Handle to document from FPDF_LoadDocument(). // wsURL - The string value of the URL, in UTF-16LE format. // Return value: // None. void (*FFI_GotoURL)(struct _FPDF_FORMFILLINFO* pThis, FPDF_DOCUMENT document, FPDF_WIDESTRING wsURL); // Method: FFI_GetPageViewRect // This method will get the current page view rectangle. // Interface Version: // Ignored if |version| < 2. // Implementation Required: // Required for XFA, otherwise set to NULL. // Parameters: // pThis - Pointer to the interface structure itself. // page - Handle to page. Returned by FPDF_LoadPage(). // left - The pointer to receive left position of the page // view area in PDF page coordinates. // top - The pointer to receive top position of the page // view area in PDF page coordinates. // right - The pointer to receive right position of the // page view area in PDF page coordinates. // bottom - The pointer to receive bottom position of the // page view area in PDF page coordinates. // Return value: // None. void (*FFI_GetPageViewRect)(struct _FPDF_FORMFILLINFO* pThis, FPDF_PAGE page, double* left, double* top, double* right, double* bottom); // Method: FFI_PageEvent // This method fires when pages have been added to or deleted from // the XFA document. // Interface Version: // Ignored if |version| < 2. // Implementation Required: // Required for XFA, otherwise set to NULL. // Parameters: // pThis - Pointer to the interface structure itself. // page_count - The number of pages to be added or deleted. // event_type - See FXFA_PAGEVIEWEVENT_* above. // Return value: // None. // Comments: // The pages to be added or deleted always start from the last page // of document. This means that if parameter page_count is 2 and // event type is FXFA_PAGEVIEWEVENT_POSTADDED, 2 new pages have been // appended to the tail of document; If page_count is 2 and // event type is FXFA_PAGEVIEWEVENT_POSTREMOVED, the last 2 pages // have been deleted. void (*FFI_PageEvent)(struct _FPDF_FORMFILLINFO* pThis, int page_count, FPDF_DWORD event_type); // Method: FFI_PopupMenu // This method will track the right context menu for XFA fields. // Interface Version: // Ignored if |version| < 2. // Implementation Required: // Required for XFA, otherwise set to NULL. // Parameters: // pThis - Pointer to the interface structure itself. // page - Handle to page. Returned by FPDF_LoadPage(). // hWidget - Always null, exists for compatibility. // menuFlag - The menu flags. Please refer to macro definition // of FXFA_MENU_XXX and this can be one or a // combination of these macros. // x - X position of the client area in PDF page // coordinates. // y - Y position of the client area in PDF page // coordinates. // Return value: // TRUE indicates success; otherwise false. FPDF_BOOL (*FFI_PopupMenu)(struct _FPDF_FORMFILLINFO* pThis, FPDF_PAGE page, FPDF_WIDGET hWidget, int menuFlag, float x, float y); // Method: FFI_OpenFile // This method will open the specified file with the specified mode. // Interface Version: // Ignored if |version| < 2. // Implementation Required: // Required for XFA, otherwise set to NULL. // Parameters: // pThis - Pointer to the interface structure itself. // fileFlag - The file flag. Please refer to macro definition // of FXFA_SAVEAS_XXX and use one of these macros. // wsURL - The string value of the file URL, in UTF-16LE // format. // mode - The mode for open file, e.g. "rb" or "wb". // Return value: // The handle to FPDF_FILEHANDLER. FPDF_FILEHANDLER* (*FFI_OpenFile)(struct _FPDF_FORMFILLINFO* pThis, int fileFlag, FPDF_WIDESTRING wsURL, const char* mode); // Method: FFI_EmailTo // This method will email the specified file stream to the specified // contact. // Interface Version: // Ignored if |version| < 2. // Implementation Required: // Required for XFA, otherwise set to NULL. // Parameters: // pThis - Pointer to the interface structure itself. // pFileHandler - Handle to the FPDF_FILEHANDLER. // pTo - A semicolon-delimited list of recipients for the // message,in UTF-16LE format. // pSubject - The subject of the message,in UTF-16LE format. // pCC - A semicolon-delimited list of CC recipients for // the message,in UTF-16LE format. // pBcc - A semicolon-delimited list of BCC recipients for // the message,in UTF-16LE format. // pMsg - Pointer to the data buffer to be sent.Can be // NULL,in UTF-16LE format. // Return value: // None. void (*FFI_EmailTo)(struct _FPDF_FORMFILLINFO* pThis, FPDF_FILEHANDLER* fileHandler, FPDF_WIDESTRING pTo, FPDF_WIDESTRING pSubject, FPDF_WIDESTRING pCC, FPDF_WIDESTRING pBcc, FPDF_WIDESTRING pMsg); // Method: FFI_UploadTo // This method will upload the specified file stream to the // specified URL. // Interface Version: // Ignored if |version| < 2. // Implementation Required: // Required for XFA, otherwise set to NULL. // Parameters: // pThis - Pointer to the interface structure itself. // pFileHandler - Handle to the FPDF_FILEHANDLER. // fileFlag - The file flag. Please refer to macro definition // of FXFA_SAVEAS_XXX and use one of these macros. // uploadTo - Pointer to the URL path, in UTF-16LE format. // Return value: // None. void (*FFI_UploadTo)(struct _FPDF_FORMFILLINFO* pThis, FPDF_FILEHANDLER* fileHandler, int fileFlag, FPDF_WIDESTRING uploadTo); // Method: FFI_GetPlatform // This method will get the current platform. // Interface Version: // Ignored if |version| < 2. // Implementation Required: // Required for XFA, otherwise set to NULL. // Parameters: // pThis - Pointer to the interface structure itself. // platform - Pointer to the data buffer to receive the // platform,in UTF-16LE format. Can be NULL. // length - The length of the buffer in bytes. Can be // 0 to query the required size. // Return value: // The length of the buffer, number of bytes. int (*FFI_GetPlatform)(struct _FPDF_FORMFILLINFO* pThis, void* platform, int length); // Method: FFI_GetLanguage // This method will get the current language. // Interface Version: // Ignored if |version| < 2. // Implementation Required: // Required for XFA, otherwise set to NULL. // Parameters: // pThis - Pointer to the interface structure itself. // language - Pointer to the data buffer to receive the // current language. Can be NULL. // length - The length of the buffer in bytes. Can be // 0 to query the required size. // Return value: // The length of the buffer, number of bytes. int (*FFI_GetLanguage)(struct _FPDF_FORMFILLINFO* pThis, void* language, int length); // Method: FFI_DownloadFromURL // This method will download the specified file from the URL. // Interface Version: // Ignored if |version| < 2. // Implementation Required: // Required for XFA, otherwise set to NULL. // Parameters: // pThis - Pointer to the interface structure itself. // URL - The string value of the file URL, in UTF-16LE // format. // Return value: // The handle to FPDF_FILEHANDLER. FPDF_FILEHANDLER* (*FFI_DownloadFromURL)(struct _FPDF_FORMFILLINFO* pThis, FPDF_WIDESTRING URL); // Method: FFI_PostRequestURL // This method will post the request to the server URL. // Interface Version: // Ignored if |version| < 2. // Implementation Required: // Required for XFA, otherwise set to NULL. // Parameters: // pThis - Pointer to the interface structure itself. // wsURL - The string value of the server URL, in UTF-16LE // format. // wsData - The post data,in UTF-16LE format. // wsContentType - The content type of the request data, in // UTF-16LE format. // wsEncode - The encode type, in UTF-16LE format. // wsHeader - The request header,in UTF-16LE format. // response - Pointer to the FPDF_BSTR to receive the response // data from the server, in UTF-16LE format. // Return value: // TRUE indicates success, otherwise FALSE. FPDF_BOOL (*FFI_PostRequestURL)(struct _FPDF_FORMFILLINFO* pThis, FPDF_WIDESTRING wsURL, FPDF_WIDESTRING wsData, FPDF_WIDESTRING wsContentType, FPDF_WIDESTRING wsEncode, FPDF_WIDESTRING wsHeader, FPDF_BSTR* response); // Method: FFI_PutRequestURL // This method will put the request to the server URL. // Interface Version: // Ignored if |version| < 2. // Implementation Required: // Required for XFA, otherwise set to NULL. // Parameters: // pThis - Pointer to the interface structure itself. // wsURL - The string value of the server URL, in UTF-16LE // format. // wsData - The put data, in UTF-16LE format. // wsEncode - The encode type, in UTR-16LE format. // Return value: // TRUE indicates success, otherwise FALSE. FPDF_BOOL (*FFI_PutRequestURL)(struct _FPDF_FORMFILLINFO* pThis, FPDF_WIDESTRING wsURL, FPDF_WIDESTRING wsData, FPDF_WIDESTRING wsEncode); // Method: FFI_OnFocusChange // Called when the focused annotation is updated. // Interface Version: // Ignored if |version| < 2. // Implementation Required: // No // Parameters: // param - Pointer to the interface structure itself. // annot - The focused annotation. // page_index - Index number of the page which contains the // focused annotation. 0 for the first page. // Return value: // None. // Comments: // This callback function is useful for implementing any view based // action such as scrolling the annotation rect into view. The // embedder should not copy and store the annot as its scope is // limited to this call only. void (*FFI_OnFocusChange)(struct _FPDF_FORMFILLINFO* param, FPDF_ANNOTATION annot, int page_index); // Method: FFI_DoURIActionWithKeyboardModifier // Ask the implementation to navigate to a uniform resource identifier // with the specified modifiers. // Interface Version: // Ignored if |version| < 2. // Implementation Required: // No // Parameters: // param - Pointer to the interface structure itself. // uri - A byte string which indicates the uniform // resource identifier, terminated by 0. // modifiers - Keyboard modifier that indicates which of // the virtual keys are down, if any. // Return value: // None. // Comments: // If the embedder who is version 2 and does not implement this API, // then a call will be redirected to FFI_DoURIAction. // See the URI actions description of <> // for more details. void(*FFI_DoURIActionWithKeyboardModifier)(struct _FPDF_FORMFILLINFO* param, FPDF_BYTESTRING uri, int modifiers); } FPDF_FORMFILLINFO; // Function: FPDFDOC_InitFormFillEnvironment // Initialize form fill environment. // Parameters: // document - Handle to document from FPDF_LoadDocument(). // formInfo - Pointer to a FPDF_FORMFILLINFO structure. // Return Value: // Handle to the form fill module, or NULL on failure. // Comments: // This function should be called before any form fill operation. // The FPDF_FORMFILLINFO passed in via |formInfo| must remain valid until // the returned FPDF_FORMHANDLE is closed. FPDF_EXPORT FPDF_FORMHANDLE FPDF_CALLCONV FPDFDOC_InitFormFillEnvironment(FPDF_DOCUMENT document, FPDF_FORMFILLINFO* formInfo); // Function: FPDFDOC_ExitFormFillEnvironment // Take ownership of |hHandle| and exit form fill environment. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // Return Value: // None. // Comments: // This function is a no-op when |hHandle| is null. FPDF_EXPORT void FPDF_CALLCONV FPDFDOC_ExitFormFillEnvironment(FPDF_FORMHANDLE hHandle); // Function: FORM_OnAfterLoadPage // This method is required for implementing all the form related // functions. Should be invoked after user successfully loaded a // PDF page, and FPDFDOC_InitFormFillEnvironment() has been invoked. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // Return Value: // None. FPDF_EXPORT void FPDF_CALLCONV FORM_OnAfterLoadPage(FPDF_PAGE page, FPDF_FORMHANDLE hHandle); // Function: FORM_OnBeforeClosePage // This method is required for implementing all the form related // functions. Should be invoked before user closes the PDF page. // Parameters: // page - Handle to the page, as returned by FPDF_LoadPage(). // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // Return Value: // None. FPDF_EXPORT void FPDF_CALLCONV FORM_OnBeforeClosePage(FPDF_PAGE page, FPDF_FORMHANDLE hHandle); // Function: FORM_DoDocumentJSAction // This method is required for performing document-level JavaScript // actions. It should be invoked after the PDF document has been loaded. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // Return Value: // None. // Comments: // If there is document-level JavaScript action embedded in the // document, this method will execute the JavaScript action. Otherwise, // the method will do nothing. FPDF_EXPORT void FPDF_CALLCONV FORM_DoDocumentJSAction(FPDF_FORMHANDLE hHandle); // Function: FORM_DoDocumentOpenAction // This method is required for performing open-action when the document // is opened. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // Return Value: // None. // Comments: // This method will do nothing if there are no open-actions embedded // in the document. FPDF_EXPORT void FPDF_CALLCONV FORM_DoDocumentOpenAction(FPDF_FORMHANDLE hHandle); // Additional actions type of document: // WC, before closing document, JavaScript action. // WS, before saving document, JavaScript action. // DS, after saving document, JavaScript action. // WP, before printing document, JavaScript action. // DP, after printing document, JavaScript action. #define FPDFDOC_AACTION_WC 0x10 #define FPDFDOC_AACTION_WS 0x11 #define FPDFDOC_AACTION_DS 0x12 #define FPDFDOC_AACTION_WP 0x13 #define FPDFDOC_AACTION_DP 0x14 // Function: FORM_DoDocumentAAction // This method is required for performing the document's // additional-action. // Parameters: // hHandle - Handle to the form fill module. Returned by // FPDFDOC_InitFormFillEnvironment. // aaType - The type of the additional-actions which defined // above. // Return Value: // None. // Comments: // This method will do nothing if there is no document // additional-action corresponding to the specified |aaType|. FPDF_EXPORT void FPDF_CALLCONV FORM_DoDocumentAAction(FPDF_FORMHANDLE hHandle, int aaType); // Additional-action types of page object: // OPEN (/O) -- An action to be performed when the page is opened // CLOSE (/C) -- An action to be performed when the page is closed #define FPDFPAGE_AACTION_OPEN 0 #define FPDFPAGE_AACTION_CLOSE 1 // Function: FORM_DoPageAAction // This method is required for performing the page object's // additional-action when opened or closed. // Parameters: // page - Handle to the page, as returned by FPDF_LoadPage(). // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // aaType - The type of the page object's additional-actions // which defined above. // Return Value: // None. // Comments: // This method will do nothing if no additional-action corresponding // to the specified |aaType| exists. FPDF_EXPORT void FPDF_CALLCONV FORM_DoPageAAction(FPDF_PAGE page, FPDF_FORMHANDLE hHandle, int aaType); // Function: FORM_OnMouseMove // Call this member function when the mouse cursor moves. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page, as returned by FPDF_LoadPage(). // modifier - Indicates whether various virtual keys are down. // page_x - Specifies the x-coordinate of the cursor in PDF user // space. // page_y - Specifies the y-coordinate of the cursor in PDF user // space. // Return Value: // True indicates success; otherwise false. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnMouseMove(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, int modifier, double page_x, double page_y); // Experimental API // Function: FORM_OnMouseWheel // Call this member function when the user scrolls the mouse wheel. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page, as returned by FPDF_LoadPage(). // modifier - Indicates whether various virtual keys are down. // page_coord - Specifies the coordinates of the cursor in PDF user // space. // delta_x - Specifies the amount of wheel movement on the x-axis, // in units of platform-agnostic wheel deltas. Negative // values mean left. // delta_y - Specifies the amount of wheel movement on the y-axis, // in units of platform-agnostic wheel deltas. Negative // values mean down. // Return Value: // True indicates success; otherwise false. // Comments: // For |delta_x| and |delta_y|, the caller must normalize // platform-specific wheel deltas. e.g. On Windows, a delta value of 240 // for a WM_MOUSEWHEEL event normalizes to 2, since Windows defines // WHEEL_DELTA as 120. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnMouseWheel( FPDF_FORMHANDLE hHandle, FPDF_PAGE page, int modifier, const FS_POINTF* page_coord, int delta_x, int delta_y); // Function: FORM_OnFocus // This function focuses the form annotation at a given point. If the // annotation at the point already has focus, nothing happens. If there // is no annotation at the point, removes form focus. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page, as returned by FPDF_LoadPage(). // modifier - Indicates whether various virtual keys are down. // page_x - Specifies the x-coordinate of the cursor in PDF user // space. // page_y - Specifies the y-coordinate of the cursor in PDF user // space. // Return Value: // True if there is an annotation at the given point and it has focus. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnFocus(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, int modifier, double page_x, double page_y); // Function: FORM_OnLButtonDown // Call this member function when the user presses the left // mouse button. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page, as returned by FPDF_LoadPage(). // modifier - Indicates whether various virtual keys are down. // page_x - Specifies the x-coordinate of the cursor in PDF user // space. // page_y - Specifies the y-coordinate of the cursor in PDF user // space. // Return Value: // True indicates success; otherwise false. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnLButtonDown(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, int modifier, double page_x, double page_y); // Function: FORM_OnRButtonDown // Same as above, execpt for the right mouse button. // Comments: // At the present time, has no effect except in XFA builds, but is // included for the sake of symmetry. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnRButtonDown(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, int modifier, double page_x, double page_y); // Function: FORM_OnLButtonUp // Call this member function when the user releases the left // mouse button. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page, as returned by FPDF_LoadPage(). // modifier - Indicates whether various virtual keys are down. // page_x - Specifies the x-coordinate of the cursor in device. // page_y - Specifies the y-coordinate of the cursor in device. // Return Value: // True indicates success; otherwise false. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnLButtonUp(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, int modifier, double page_x, double page_y); // Function: FORM_OnRButtonUp // Same as above, execpt for the right mouse button. // Comments: // At the present time, has no effect except in XFA builds, but is // included for the sake of symmetry. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnRButtonUp(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, int modifier, double page_x, double page_y); // Function: FORM_OnLButtonDoubleClick // Call this member function when the user double clicks the // left mouse button. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page, as returned by FPDF_LoadPage(). // modifier - Indicates whether various virtual keys are down. // page_x - Specifies the x-coordinate of the cursor in PDF user // space. // page_y - Specifies the y-coordinate of the cursor in PDF user // space. // Return Value: // True indicates success; otherwise false. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnLButtonDoubleClick(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, int modifier, double page_x, double page_y); // Function: FORM_OnKeyDown // Call this member function when a nonsystem key is pressed. // Parameters: // hHandle - Handle to the form fill module, aseturned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page, as returned by FPDF_LoadPage(). // nKeyCode - The virtual-key code of the given key (see // fpdf_fwlevent.h for virtual key codes). // modifier - Mask of key flags (see fpdf_fwlevent.h for key // flag values). // Return Value: // True indicates success; otherwise false. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnKeyDown(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, int nKeyCode, int modifier); // Function: FORM_OnKeyUp // Call this member function when a nonsystem key is released. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page, as returned by FPDF_LoadPage(). // nKeyCode - The virtual-key code of the given key (see // fpdf_fwlevent.h for virtual key codes). // modifier - Mask of key flags (see fpdf_fwlevent.h for key // flag values). // Return Value: // True indicates success; otherwise false. // Comments: // Currently unimplemented and always returns false. PDFium reserves this // API and may implement it in the future on an as-needed basis. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnKeyUp(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, int nKeyCode, int modifier); // Function: FORM_OnChar // Call this member function when a keystroke translates to a // nonsystem character. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page, as returned by FPDF_LoadPage(). // nChar - The character code value itself. // modifier - Mask of key flags (see fpdf_fwlevent.h for key // flag values). // Return Value: // True indicates success; otherwise false. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnChar(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, int nChar, int modifier); // Experimental API // Function: FORM_GetFocusedText // Call this function to obtain the text within the current focused // field, if any. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page, as returned by FPDF_LoadPage(). // buffer - Buffer for holding the form text, encoded in // UTF-16LE. If NULL, |buffer| is not modified. // buflen - Length of |buffer| in bytes. If |buflen| is less // than the length of the form text string, |buffer| is // not modified. // Return Value: // Length in bytes for the text in the focused field. FPDF_EXPORT unsigned long FPDF_CALLCONV FORM_GetFocusedText(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, void* buffer, unsigned long buflen); // Function: FORM_GetSelectedText // Call this function to obtain selected text within a form text // field or form combobox text field. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page, as returned by FPDF_LoadPage(). // buffer - Buffer for holding the selected text, encoded in // UTF-16LE. If NULL, |buffer| is not modified. // buflen - Length of |buffer| in bytes. If |buflen| is less // than the length of the selected text string, // |buffer| is not modified. // Return Value: // Length in bytes of selected text in form text field or form combobox // text field. FPDF_EXPORT unsigned long FPDF_CALLCONV FORM_GetSelectedText(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, void* buffer, unsigned long buflen); // Experimental API // Function: FORM_ReplaceAndKeepSelection // Call this function to replace the selected text in a form // text field or user-editable form combobox text field with another // text string (which can be empty or non-empty). If there is no // selected text, this function will append the replacement text after // the current caret position. After the insertion, the inserted text // will be selected. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page, as Returned by FPDF_LoadPage(). // wsText - The text to be inserted, in UTF-16LE format. // Return Value: // None. FPDF_EXPORT void FPDF_CALLCONV FORM_ReplaceAndKeepSelection(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, FPDF_WIDESTRING wsText); // Function: FORM_ReplaceSelection // Call this function to replace the selected text in a form // text field or user-editable form combobox text field with another // text string (which can be empty or non-empty). If there is no // selected text, this function will append the replacement text after // the current caret position. After the insertion, the selection range // will be set to empty. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page, as Returned by FPDF_LoadPage(). // wsText - The text to be inserted, in UTF-16LE format. // Return Value: // None. FPDF_EXPORT void FPDF_CALLCONV FORM_ReplaceSelection(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, FPDF_WIDESTRING wsText); // Experimental API // Function: FORM_SelectAllText // Call this function to select all the text within the currently focused // form text field or form combobox text field. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page, as returned by FPDF_LoadPage(). // Return Value: // Whether the operation succeeded or not. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_SelectAllText(FPDF_FORMHANDLE hHandle, FPDF_PAGE page); // Function: FORM_CanUndo // Find out if it is possible for the current focused widget in a given // form to perform an undo operation. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page, as returned by FPDF_LoadPage(). // Return Value: // True if it is possible to undo. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_CanUndo(FPDF_FORMHANDLE hHandle, FPDF_PAGE page); // Function: FORM_CanRedo // Find out if it is possible for the current focused widget in a given // form to perform a redo operation. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page, as returned by FPDF_LoadPage(). // Return Value: // True if it is possible to redo. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_CanRedo(FPDF_FORMHANDLE hHandle, FPDF_PAGE page); // Function: FORM_Undo // Make the current focused widget perform an undo operation. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page, as returned by FPDF_LoadPage(). // Return Value: // True if the undo operation succeeded. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_Undo(FPDF_FORMHANDLE hHandle, FPDF_PAGE page); // Function: FORM_Redo // Make the current focused widget perform a redo operation. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page, as returned by FPDF_LoadPage(). // Return Value: // True if the redo operation succeeded. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_Redo(FPDF_FORMHANDLE hHandle, FPDF_PAGE page); // Function: FORM_ForceToKillFocus. // Call this member function to force to kill the focus of the form // field which has focus. If it would kill the focus of a form field, // save the value of form field if was changed by theuser. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // Return Value: // True indicates success; otherwise false. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_ForceToKillFocus(FPDF_FORMHANDLE hHandle); // Experimental API. // Function: FORM_GetFocusedAnnot. // Call this member function to get the currently focused annotation. // Parameters: // handle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // page_index - Buffer to hold the index number of the page which // contains the focused annotation. 0 for the first page. // Can't be NULL. // annot - Buffer to hold the focused annotation. Can't be NULL. // Return Value: // On success, return true and write to the out parameters. Otherwise // return false and leave the out parameters unmodified. // Comments: // Not currently supported for XFA forms - will report no focused // annotation. // Must call FPDFPage_CloseAnnot() when the annotation returned in |annot| // by this function is no longer needed. // This will return true and set |page_index| to -1 and |annot| to NULL, // if there is no focused annotation. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_GetFocusedAnnot(FPDF_FORMHANDLE handle, int* page_index, FPDF_ANNOTATION* annot); // Experimental API. // Function: FORM_SetFocusedAnnot. // Call this member function to set the currently focused annotation. // Parameters: // handle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // annot - Handle to an annotation. // Return Value: // True indicates success; otherwise false. // Comments: // |annot| can't be NULL. To kill focus, use FORM_ForceToKillFocus() // instead. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_SetFocusedAnnot(FPDF_FORMHANDLE handle, FPDF_ANNOTATION annot); // Form Field Types // The names of the defines are stable, but the specific values associated with // them are not, so do not hardcode their values. #define FPDF_FORMFIELD_UNKNOWN 0 // Unknown. #define FPDF_FORMFIELD_PUSHBUTTON 1 // push button type. #define FPDF_FORMFIELD_CHECKBOX 2 // check box type. #define FPDF_FORMFIELD_RADIOBUTTON 3 // radio button type. #define FPDF_FORMFIELD_COMBOBOX 4 // combo box type. #define FPDF_FORMFIELD_LISTBOX 5 // list box type. #define FPDF_FORMFIELD_TEXTFIELD 6 // text field type. #define FPDF_FORMFIELD_SIGNATURE 7 // text field type. #ifdef PDF_ENABLE_XFA #define FPDF_FORMFIELD_XFA 8 // Generic XFA type. #define FPDF_FORMFIELD_XFA_CHECKBOX 9 // XFA check box type. #define FPDF_FORMFIELD_XFA_COMBOBOX 10 // XFA combo box type. #define FPDF_FORMFIELD_XFA_IMAGEFIELD 11 // XFA image field type. #define FPDF_FORMFIELD_XFA_LISTBOX 12 // XFA list box type. #define FPDF_FORMFIELD_XFA_PUSHBUTTON 13 // XFA push button type. #define FPDF_FORMFIELD_XFA_SIGNATURE 14 // XFA signture field type. #define FPDF_FORMFIELD_XFA_TEXTFIELD 15 // XFA text field type. #endif // PDF_ENABLE_XFA #ifdef PDF_ENABLE_XFA #define FPDF_FORMFIELD_COUNT 16 #else // PDF_ENABLE_XFA #define FPDF_FORMFIELD_COUNT 8 #endif // PDF_ENABLE_XFA #ifdef PDF_ENABLE_XFA #define IS_XFA_FORMFIELD(type) \ (((type) == FPDF_FORMFIELD_XFA) || \ ((type) == FPDF_FORMFIELD_XFA_CHECKBOX) || \ ((type) == FPDF_FORMFIELD_XFA_COMBOBOX) || \ ((type) == FPDF_FORMFIELD_XFA_IMAGEFIELD) || \ ((type) == FPDF_FORMFIELD_XFA_LISTBOX) || \ ((type) == FPDF_FORMFIELD_XFA_PUSHBUTTON) || \ ((type) == FPDF_FORMFIELD_XFA_SIGNATURE) || \ ((type) == FPDF_FORMFIELD_XFA_TEXTFIELD)) #endif // PDF_ENABLE_XFA // Function: FPDFPage_HasFormFieldAtPoint // Get the form field type by point. // Parameters: // hHandle - Handle to the form fill module. Returned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page. Returned by FPDF_LoadPage(). // page_x - X position in PDF "user space". // page_y - Y position in PDF "user space". // Return Value: // Return the type of the form field; -1 indicates no field. // See field types above. FPDF_EXPORT int FPDF_CALLCONV FPDFPage_HasFormFieldAtPoint(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, double page_x, double page_y); // Function: FPDFPage_FormFieldZOrderAtPoint // Get the form field z-order by point. // Parameters: // hHandle - Handle to the form fill module. Returned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page. Returned by FPDF_LoadPage(). // page_x - X position in PDF "user space". // page_y - Y position in PDF "user space". // Return Value: // Return the z-order of the form field; -1 indicates no field. // Higher numbers are closer to the front. FPDF_EXPORT int FPDF_CALLCONV FPDFPage_FormFieldZOrderAtPoint(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, double page_x, double page_y); // Function: FPDF_SetFormFieldHighlightColor // Set the highlight color of the specified (or all) form fields // in the document. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // doc - Handle to the document, as returned by // FPDF_LoadDocument(). // fieldType - A 32-bit integer indicating the type of a form // field (defined above). // color - The highlight color of the form field. Constructed by // 0xxxrrggbb. // Return Value: // None. // Comments: // When the parameter fieldType is set to FPDF_FORMFIELD_UNKNOWN, the // highlight color will be applied to all the form fields in the // document. // Please refresh the client window to show the highlight immediately // if necessary. FPDF_EXPORT void FPDF_CALLCONV FPDF_SetFormFieldHighlightColor(FPDF_FORMHANDLE hHandle, int fieldType, unsigned long color); // Function: FPDF_SetFormFieldHighlightAlpha // Set the transparency of the form field highlight color in the // document. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // doc - Handle to the document, as returaned by // FPDF_LoadDocument(). // alpha - The transparency of the form field highlight color, // between 0-255. // Return Value: // None. FPDF_EXPORT void FPDF_CALLCONV FPDF_SetFormFieldHighlightAlpha(FPDF_FORMHANDLE hHandle, unsigned char alpha); // Function: FPDF_RemoveFormFieldHighlight // Remove the form field highlight color in the document. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // Return Value: // None. // Comments: // Please refresh the client window to remove the highlight immediately // if necessary. FPDF_EXPORT void FPDF_CALLCONV FPDF_RemoveFormFieldHighlight(FPDF_FORMHANDLE hHandle); // Function: FPDF_FFLDraw // Render FormFields and popup window on a page to a device independent // bitmap. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // bitmap - Handle to the device independent bitmap (as the // output buffer). Bitmap handles can be created by // FPDFBitmap_Create(). // page - Handle to the page, as returned by FPDF_LoadPage(). // start_x - Left pixel position of the display area in the // device coordinates. // start_y - Top pixel position of the display area in the device // coordinates. // size_x - Horizontal size (in pixels) for displaying the page. // size_y - Vertical size (in pixels) for displaying the page. // rotate - Page orientation: 0 (normal), 1 (rotated 90 degrees // clockwise), 2 (rotated 180 degrees), 3 (rotated 90 // degrees counter-clockwise). // flags - 0 for normal display, or combination of flags // defined above. // Return Value: // None. // Comments: // This function is designed to render annotations that are // user-interactive, which are widget annotations (for FormFields) and // popup annotations. // With the FPDF_ANNOT flag, this function will render a popup annotation // when users mouse-hover on a non-widget annotation. Regardless of // FPDF_ANNOT flag, this function will always render widget annotations // for FormFields. // In order to implement the FormFill functions, implementation should // call this function after rendering functions, such as // FPDF_RenderPageBitmap() or FPDF_RenderPageBitmap_Start(), have // finished rendering the page contents. FPDF_EXPORT void FPDF_CALLCONV FPDF_FFLDraw(FPDF_FORMHANDLE hHandle, FPDF_BITMAP bitmap, FPDF_PAGE page, int start_x, int start_y, int size_x, int size_y, int rotate, int flags); #if defined(PDF_USE_SKIA) FPDF_EXPORT void FPDF_CALLCONV FPDF_FFLDrawSkia(FPDF_FORMHANDLE hHandle, FPDF_SKIA_CANVAS canvas, FPDF_PAGE page, int start_x, int start_y, int size_x, int size_y, int rotate, int flags); #endif // Experimental API // Function: FPDF_GetFormType // Returns the type of form contained in the PDF document. // Parameters: // document - Handle to document. // Return Value: // Integer value representing one of the FORMTYPE_ values. // Comments: // If |document| is NULL, then the return value is FORMTYPE_NONE. FPDF_EXPORT int FPDF_CALLCONV FPDF_GetFormType(FPDF_DOCUMENT document); // Experimental API // Function: FORM_SetIndexSelected // Selects/deselects the value at the given |index| of the focused // annotation. // Parameters: // hHandle - Handle to the form fill module. Returned by // FPDFDOC_InitFormFillEnvironment. // page - Handle to the page. Returned by FPDF_LoadPage // index - 0-based index of value to be set as // selected/unselected // selected - true to select, false to deselect // Return Value: // TRUE if the operation succeeded. // FALSE if the operation failed or widget is not a supported type. // Comments: // Intended for use with listbox/combobox widget types. Comboboxes // have at most a single value selected at a time which cannot be // deselected. Deselect on a combobox is a no-op that returns false. // Default implementation is a no-op that will return false for // other types. // Not currently supported for XFA forms - will return false. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_SetIndexSelected(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, int index, FPDF_BOOL selected); // Experimental API // Function: FORM_IsIndexSelected // Returns whether or not the value at |index| of the focused // annotation is currently selected. // Parameters: // hHandle - Handle to the form fill module. Returned by // FPDFDOC_InitFormFillEnvironment. // page - Handle to the page. Returned by FPDF_LoadPage // index - 0-based Index of value to check // Return Value: // TRUE if value at |index| is currently selected. // FALSE if value at |index| is not selected or widget is not a // supported type. // Comments: // Intended for use with listbox/combobox widget types. Default // implementation is a no-op that will return false for other types. // Not currently supported for XFA forms - will return false. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_IsIndexSelected(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, int index); // Function: FPDF_LoadXFA // If the document consists of XFA fields, call this method to // attempt to load XFA fields. // Parameters: // document - Handle to document from FPDF_LoadDocument(). // Return Value: // TRUE upon success, otherwise FALSE. If XFA support is not built // into PDFium, performs no action and always returns FALSE. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_LoadXFA(FPDF_DOCUMENT document); #ifdef __cplusplus } #endif #endif // PUBLIC_FPDF_FORMFILL_H_ ================================================ FILE: external/pdfium/macos-x64/include/fpdf_fwlevent.h ================================================ // Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #ifndef PUBLIC_FPDF_FWLEVENT_H_ #define PUBLIC_FPDF_FWLEVENT_H_ // NOLINTNEXTLINE(build/include) #include "fpdfview.h" #ifdef __cplusplus extern "C" { #endif // __cplusplus // Key flags. typedef enum { FWL_EVENTFLAG_ShiftKey = 1 << 0, FWL_EVENTFLAG_ControlKey = 1 << 1, FWL_EVENTFLAG_AltKey = 1 << 2, FWL_EVENTFLAG_MetaKey = 1 << 3, FWL_EVENTFLAG_KeyPad = 1 << 4, FWL_EVENTFLAG_AutoRepeat = 1 << 5, FWL_EVENTFLAG_LeftButtonDown = 1 << 6, FWL_EVENTFLAG_MiddleButtonDown = 1 << 7, FWL_EVENTFLAG_RightButtonDown = 1 << 8, } FWL_EVENTFLAG; // Virtual keycodes. typedef enum { FWL_VKEY_Back = 0x08, FWL_VKEY_Tab = 0x09, FWL_VKEY_NewLine = 0x0A, FWL_VKEY_Clear = 0x0C, FWL_VKEY_Return = 0x0D, FWL_VKEY_Shift = 0x10, FWL_VKEY_Control = 0x11, FWL_VKEY_Menu = 0x12, FWL_VKEY_Pause = 0x13, FWL_VKEY_Capital = 0x14, FWL_VKEY_Kana = 0x15, FWL_VKEY_Hangul = 0x15, FWL_VKEY_Junja = 0x17, FWL_VKEY_Final = 0x18, FWL_VKEY_Hanja = 0x19, FWL_VKEY_Kanji = 0x19, FWL_VKEY_Escape = 0x1B, FWL_VKEY_Convert = 0x1C, FWL_VKEY_NonConvert = 0x1D, FWL_VKEY_Accept = 0x1E, FWL_VKEY_ModeChange = 0x1F, FWL_VKEY_Space = 0x20, FWL_VKEY_Prior = 0x21, FWL_VKEY_Next = 0x22, FWL_VKEY_End = 0x23, FWL_VKEY_Home = 0x24, FWL_VKEY_Left = 0x25, FWL_VKEY_Up = 0x26, FWL_VKEY_Right = 0x27, FWL_VKEY_Down = 0x28, FWL_VKEY_Select = 0x29, FWL_VKEY_Print = 0x2A, FWL_VKEY_Execute = 0x2B, FWL_VKEY_Snapshot = 0x2C, FWL_VKEY_Insert = 0x2D, FWL_VKEY_Delete = 0x2E, FWL_VKEY_Help = 0x2F, FWL_VKEY_0 = 0x30, FWL_VKEY_1 = 0x31, FWL_VKEY_2 = 0x32, FWL_VKEY_3 = 0x33, FWL_VKEY_4 = 0x34, FWL_VKEY_5 = 0x35, FWL_VKEY_6 = 0x36, FWL_VKEY_7 = 0x37, FWL_VKEY_8 = 0x38, FWL_VKEY_9 = 0x39, FWL_VKEY_A = 0x41, FWL_VKEY_B = 0x42, FWL_VKEY_C = 0x43, FWL_VKEY_D = 0x44, FWL_VKEY_E = 0x45, FWL_VKEY_F = 0x46, FWL_VKEY_G = 0x47, FWL_VKEY_H = 0x48, FWL_VKEY_I = 0x49, FWL_VKEY_J = 0x4A, FWL_VKEY_K = 0x4B, FWL_VKEY_L = 0x4C, FWL_VKEY_M = 0x4D, FWL_VKEY_N = 0x4E, FWL_VKEY_O = 0x4F, FWL_VKEY_P = 0x50, FWL_VKEY_Q = 0x51, FWL_VKEY_R = 0x52, FWL_VKEY_S = 0x53, FWL_VKEY_T = 0x54, FWL_VKEY_U = 0x55, FWL_VKEY_V = 0x56, FWL_VKEY_W = 0x57, FWL_VKEY_X = 0x58, FWL_VKEY_Y = 0x59, FWL_VKEY_Z = 0x5A, FWL_VKEY_LWin = 0x5B, FWL_VKEY_Command = 0x5B, FWL_VKEY_RWin = 0x5C, FWL_VKEY_Apps = 0x5D, FWL_VKEY_Sleep = 0x5F, FWL_VKEY_NumPad0 = 0x60, FWL_VKEY_NumPad1 = 0x61, FWL_VKEY_NumPad2 = 0x62, FWL_VKEY_NumPad3 = 0x63, FWL_VKEY_NumPad4 = 0x64, FWL_VKEY_NumPad5 = 0x65, FWL_VKEY_NumPad6 = 0x66, FWL_VKEY_NumPad7 = 0x67, FWL_VKEY_NumPad8 = 0x68, FWL_VKEY_NumPad9 = 0x69, FWL_VKEY_Multiply = 0x6A, FWL_VKEY_Add = 0x6B, FWL_VKEY_Separator = 0x6C, FWL_VKEY_Subtract = 0x6D, FWL_VKEY_Decimal = 0x6E, FWL_VKEY_Divide = 0x6F, FWL_VKEY_F1 = 0x70, FWL_VKEY_F2 = 0x71, FWL_VKEY_F3 = 0x72, FWL_VKEY_F4 = 0x73, FWL_VKEY_F5 = 0x74, FWL_VKEY_F6 = 0x75, FWL_VKEY_F7 = 0x76, FWL_VKEY_F8 = 0x77, FWL_VKEY_F9 = 0x78, FWL_VKEY_F10 = 0x79, FWL_VKEY_F11 = 0x7A, FWL_VKEY_F12 = 0x7B, FWL_VKEY_F13 = 0x7C, FWL_VKEY_F14 = 0x7D, FWL_VKEY_F15 = 0x7E, FWL_VKEY_F16 = 0x7F, FWL_VKEY_F17 = 0x80, FWL_VKEY_F18 = 0x81, FWL_VKEY_F19 = 0x82, FWL_VKEY_F20 = 0x83, FWL_VKEY_F21 = 0x84, FWL_VKEY_F22 = 0x85, FWL_VKEY_F23 = 0x86, FWL_VKEY_F24 = 0x87, FWL_VKEY_NunLock = 0x90, FWL_VKEY_Scroll = 0x91, FWL_VKEY_LShift = 0xA0, FWL_VKEY_RShift = 0xA1, FWL_VKEY_LControl = 0xA2, FWL_VKEY_RControl = 0xA3, FWL_VKEY_LMenu = 0xA4, FWL_VKEY_RMenu = 0xA5, FWL_VKEY_BROWSER_Back = 0xA6, FWL_VKEY_BROWSER_Forward = 0xA7, FWL_VKEY_BROWSER_Refresh = 0xA8, FWL_VKEY_BROWSER_Stop = 0xA9, FWL_VKEY_BROWSER_Search = 0xAA, FWL_VKEY_BROWSER_Favorites = 0xAB, FWL_VKEY_BROWSER_Home = 0xAC, FWL_VKEY_VOLUME_Mute = 0xAD, FWL_VKEY_VOLUME_Down = 0xAE, FWL_VKEY_VOLUME_Up = 0xAF, FWL_VKEY_MEDIA_NEXT_Track = 0xB0, FWL_VKEY_MEDIA_PREV_Track = 0xB1, FWL_VKEY_MEDIA_Stop = 0xB2, FWL_VKEY_MEDIA_PLAY_Pause = 0xB3, FWL_VKEY_MEDIA_LAUNCH_Mail = 0xB4, FWL_VKEY_MEDIA_LAUNCH_MEDIA_Select = 0xB5, FWL_VKEY_MEDIA_LAUNCH_APP1 = 0xB6, FWL_VKEY_MEDIA_LAUNCH_APP2 = 0xB7, FWL_VKEY_OEM_1 = 0xBA, FWL_VKEY_OEM_Plus = 0xBB, FWL_VKEY_OEM_Comma = 0xBC, FWL_VKEY_OEM_Minus = 0xBD, FWL_VKEY_OEM_Period = 0xBE, FWL_VKEY_OEM_2 = 0xBF, FWL_VKEY_OEM_3 = 0xC0, FWL_VKEY_OEM_4 = 0xDB, FWL_VKEY_OEM_5 = 0xDC, FWL_VKEY_OEM_6 = 0xDD, FWL_VKEY_OEM_7 = 0xDE, FWL_VKEY_OEM_8 = 0xDF, FWL_VKEY_OEM_102 = 0xE2, FWL_VKEY_ProcessKey = 0xE5, FWL_VKEY_Packet = 0xE7, FWL_VKEY_Attn = 0xF6, FWL_VKEY_Crsel = 0xF7, FWL_VKEY_Exsel = 0xF8, FWL_VKEY_Ereof = 0xF9, FWL_VKEY_Play = 0xFA, FWL_VKEY_Zoom = 0xFB, FWL_VKEY_NoName = 0xFC, FWL_VKEY_PA1 = 0xFD, FWL_VKEY_OEM_Clear = 0xFE, FWL_VKEY_Unknown = 0, } FWL_VKEYCODE; #ifdef __cplusplus } // extern "C" #endif // __cplusplus #endif // PUBLIC_FPDF_FWLEVENT_H_ ================================================ FILE: external/pdfium/macos-x64/include/fpdf_javascript.h ================================================ // Copyright 2019 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef PUBLIC_FPDF_JAVASCRIPT_H_ #define PUBLIC_FPDF_JAVASCRIPT_H_ // NOLINTNEXTLINE(build/include) #include "fpdfview.h" #ifdef __cplusplus extern "C" { #endif // __cplusplus // Experimental API. // Get the number of JavaScript actions in |document|. // // document - handle to a document. // // Returns the number of JavaScript actions in |document| or -1 on error. FPDF_EXPORT int FPDF_CALLCONV FPDFDoc_GetJavaScriptActionCount(FPDF_DOCUMENT document); // Experimental API. // Get the JavaScript action at |index| in |document|. // // document - handle to a document. // index - the index of the requested JavaScript action. // // Returns the handle to the JavaScript action, or NULL on failure. // Caller owns the returned handle and must close it with // FPDFDoc_CloseJavaScriptAction(). FPDF_EXPORT FPDF_JAVASCRIPT_ACTION FPDF_CALLCONV FPDFDoc_GetJavaScriptAction(FPDF_DOCUMENT document, int index); // Experimental API. // Close a loaded FPDF_JAVASCRIPT_ACTION object. // javascript - Handle to a JavaScript action. FPDF_EXPORT void FPDF_CALLCONV FPDFDoc_CloseJavaScriptAction(FPDF_JAVASCRIPT_ACTION javascript); // Experimental API. // Get the name from the |javascript| handle. |buffer| is only modified if // |buflen| is longer than the length of the name. On errors, |buffer| is // unmodified and the returned length is 0. // // javascript - handle to an JavaScript action. // buffer - buffer for holding the name, encoded in UTF-16LE. // buflen - length of the buffer in bytes. // // Returns the length of the JavaScript action name in bytes. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFJavaScriptAction_GetName(FPDF_JAVASCRIPT_ACTION javascript, FPDF_WCHAR* buffer, unsigned long buflen); // Experimental API. // Get the script from the |javascript| handle. |buffer| is only modified if // |buflen| is longer than the length of the script. On errors, |buffer| is // unmodified and the returned length is 0. // // javascript - handle to an JavaScript action. // buffer - buffer for holding the name, encoded in UTF-16LE. // buflen - length of the buffer in bytes. // // Returns the length of the JavaScript action name in bytes. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFJavaScriptAction_GetScript(FPDF_JAVASCRIPT_ACTION javascript, FPDF_WCHAR* buffer, unsigned long buflen); #ifdef __cplusplus } // extern "C" #endif // __cplusplus #endif // PUBLIC_FPDF_JAVASCRIPT_H_ ================================================ FILE: external/pdfium/macos-x64/include/fpdf_ppo.h ================================================ // Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #ifndef PUBLIC_FPDF_PPO_H_ #define PUBLIC_FPDF_PPO_H_ // NOLINTNEXTLINE(build/include) #include "fpdfview.h" #ifdef __cplusplus extern "C" { #endif // Experimental API. // Import pages to a FPDF_DOCUMENT. // // dest_doc - The destination document for the pages. // src_doc - The document to be imported. // page_indices - An array of page indices to be imported. The first page is // zero. If |page_indices| is NULL, all pages from |src_doc| // are imported. // length - The length of the |page_indices| array. // index - The page index at which to insert the first imported page // into |dest_doc|. The first page is zero. // // Returns TRUE on success. Returns FALSE if any pages in |page_indices| is // invalid. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_ImportPagesByIndex(FPDF_DOCUMENT dest_doc, FPDF_DOCUMENT src_doc, const int* page_indices, unsigned long length, int index); // Import pages to a FPDF_DOCUMENT. // // dest_doc - The destination document for the pages. // src_doc - The document to be imported. // pagerange - A page range string, Such as "1,3,5-7". The first page is one. // If |pagerange| is NULL, all pages from |src_doc| are imported. // index - The page index at which to insert the first imported page into // |dest_doc|. The first page is zero. // // Returns TRUE on success. Returns FALSE if any pages in |pagerange| is // invalid or if |pagerange| cannot be read. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_ImportPages(FPDF_DOCUMENT dest_doc, FPDF_DOCUMENT src_doc, FPDF_BYTESTRING pagerange, int index); // Experimental API. // Create a new document from |src_doc|. The pages of |src_doc| will be // combined to provide |num_pages_on_x_axis x num_pages_on_y_axis| pages per // |output_doc| page. // // src_doc - The document to be imported. // output_width - The output page width in PDF "user space" units. // output_height - The output page height in PDF "user space" units. // num_pages_on_x_axis - The number of pages on X Axis. // num_pages_on_y_axis - The number of pages on Y Axis. // // Return value: // A handle to the created document, or NULL on failure. // // Comments: // number of pages per page = num_pages_on_x_axis * num_pages_on_y_axis // FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV FPDF_ImportNPagesToOne(FPDF_DOCUMENT src_doc, float output_width, float output_height, size_t num_pages_on_x_axis, size_t num_pages_on_y_axis); // Experimental API. // Create a template to generate form xobjects from |src_doc|'s page at // |src_page_index|, for use in |dest_doc|. // // Returns a handle on success, or NULL on failure. Caller owns the newly // created object. FPDF_EXPORT FPDF_XOBJECT FPDF_CALLCONV FPDF_NewXObjectFromPage(FPDF_DOCUMENT dest_doc, FPDF_DOCUMENT src_doc, int src_page_index); // Experimental API. // Close an FPDF_XOBJECT handle created by FPDF_NewXObjectFromPage(). // FPDF_PAGEOBJECTs created from the FPDF_XOBJECT handle are not affected. FPDF_EXPORT void FPDF_CALLCONV FPDF_CloseXObject(FPDF_XOBJECT xobject); // Experimental API. // Create a new form object from an FPDF_XOBJECT object. // // Returns a new form object on success, or NULL on failure. Caller owns the // newly created object. FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV FPDF_NewFormObjectFromXObject(FPDF_XOBJECT xobject); // Copy the viewer preferences from |src_doc| into |dest_doc|. // // dest_doc - Document to write the viewer preferences into. // src_doc - Document to read the viewer preferences from. // // Returns TRUE on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_CopyViewerPreferences(FPDF_DOCUMENT dest_doc, FPDF_DOCUMENT src_doc); #ifdef __cplusplus } // extern "C" #endif // __cplusplus #endif // PUBLIC_FPDF_PPO_H_ ================================================ FILE: external/pdfium/macos-x64/include/fpdf_progressive.h ================================================ // Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #ifndef PUBLIC_FPDF_PROGRESSIVE_H_ #define PUBLIC_FPDF_PROGRESSIVE_H_ // clang-format off // NOLINTNEXTLINE(build/include) #include "fpdfview.h" // Flags for progressive process status. #define FPDF_RENDER_READY 0 #define FPDF_RENDER_TOBECONTINUED 1 #define FPDF_RENDER_DONE 2 #define FPDF_RENDER_FAILED 3 #ifdef __cplusplus extern "C" { #endif // IFPDF_RENDERINFO interface. typedef struct _IFSDK_PAUSE { // Version number of the interface. Currently must be 1. int version; // Method: NeedToPauseNow // Check if we need to pause a progressive process now. // Interface Version: // 1 // Implementation Required: // yes // Parameters: // pThis - Pointer to the interface structure itself // Return Value: // Non-zero for pause now, 0 for continue. FPDF_BOOL (*NeedToPauseNow)(struct _IFSDK_PAUSE* pThis); // A user defined data pointer, used by user's application. Can be NULL. void* user; } IFSDK_PAUSE; // Experimental API. // Function: FPDF_RenderPageBitmapWithColorScheme_Start // Start to render page contents to a device independent bitmap // progressively with a specified color scheme for the content. // Parameters: // bitmap - Handle to the device independent bitmap (as the // output buffer). Bitmap handle can be created by // FPDFBitmap_Create function. // page - Handle to the page as returned by FPDF_LoadPage // function. // start_x - Left pixel position of the display area in the // bitmap coordinate. // start_y - Top pixel position of the display area in the // bitmap coordinate. // size_x - Horizontal size (in pixels) for displaying the // page. // size_y - Vertical size (in pixels) for displaying the page. // rotate - Page orientation: 0 (normal), 1 (rotated 90 // degrees clockwise), 2 (rotated 180 degrees), // 3 (rotated 90 degrees counter-clockwise). // flags - 0 for normal display, or combination of flags // defined in fpdfview.h. With FPDF_ANNOT flag, it // renders all annotations that does not require // user-interaction, which are all annotations except // widget and popup annotations. // color_scheme - Color scheme to be used in rendering the |page|. // If null, this function will work similar to // FPDF_RenderPageBitmap_Start(). // pause - The IFSDK_PAUSE interface. A callback mechanism // allowing the page rendering process. // Return value: // Rendering Status. See flags for progressive process status for the // details. FPDF_EXPORT int FPDF_CALLCONV FPDF_RenderPageBitmapWithColorScheme_Start(FPDF_BITMAP bitmap, FPDF_PAGE page, int start_x, int start_y, int size_x, int size_y, int rotate, int flags, const FPDF_COLORSCHEME* color_scheme, IFSDK_PAUSE* pause); // Function: FPDF_RenderPageBitmap_Start // Start to render page contents to a device independent bitmap // progressively. // Parameters: // bitmap - Handle to the device independent bitmap (as the // output buffer). Bitmap handle can be created by // FPDFBitmap_Create(). // page - Handle to the page, as returned by FPDF_LoadPage(). // start_x - Left pixel position of the display area in the // bitmap coordinates. // start_y - Top pixel position of the display area in the bitmap // coordinates. // size_x - Horizontal size (in pixels) for displaying the page. // size_y - Vertical size (in pixels) for displaying the page. // rotate - Page orientation: 0 (normal), 1 (rotated 90 degrees // clockwise), 2 (rotated 180 degrees), 3 (rotated 90 // degrees counter-clockwise). // flags - 0 for normal display, or combination of flags // defined in fpdfview.h. With FPDF_ANNOT flag, it // renders all annotations that does not require // user-interaction, which are all annotations except // widget and popup annotations. // pause - The IFSDK_PAUSE interface.A callback mechanism // allowing the page rendering process // Return value: // Rendering Status. See flags for progressive process status for the // details. FPDF_EXPORT int FPDF_CALLCONV FPDF_RenderPageBitmap_Start(FPDF_BITMAP bitmap, FPDF_PAGE page, int start_x, int start_y, int size_x, int size_y, int rotate, int flags, IFSDK_PAUSE* pause); // Function: FPDF_RenderPage_Continue // Continue rendering a PDF page. // Parameters: // page - Handle to the page, as returned by FPDF_LoadPage(). // pause - The IFSDK_PAUSE interface (a callback mechanism // allowing the page rendering process to be paused // before it's finished). This can be NULL if you // don't want to pause. // Return value: // The rendering status. See flags for progressive process status for // the details. FPDF_EXPORT int FPDF_CALLCONV FPDF_RenderPage_Continue(FPDF_PAGE page, IFSDK_PAUSE* pause); // Function: FPDF_RenderPage_Close // Release the resource allocate during page rendering. Need to be // called after finishing rendering or // cancel the rendering. // Parameters: // page - Handle to the page, as returned by FPDF_LoadPage(). // Return value: // None. FPDF_EXPORT void FPDF_CALLCONV FPDF_RenderPage_Close(FPDF_PAGE page); #ifdef __cplusplus } #endif #endif // PUBLIC_FPDF_PROGRESSIVE_H_ ================================================ FILE: external/pdfium/macos-x64/include/fpdf_save.h ================================================ // Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #ifndef PUBLIC_FPDF_SAVE_H_ #define PUBLIC_FPDF_SAVE_H_ // clang-format off // NOLINTNEXTLINE(build/include) #include "fpdfview.h" #ifdef __cplusplus extern "C" { #endif // Structure for custom file write typedef struct FPDF_FILEWRITE_ { // // Version number of the interface. Currently must be 1. // int version; // Method: WriteBlock // Output a block of data in your custom way. // Interface Version: // 1 // Implementation Required: // Yes // Comments: // Called by function FPDF_SaveDocument // Parameters: // self - Pointer to the structure itself // data - Pointer to a buffer to output // size - The size of the buffer. // Return value: // Should be non-zero if successful, zero for error. int (*WriteBlock)(struct FPDF_FILEWRITE_* self, const void* data, unsigned long size); } FPDF_FILEWRITE; // Flags for FPDF_SaveAsCopy(). // FPDF_INCREMENTAL and FPDF_NO_INCREMENTAL cannot be used together. #define FPDF_INCREMENTAL (1 << 0) #define FPDF_NO_INCREMENTAL (1 << 1) // Deprecated. Use FPDF_REMOVE_SECURITY instead. // TODO(crbug.com/42270430): Remove FPDF_REMOVE_SECURITY_DEPRECATED. #define FPDF_REMOVE_SECURITY_DEPRECATED 3 #define FPDF_REMOVE_SECURITY (1 << 2) // Experimental. Subsets any embedded font files for new text objects added to // the document. #define FPDF_SUBSET_NEW_FONTS (1 << 3) // Function: FPDF_SaveAsCopy // Saves the copy of specified document in custom way. // Parameters: // document - Handle to document, as returned by // FPDF_LoadDocument() or FPDF_CreateNewDocument(). // file_write - A pointer to a custom file write structure. // flags - Flags above that affect how the PDF gets saved. // Pass in 0 when there are no flags. // Return value: // TRUE for succeed, FALSE for failed. // FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_SaveAsCopy(FPDF_DOCUMENT document, FPDF_FILEWRITE* file_write, FPDF_DWORD flags); // Function: FPDF_SaveWithVersion // Same as FPDF_SaveAsCopy(), except the file version of the // saved document can be specified by the caller. // Parameters: // document - Handle to document. // file_write - A pointer to a custom file write structure. // flags - The creating flags. // file_version - The PDF file version. File version: 14 for 1.4, // 15 for 1.5, ... // Return value: // TRUE if succeed, FALSE if failed. // FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_SaveWithVersion(FPDF_DOCUMENT document, FPDF_FILEWRITE* file_write, FPDF_DWORD flags, int file_version); #ifdef __cplusplus } #endif #endif // PUBLIC_FPDF_SAVE_H_ ================================================ FILE: external/pdfium/macos-x64/include/fpdf_searchex.h ================================================ // Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #ifndef PUBLIC_FPDF_SEARCHEX_H_ #define PUBLIC_FPDF_SEARCHEX_H_ // NOLINTNEXTLINE(build/include) #include "fpdfview.h" #ifdef __cplusplus extern "C" { #endif // __cplusplus // Get the character index in |text_page| internal character list. // // text_page - a text page information structure. // nTextIndex - index of the text returned from FPDFText_GetText(). // // Returns the index of the character in internal character list. -1 for error. FPDF_EXPORT int FPDF_CALLCONV FPDFText_GetCharIndexFromTextIndex(FPDF_TEXTPAGE text_page, int nTextIndex); // Get the text index in |text_page| internal character list. // // text_page - a text page information structure. // nCharIndex - index of the character in internal character list. // // Returns the index of the text returned from FPDFText_GetText(). -1 for error. FPDF_EXPORT int FPDF_CALLCONV FPDFText_GetTextIndexFromCharIndex(FPDF_TEXTPAGE text_page, int nCharIndex); #ifdef __cplusplus } // extern "C" #endif // __cplusplus #endif // PUBLIC_FPDF_SEARCHEX_H_ ================================================ FILE: external/pdfium/macos-x64/include/fpdf_signature.h ================================================ // Copyright 2020 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef PUBLIC_FPDF_SIGNATURE_H_ #define PUBLIC_FPDF_SIGNATURE_H_ // NOLINTNEXTLINE(build/include) #include "fpdfview.h" #ifdef __cplusplus extern "C" { #endif // __cplusplus // Experimental API. // Function: FPDF_GetSignatureCount // Get total number of signatures in the document. // Parameters: // document - Handle to document. Returned by FPDF_LoadDocument(). // Return value: // Total number of signatures in the document on success, -1 on error. FPDF_EXPORT int FPDF_CALLCONV FPDF_GetSignatureCount(FPDF_DOCUMENT document); // Experimental API. // Function: FPDF_GetSignatureObject // Get the Nth signature of the document. // Parameters: // document - Handle to document. Returned by FPDF_LoadDocument(). // index - Index into the array of signatures of the document. // Return value: // Returns the handle to the signature, or NULL on failure. The caller // does not take ownership of the returned FPDF_SIGNATURE. Instead, it // remains valid until FPDF_CloseDocument() is called for the document. FPDF_EXPORT FPDF_SIGNATURE FPDF_CALLCONV FPDF_GetSignatureObject(FPDF_DOCUMENT document, int index); // Experimental API. // Function: FPDFSignatureObj_GetContents // Get the contents of a signature object. // Parameters: // signature - Handle to the signature object. Returned by // FPDF_GetSignatureObject(). // buffer - The address of a buffer that receives the contents. // length - The size, in bytes, of |buffer|. // Return value: // Returns the number of bytes in the contents on success, 0 on error. // // For public-key signatures, |buffer| is either a DER-encoded PKCS#1 binary or // a DER-encoded PKCS#7 binary. If |length| is less than the returned length, or // |buffer| is NULL, |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFSignatureObj_GetContents(FPDF_SIGNATURE signature, void* buffer, unsigned long length); // Experimental API. // Function: FPDFSignatureObj_GetByteRange // Get the byte range of a signature object. // Parameters: // signature - Handle to the signature object. Returned by // FPDF_GetSignatureObject(). // buffer - The address of a buffer that receives the // byte range. // length - The size, in ints, of |buffer|. // Return value: // Returns the number of ints in the byte range on // success, 0 on error. // // |buffer| is an array of pairs of integers (starting byte offset, // length in bytes) that describes the exact byte range for the digest // calculation. If |length| is less than the returned length, or // |buffer| is NULL, |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFSignatureObj_GetByteRange(FPDF_SIGNATURE signature, int* buffer, unsigned long length); // Experimental API. // Function: FPDFSignatureObj_GetSubFilter // Get the encoding of the value of a signature object. // Parameters: // signature - Handle to the signature object. Returned by // FPDF_GetSignatureObject(). // buffer - The address of a buffer that receives the encoding. // length - The size, in bytes, of |buffer|. // Return value: // Returns the number of bytes in the encoding name (including the // trailing NUL character) on success, 0 on error. // // The |buffer| is always encoded in 7-bit ASCII. If |length| is less than the // returned length, or |buffer| is NULL, |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFSignatureObj_GetSubFilter(FPDF_SIGNATURE signature, char* buffer, unsigned long length); // Experimental API. // Function: FPDFSignatureObj_GetReason // Get the reason (comment) of the signature object. // Parameters: // signature - Handle to the signature object. Returned by // FPDF_GetSignatureObject(). // buffer - The address of a buffer that receives the reason. // length - The size, in bytes, of |buffer|. // Return value: // Returns the number of bytes in the reason on success, 0 on error. // // Regardless of the platform, the |buffer| is always in UTF-16LE encoding. The // string is terminated by a UTF16 NUL character. If |length| is less than the // returned length, or |buffer| is NULL, |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFSignatureObj_GetReason(FPDF_SIGNATURE signature, void* buffer, unsigned long length); // Experimental API. // Function: FPDFSignatureObj_GetTime // Get the time of signing of a signature object. // Parameters: // signature - Handle to the signature object. Returned by // FPDF_GetSignatureObject(). // buffer - The address of a buffer that receives the time. // length - The size, in bytes, of |buffer|. // Return value: // Returns the number of bytes in the encoding name (including the // trailing NUL character) on success, 0 on error. // // The |buffer| is always encoded in 7-bit ASCII. If |length| is less than the // returned length, or |buffer| is NULL, |buffer| will not be modified. // // The format of time is expected to be D:YYYYMMDDHHMMSS+XX'YY', i.e. it's // percision is seconds, with timezone information. This value should be used // only when the time of signing is not available in the (PKCS#7 binary) // signature. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFSignatureObj_GetTime(FPDF_SIGNATURE signature, char* buffer, unsigned long length); // Experimental API. // Function: FPDFSignatureObj_GetDocMDPPermission // Get the DocMDP permission of a signature object. // Parameters: // signature - Handle to the signature object. Returned by // FPDF_GetSignatureObject(). // Return value: // Returns the permission (1, 2 or 3) on success, 0 on error. FPDF_EXPORT unsigned int FPDF_CALLCONV FPDFSignatureObj_GetDocMDPPermission(FPDF_SIGNATURE signature); #ifdef __cplusplus } // extern "C" #endif // __cplusplus #endif // PUBLIC_FPDF_SIGNATURE_H_ ================================================ FILE: external/pdfium/macos-x64/include/fpdf_structtree.h ================================================ // Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #ifndef PUBLIC_FPDF_STRUCTTREE_H_ #define PUBLIC_FPDF_STRUCTTREE_H_ // clang-format off // NOLINTNEXTLINE(build/include) #include "fpdfview.h" #ifdef __cplusplus extern "C" { #endif // Function: FPDF_StructTree_GetForPage // Get the structure tree for a page. // Parameters: // page - Handle to the page, as returned by FPDF_LoadPage(). // Return value: // A handle to the structure tree or NULL on error. The caller owns the // returned handle and must use FPDF_StructTree_Close() to release it. // The handle should be released before |page| gets released. FPDF_EXPORT FPDF_STRUCTTREE FPDF_CALLCONV FPDF_StructTree_GetForPage(FPDF_PAGE page); // Function: FPDF_StructTree_Close // Release a resource allocated by FPDF_StructTree_GetForPage(). // Parameters: // struct_tree - Handle to the structure tree, as returned by // FPDF_StructTree_LoadPage(). // Return value: // None. FPDF_EXPORT void FPDF_CALLCONV FPDF_StructTree_Close(FPDF_STRUCTTREE struct_tree); // Function: FPDF_StructTree_CountChildren // Count the number of children for the structure tree. // Parameters: // struct_tree - Handle to the structure tree, as returned by // FPDF_StructTree_LoadPage(). // Return value: // The number of children, or -1 on error. FPDF_EXPORT int FPDF_CALLCONV FPDF_StructTree_CountChildren(FPDF_STRUCTTREE struct_tree); // Function: FPDF_StructTree_GetChildAtIndex // Get a child in the structure tree. // Parameters: // struct_tree - Handle to the structure tree, as returned by // FPDF_StructTree_LoadPage(). // index - The index for the child, 0-based. // Return value: // The child at the n-th index or NULL on error. The caller does not // own the handle. The handle remains valid as long as |struct_tree| // remains valid. // Comments: // The |index| must be less than the FPDF_StructTree_CountChildren() // return value. FPDF_EXPORT FPDF_STRUCTELEMENT FPDF_CALLCONV FPDF_StructTree_GetChildAtIndex(FPDF_STRUCTTREE struct_tree, int index); // Function: FPDF_StructElement_GetAltText // Get the alt text for a given element. // Parameters: // struct_element - Handle to the struct element. // buffer - A buffer for output the alt text. May be NULL. // buflen - The length of the buffer, in bytes. May be 0. // Return value: // The number of bytes in the alt text, including the terminating NUL // character. The number of bytes is returned regardless of the // |buffer| and |buflen| parameters. // Comments: // Regardless of the platform, the |buffer| is always in UTF-16LE // encoding. The string is terminated by a UTF16 NUL character. If // |buflen| is less than the required length, or |buffer| is NULL, // |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_StructElement_GetAltText(FPDF_STRUCTELEMENT struct_element, void* buffer, unsigned long buflen); // Experimental API. // Function: FPDF_StructElement_GetActualText // Get the actual text for a given element. // Parameters: // struct_element - Handle to the struct element. // buffer - A buffer for output the actual text. May be NULL. // buflen - The length of the buffer, in bytes. May be 0. // Return value: // The number of bytes in the actual text, including the terminating // NUL character. The number of bytes is returned regardless of the // |buffer| and |buflen| parameters. // Comments: // Regardless of the platform, the |buffer| is always in UTF-16LE // encoding. The string is terminated by a UTF16 NUL character. If // |buflen| is less than the required length, or |buffer| is NULL, // |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_StructElement_GetActualText(FPDF_STRUCTELEMENT struct_element, void* buffer, unsigned long buflen); // Experimental API. // Function: FPDF_StructElement_GetExpansion // Get the expansion of an abbreviation or acronym for a given element. // Parameters: // struct_element - Handle to the struct element. // buffer - A buffer for output the expansion text. May be // NULL. // buflen - The length of the buffer, in bytes. May be 0. // Return value: // The number of bytes in the expansion text, including the terminating // NUL character. The number of bytes is returned regardless of the // |buffer| and |buflen| parameters. // Comments: // Regardless of the platform, the |buffer| is always in UTF-16LE // encoding. The string is terminated by a UTF16 NUL character. If // |buflen| is less than the required length, or |buffer| is NULL, // |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_StructElement_GetExpansion(FPDF_STRUCTELEMENT struct_element, void* buffer, unsigned long buflen); // Function: FPDF_StructElement_GetID // Get the ID for a given element. // Parameters: // struct_element - Handle to the struct element. // buffer - A buffer for output the ID string. May be NULL. // buflen - The length of the buffer, in bytes. May be 0. // Return value: // The number of bytes in the ID string, including the terminating NUL // character. The number of bytes is returned regardless of the // |buffer| and |buflen| parameters. // Comments: // Regardless of the platform, the |buffer| is always in UTF-16LE // encoding. The string is terminated by a UTF16 NUL character. If // |buflen| is less than the required length, or |buffer| is NULL, // |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_StructElement_GetID(FPDF_STRUCTELEMENT struct_element, void* buffer, unsigned long buflen); // Experimental API. // Function: FPDF_StructElement_GetLang // Get the case-insensitive IETF BCP 47 language code for an element. // Parameters: // struct_element - Handle to the struct element. // buffer - A buffer for output the lang string. May be NULL. // buflen - The length of the buffer, in bytes. May be 0. // Return value: // The number of bytes in the ID string, including the terminating NUL // character. The number of bytes is returned regardless of the // |buffer| and |buflen| parameters. // Comments: // Regardless of the platform, the |buffer| is always in UTF-16LE // encoding. The string is terminated by a UTF16 NUL character. If // |buflen| is less than the required length, or |buffer| is NULL, // |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_StructElement_GetLang(FPDF_STRUCTELEMENT struct_element, void* buffer, unsigned long buflen); // Experimental API. // Function: FPDF_StructElement_GetStringAttribute // Get a struct element attribute of type "name" or "string". // Parameters: // struct_element - Handle to the struct element. // attr_name - The name of the attribute to retrieve. // buffer - A buffer for output. May be NULL. // buflen - The length of the buffer, in bytes. May be 0. // Return value: // The number of bytes in the attribute value, including the // terminating NUL character. The number of bytes is returned // regardless of the |buffer| and |buflen| parameters. // Comments: // Regardless of the platform, the |buffer| is always in UTF-16LE // encoding. The string is terminated by a UTF16 NUL character. If // |buflen| is less than the required length, or |buffer| is NULL, // |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_StructElement_GetStringAttribute(FPDF_STRUCTELEMENT struct_element, FPDF_BYTESTRING attr_name, void* buffer, unsigned long buflen); // Function: FPDF_StructElement_GetMarkedContentID // Get the marked content ID for a given element. // Parameters: // struct_element - Handle to the struct element. // Return value: // The marked content ID of the element. If no ID exists, returns // -1. // Comments: // FPDF_StructElement_GetMarkedContentIdAtIndex() may be able to // extract more marked content IDs out of |struct_element|. This API // may be deprecated in the future. FPDF_EXPORT int FPDF_CALLCONV FPDF_StructElement_GetMarkedContentID(FPDF_STRUCTELEMENT struct_element); // Function: FPDF_StructElement_GetType // Get the type (/S) for a given element. // Parameters: // struct_element - Handle to the struct element. // buffer - A buffer for output. May be NULL. // buflen - The length of the buffer, in bytes. May be 0. // Return value: // The number of bytes in the type, including the terminating NUL // character. The number of bytes is returned regardless of the // |buffer| and |buflen| parameters. // Comments: // Regardless of the platform, the |buffer| is always in UTF-16LE // encoding. The string is terminated by a UTF16 NUL character. If // |buflen| is less than the required length, or |buffer| is NULL, // |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_StructElement_GetType(FPDF_STRUCTELEMENT struct_element, void* buffer, unsigned long buflen); // Experimental API. // Function: FPDF_StructElement_GetObjType // Get the object type (/Type) for a given element. // Parameters: // struct_element - Handle to the struct element. // buffer - A buffer for output. May be NULL. // buflen - The length of the buffer, in bytes. May be 0. // Return value: // The number of bytes in the object type, including the terminating // NUL character. The number of bytes is returned regardless of the // |buffer| and |buflen| parameters. // Comments: // Regardless of the platform, the |buffer| is always in UTF-16LE // encoding. The string is terminated by a UTF16 NUL character. If // |buflen| is less than the required length, or |buffer| is NULL, // |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_StructElement_GetObjType(FPDF_STRUCTELEMENT struct_element, void* buffer, unsigned long buflen); // Function: FPDF_StructElement_GetTitle // Get the title (/T) for a given element. // Parameters: // struct_element - Handle to the struct element. // buffer - A buffer for output. May be NULL. // buflen - The length of the buffer, in bytes. May be 0. // Return value: // The number of bytes in the title, including the terminating NUL // character. The number of bytes is returned regardless of the // |buffer| and |buflen| parameters. // Comments: // Regardless of the platform, the |buffer| is always in UTF-16LE // encoding. The string is terminated by a UTF16 NUL character. If // |buflen| is less than the required length, or |buffer| is NULL, // |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_StructElement_GetTitle(FPDF_STRUCTELEMENT struct_element, void* buffer, unsigned long buflen); // Function: FPDF_StructElement_CountChildren // Count the number of children for the structure element. // Parameters: // struct_element - Handle to the struct element. // Return value: // The number of children, or -1 on error. FPDF_EXPORT int FPDF_CALLCONV FPDF_StructElement_CountChildren(FPDF_STRUCTELEMENT struct_element); // Function: FPDF_StructElement_GetChildAtIndex // Get a child in the structure element. // Parameters: // struct_element - Handle to the struct element. // index - The index for the child, 0-based. // Return value: // The child at the n-th index or NULL on error. // Comments: // If the child exists but is not an element, then this function will // return NULL. This will also return NULL for out of bounds indices. // The |index| must be less than the FPDF_StructElement_CountChildren() // return value. FPDF_EXPORT FPDF_STRUCTELEMENT FPDF_CALLCONV FPDF_StructElement_GetChildAtIndex(FPDF_STRUCTELEMENT struct_element, int index); // Experimental API. // Function: FPDF_StructElement_GetChildMarkedContentID // Get the child's content id // Parameters: // struct_element - Handle to the struct element. // index - The index for the child, 0-based. // Return value: // The marked content ID of the child. If no ID exists, returns -1. // Comments: // If the child exists but is not a stream or object, then this // function will return -1. This will also return -1 for out of bounds // indices. Compared to FPDF_StructElement_GetMarkedContentIdAtIndex, // it is scoped to the current page. // The |index| must be less than the FPDF_StructElement_CountChildren() // return value. FPDF_EXPORT int FPDF_CALLCONV FPDF_StructElement_GetChildMarkedContentID(FPDF_STRUCTELEMENT struct_element, int index); // Experimental API. // Function: FPDF_StructElement_GetParent // Get the parent of the structure element. // Parameters: // struct_element - Handle to the struct element. // Return value: // The parent structure element or NULL on error. // Comments: // If structure element is StructTreeRoot, then this function will // return NULL. FPDF_EXPORT FPDF_STRUCTELEMENT FPDF_CALLCONV FPDF_StructElement_GetParent(FPDF_STRUCTELEMENT struct_element); // Function: FPDF_StructElement_GetAttributeCount // Count the number of attributes for the structure element. // Parameters: // struct_element - Handle to the struct element. // Return value: // The number of attributes, or -1 on error. FPDF_EXPORT int FPDF_CALLCONV FPDF_StructElement_GetAttributeCount(FPDF_STRUCTELEMENT struct_element); // Experimental API. // Function: FPDF_StructElement_GetAttributeAtIndex // Get an attribute object in the structure element. // Parameters: // struct_element - Handle to the struct element. // index - The index for the attribute object, 0-based. // Return value: // The attribute object at the n-th index or NULL on error. // Comments: // If the attribute object exists but is not a dict, then this // function will return NULL. This will also return NULL for out of // bounds indices. The caller does not own the handle. The handle // remains valid as long as |struct_element| remains valid. // The |index| must be less than the // FPDF_StructElement_GetAttributeCount() return value. FPDF_EXPORT FPDF_STRUCTELEMENT_ATTR FPDF_CALLCONV FPDF_StructElement_GetAttributeAtIndex(FPDF_STRUCTELEMENT struct_element, int index); // Experimental API. // Function: FPDF_StructElement_Attr_GetCount // Count the number of attributes in a structure element attribute map. // Parameters: // struct_attribute - Handle to the struct element attribute. // Return value: // The number of attributes, or -1 on error. FPDF_EXPORT int FPDF_CALLCONV FPDF_StructElement_Attr_GetCount(FPDF_STRUCTELEMENT_ATTR struct_attribute); // Experimental API. // Function: FPDF_StructElement_Attr_GetName // Get the name of an attribute in a structure element attribute map. // Parameters: // struct_attribute - Handle to the struct element attribute. // index - The index of attribute in the map. // buffer - A buffer for output. May be NULL. This is only // modified if |buflen| is longer than the length // of the key. Optional, pass null to just // retrieve the size of the buffer needed. // buflen - The length of the buffer. // out_buflen - A pointer to variable that will receive the // minimum buffer size to contain the key. Not // filled if FALSE is returned. // Return value: // TRUE if the operation was successful, FALSE otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_StructElement_Attr_GetName(FPDF_STRUCTELEMENT_ATTR struct_attribute, int index, void* buffer, unsigned long buflen, unsigned long* out_buflen); // Experimental API. // Function: FPDF_StructElement_Attr_GetValue // Get a handle to a value for an attribute in a structure element // attribute map. // Parameters: // struct_attribute - Handle to the struct element attribute. // name - The attribute name. // Return value: // Returns a handle to the value associated with the input, if any. // Returns NULL on failure. The caller does not own the handle. // The handle remains valid as long as |struct_attribute| remains // valid. FPDF_EXPORT FPDF_STRUCTELEMENT_ATTR_VALUE FPDF_CALLCONV FPDF_StructElement_Attr_GetValue(FPDF_STRUCTELEMENT_ATTR struct_attribute, FPDF_BYTESTRING name); // Experimental API. // Function: FPDF_StructElement_Attr_GetType // Get the type of an attribute in a structure element attribute map. // Parameters: // value - Handle to the value. // Return value: // Returns the type of the value, or FPDF_OBJECT_UNKNOWN in case of // failure. Note that this will never return FPDF_OBJECT_REFERENCE, as // references are always dereferenced. FPDF_EXPORT FPDF_OBJECT_TYPE FPDF_CALLCONV FPDF_StructElement_Attr_GetType(FPDF_STRUCTELEMENT_ATTR_VALUE value); // Experimental API. // Function: FPDF_StructElement_Attr_GetBooleanValue // Get the value of a boolean attribute in an attribute map as // FPDF_BOOL. FPDF_StructElement_Attr_GetType() should have returned // FPDF_OBJECT_BOOLEAN for this property. // Parameters: // value - Handle to the value. // out_value - A pointer to variable that will receive the value. Not // filled if false is returned. // Return value: // Returns TRUE if the attribute maps to a boolean value, FALSE // otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_StructElement_Attr_GetBooleanValue(FPDF_STRUCTELEMENT_ATTR_VALUE value, FPDF_BOOL* out_value); // Experimental API. // Function: FPDF_StructElement_Attr_GetNumberValue // Get the value of a number attribute in an attribute map as float. // FPDF_StructElement_Attr_GetType() should have returned // FPDF_OBJECT_NUMBER for this property. // Parameters: // value - Handle to the value. // out_value - A pointer to variable that will receive the value. Not // filled if false is returned. // Return value: // Returns TRUE if the attribute maps to a number value, FALSE // otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_StructElement_Attr_GetNumberValue(FPDF_STRUCTELEMENT_ATTR_VALUE value, float* out_value); // Experimental API. // Function: FPDF_StructElement_Attr_GetStringValue // Get the value of a string attribute in an attribute map as string. // FPDF_StructElement_Attr_GetType() should have returned // FPDF_OBJECT_STRING or FPDF_OBJECT_NAME for this property. // Parameters: // value - Handle to the value. // buffer - A buffer for holding the returned key in UTF-16LE. // This is only modified if |buflen| is longer than the // length of the key. Optional, pass null to just // retrieve the size of the buffer needed. // buflen - The length of the buffer. // out_buflen - A pointer to variable that will receive the minimum // buffer size to contain the key. Not filled if FALSE is // returned. // Return value: // Returns TRUE if the attribute maps to a string value, FALSE // otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_StructElement_Attr_GetStringValue(FPDF_STRUCTELEMENT_ATTR_VALUE value, void* buffer, unsigned long buflen, unsigned long* out_buflen); // Experimental API. // Function: FPDF_StructElement_Attr_GetBlobValue // Get the value of a blob attribute in an attribute map as string. // Parameters: // value - Handle to the value. // buffer - A buffer for holding the returned value. This is only // modified if |buflen| is at least as long as the length // of the value. Optional, pass null to just retrieve the // size of the buffer needed. // buflen - The length of the buffer. // out_buflen - A pointer to variable that will receive the minimum // buffer size to contain the key. Not filled if FALSE is // returned. // Return value: // Returns TRUE if the attribute maps to a string value, FALSE // otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_StructElement_Attr_GetBlobValue(FPDF_STRUCTELEMENT_ATTR_VALUE value, void* buffer, unsigned long buflen, unsigned long* out_buflen); // Experimental API. // Function: FPDF_StructElement_Attr_CountChildren // Count the number of children values in an attribute. // Parameters: // value - Handle to the value. // Return value: // The number of children, or -1 on error. FPDF_EXPORT int FPDF_CALLCONV FPDF_StructElement_Attr_CountChildren(FPDF_STRUCTELEMENT_ATTR_VALUE value); // Experimental API. // Function: FPDF_StructElement_Attr_GetChildAtIndex // Get a child from an attribute. // Parameters: // value - Handle to the value. // index - The index for the child, 0-based. // Return value: // The child at the n-th index or NULL on error. // Comments: // The |index| must be less than the // FPDF_StructElement_Attr_CountChildren() return value. FPDF_EXPORT FPDF_STRUCTELEMENT_ATTR_VALUE FPDF_CALLCONV FPDF_StructElement_Attr_GetChildAtIndex(FPDF_STRUCTELEMENT_ATTR_VALUE value, int index); // Experimental API. // Function: FPDF_StructElement_GetMarkedContentIdCount // Get the count of marked content ids for a given element. // Parameters: // struct_element - Handle to the struct element. // Return value: // The count of marked content ids or -1 if none exists. FPDF_EXPORT int FPDF_CALLCONV FPDF_StructElement_GetMarkedContentIdCount(FPDF_STRUCTELEMENT struct_element); // Experimental API. // Function: FPDF_StructElement_GetMarkedContentIdAtIndex // Get the marked content id at a given index for a given element. // Parameters: // struct_element - Handle to the struct element. // index - The index of the marked content id, 0-based. // Return value: // The marked content ID of the element. If no ID exists, returns // -1. // Comments: // The |index| must be less than the // FPDF_StructElement_GetMarkedContentIdCount() return value. // This will likely supersede FPDF_StructElement_GetMarkedContentID(). FPDF_EXPORT int FPDF_CALLCONV FPDF_StructElement_GetMarkedContentIdAtIndex(FPDF_STRUCTELEMENT struct_element, int index); #ifdef __cplusplus } // extern "C" #endif #endif // PUBLIC_FPDF_STRUCTTREE_H_ ================================================ FILE: external/pdfium/macos-x64/include/fpdf_sysfontinfo.h ================================================ // Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #ifndef PUBLIC_FPDF_SYSFONTINFO_H_ #define PUBLIC_FPDF_SYSFONTINFO_H_ #include // clang-format off // NOLINTNEXTLINE(build/include) #include "fpdfview.h" // Character sets for the font #define FXFONT_ANSI_CHARSET 0 #define FXFONT_DEFAULT_CHARSET 1 #define FXFONT_SYMBOL_CHARSET 2 #define FXFONT_SHIFTJIS_CHARSET 128 #define FXFONT_HANGEUL_CHARSET 129 #define FXFONT_GB2312_CHARSET 134 #define FXFONT_CHINESEBIG5_CHARSET 136 #define FXFONT_GREEK_CHARSET 161 #define FXFONT_VIETNAMESE_CHARSET 163 #define FXFONT_HEBREW_CHARSET 177 #define FXFONT_ARABIC_CHARSET 178 #define FXFONT_CYRILLIC_CHARSET 204 #define FXFONT_THAI_CHARSET 222 #define FXFONT_EASTERNEUROPEAN_CHARSET 238 // Font pitch and family flags #define FXFONT_FF_FIXEDPITCH (1 << 0) #define FXFONT_FF_ROMAN (1 << 4) #define FXFONT_FF_SCRIPT (4 << 4) // Typical weight values #define FXFONT_FW_NORMAL 400 #define FXFONT_FW_BOLD 700 // Exported Functions #ifdef __cplusplus extern "C" { #endif // Interface: FPDF_SYSFONTINFO // Interface for getting system font information and font mapping typedef struct _FPDF_SYSFONTINFO { // Version number of the interface. Currently must be 1 or 2. // Version 1: Traditional behavior - calls EnumFonts during initialization. // Version 2: Per-request behavior - skips EnumFonts, relies on MapFont. // Experimental: Subject to change based on feedback. int version; // Method: Release // Give implementation a chance to release any data after the // interface is no longer used. // Interface Version: // 1 and 2 // Implementation Required: // No // Parameters: // pThis - Pointer to the interface structure itself // Return Value: // None // Comments: // Called by PDFium during the final cleanup process. void (*Release)(struct _FPDF_SYSFONTINFO* pThis); // Method: EnumFonts // Enumerate all fonts installed on the system // Interface Version: // 1 // Implementation Required: // No // Parameters: // pThis - Pointer to the interface structure itself // pMapper - An opaque pointer to internal font mapper, used // when calling FPDF_AddInstalledFont(). // Return Value: // None // Comments: // Implementations should call FPDF_AddInstalledFont() function for // each font found. Only TrueType/OpenType and Type1 fonts are // accepted by PDFium. // NOTE: This method will not be called when version is set to 2. // Version 2 relies entirely on MapFont() for per-request matching. void (*EnumFonts)(struct _FPDF_SYSFONTINFO* pThis, void* pMapper); // Method: MapFont // Use the system font mapper to get a font handle from requested // parameters. // Interface Version: // 1 and 2 // Implementation Required: // Required if GetFont method is not implemented. // Parameters: // pThis - Pointer to the interface structure itself // weight - Weight of the requested font. 400 is normal and // 700 is bold. // bItalic - Italic option of the requested font, TRUE or // FALSE. // charset - Character set identifier for the requested font. // See above defined constants. // pitch_family - A combination of flags. See above defined // constants. // face - Typeface name. Currently use system local encoding // only. // bExact - Obsolete: this parameter is now ignored. // Return Value: // An opaque pointer for font handle, or NULL if system mapping is // not supported. // Comments: // If the system supports native font mapper (like Windows), // implementation can implement this method to get a font handle. // Otherwise, PDFium will do the mapping and then call GetFont // method. Only TrueType/OpenType and Type1 fonts are accepted // by PDFium. void* (*MapFont)(struct _FPDF_SYSFONTINFO* pThis, int weight, FPDF_BOOL bItalic, int charset, int pitch_family, const char* face, FPDF_BOOL* bExact); // Method: GetFont // Get a handle to a particular font by its internal ID // Interface Version: // 1 and 2 // Implementation Required: // Required if MapFont method is not implemented. // Return Value: // An opaque pointer for font handle. // Parameters: // pThis - Pointer to the interface structure itself // face - Typeface name in system local encoding. // Comments: // If the system mapping not supported, PDFium will do the font // mapping and use this method to get a font handle. void* (*GetFont)(struct _FPDF_SYSFONTINFO* pThis, const char* face); // Method: GetFontData // Get font data from a font // Interface Version: // 1 and 2 // Implementation Required: // Yes // Parameters: // pThis - Pointer to the interface structure itself // hFont - Font handle returned by MapFont or GetFont method // table - TrueType/OpenType table identifier (refer to // TrueType specification), or 0 for the whole file. // buffer - The buffer receiving the font data. Can be NULL if // not provided. // buf_size - Buffer size, can be zero if not provided. // Return Value: // Number of bytes needed, if buffer not provided or not large // enough, or number of bytes written into buffer otherwise. // Comments: // Can read either the full font file, or a particular // TrueType/OpenType table. unsigned long (*GetFontData)(struct _FPDF_SYSFONTINFO* pThis, void* hFont, unsigned int table, unsigned char* buffer, unsigned long buf_size); // Method: GetFaceName // Get face name from a font handle // Interface Version: // 1 and 2 // Implementation Required: // No // Parameters: // pThis - Pointer to the interface structure itself // hFont - Font handle returned by MapFont or GetFont method // buffer - The buffer receiving the face name. Can be NULL if // not provided // buf_size - Buffer size, can be zero if not provided // Return Value: // Number of bytes needed, if buffer not provided or not large // enough, or number of bytes written into buffer otherwise. unsigned long (*GetFaceName)(struct _FPDF_SYSFONTINFO* pThis, void* hFont, char* buffer, unsigned long buf_size); // Method: GetFontCharset // Get character set information for a font handle // Interface Version: // 1 and 2 // Implementation Required: // No // Parameters: // pThis - Pointer to the interface structure itself // hFont - Font handle returned by MapFont or GetFont method // Return Value: // Character set identifier. See defined constants above. int (*GetFontCharset)(struct _FPDF_SYSFONTINFO* pThis, void* hFont); // Method: DeleteFont // Delete a font handle // Interface Version: // 1 and 2 // Implementation Required: // Yes // Parameters: // pThis - Pointer to the interface structure itself // hFont - Font handle returned by MapFont or GetFont method // Return Value: // None void (*DeleteFont)(struct _FPDF_SYSFONTINFO* pThis, void* hFont); } FPDF_SYSFONTINFO; // Struct: FPDF_CharsetFontMap // Provides the name of a font to use for a given charset value. typedef struct FPDF_CharsetFontMap_ { int charset; // Character Set Enum value, see FXFONT_*_CHARSET above. const char* fontname; // Name of default font to use with that charset. } FPDF_CharsetFontMap; // Function: FPDF_GetDefaultTTFMap // Returns a pointer to the default character set to TT Font name map. The // map is an array of FPDF_CharsetFontMap structs, with its end indicated // by a { -1, NULL } entry. // Parameters: // None. // Return Value: // Pointer to the Charset Font Map. // Note: // Once FPDF_GetDefaultTTFMapCount() and FPDF_GetDefaultTTFMapEntry() are no // longer experimental, this API will be marked as deprecated. // See https://crbug.com/348468114 FPDF_EXPORT const FPDF_CharsetFontMap* FPDF_CALLCONV FPDF_GetDefaultTTFMap(); // Experimental API. // // Function: FPDF_GetDefaultTTFMapCount // Returns the number of entries in the default character set to TT Font name // map. // Parameters: // None. // Return Value: // The number of entries in the map. FPDF_EXPORT size_t FPDF_CALLCONV FPDF_GetDefaultTTFMapCount(); // Experimental API. // // Function: FPDF_GetDefaultTTFMapEntry // Returns an entry in the default character set to TT Font name map. // Parameters: // index - The index to the entry in the map to retrieve. // Return Value: // A pointer to the entry, if it is in the map, or NULL if the index is out // of bounds. FPDF_EXPORT const FPDF_CharsetFontMap* FPDF_CALLCONV FPDF_GetDefaultTTFMapEntry(size_t index); // Function: FPDF_AddInstalledFont // Add a system font to the list in PDFium. // Comments: // This function is only called during the system font list building // process. // Parameters: // mapper - Opaque pointer to Foxit font mapper // face - The font face name // charset - Font character set. See above defined constants. // Return Value: // None. FPDF_EXPORT void FPDF_CALLCONV FPDF_AddInstalledFont(void* mapper, const char* face, int charset); // Function: FPDF_SetSystemFontInfo // Set the system font info interface into PDFium // Parameters: // font_info - Pointer to a FPDF_SYSFONTINFO structure // Return Value: // None // Comments: // Platform support implementation should implement required methods of // FFDF_SYSFONTINFO interface, then call this function during PDFium // initialization process. // // Call this with NULL to tell PDFium to stop using a previously set // |FPDF_SYSFONTINFO|. FPDF_EXPORT void FPDF_CALLCONV FPDF_SetSystemFontInfo(FPDF_SYSFONTINFO* font_info); // Function: FPDF_GetDefaultSystemFontInfo // Get default system font info interface for current platform // Parameters: // None // Return Value: // Pointer to a FPDF_SYSFONTINFO structure describing the default // interface, or NULL if the platform doesn't have a default interface. // Application should call FPDF_FreeDefaultSystemFontInfo to free the // returned pointer. // Comments: // For some platforms, PDFium implements a default version of system // font info interface. The default implementation can be passed to // FPDF_SetSystemFontInfo(). FPDF_EXPORT FPDF_SYSFONTINFO* FPDF_CALLCONV FPDF_GetDefaultSystemFontInfo(); // Function: FPDF_FreeDefaultSystemFontInfo // Free a default system font info interface // Parameters: // font_info - Pointer to a FPDF_SYSFONTINFO structure // Return Value: // None // Comments: // This function should be called on the output from // FPDF_GetDefaultSystemFontInfo() once it is no longer needed. FPDF_EXPORT void FPDF_CALLCONV FPDF_FreeDefaultSystemFontInfo(FPDF_SYSFONTINFO* font_info); #ifdef __cplusplus } #endif #endif // PUBLIC_FPDF_SYSFONTINFO_H_ ================================================ FILE: external/pdfium/macos-x64/include/fpdf_text.h ================================================ // Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #ifndef PUBLIC_FPDF_TEXT_H_ #define PUBLIC_FPDF_TEXT_H_ // clang-format off // NOLINTNEXTLINE(build/include) #include "fpdfview.h" // Exported Functions #ifdef __cplusplus extern "C" { #endif // Function: FPDFText_LoadPage // Prepare information about all characters in a page. // Parameters: // page - Handle to the page. Returned by FPDF_LoadPage function // (in FPDFVIEW module). // Return value: // A handle to the text page information structure. // NULL if something goes wrong. // Comments: // Application must call FPDFText_ClosePage to release the text page // information. // FPDF_EXPORT FPDF_TEXTPAGE FPDF_CALLCONV FPDFText_LoadPage(FPDF_PAGE page); // Function: FPDFText_ClosePage // Release all resources allocated for a text page information // structure. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // Return Value: // None. // FPDF_EXPORT void FPDF_CALLCONV FPDFText_ClosePage(FPDF_TEXTPAGE text_page); // Function: FPDFText_CountChars // Get number of characters in a page. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // Return value: // Number of characters in the page. Return -1 for error. // Generated characters, like additional space characters, new line // characters, are also counted. // Comments: // Characters in a page form a "stream", inside the stream, each // character has an index. // We will use the index parameters in many of FPDFTEXT functions. The // first character in the page // has an index value of zero. // FPDF_EXPORT int FPDF_CALLCONV FPDFText_CountChars(FPDF_TEXTPAGE text_page); // Function: FPDFText_GetUnicode // Get Unicode of a character in a page. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // index - Zero-based index of the character. // Return value: // The Unicode of the particular character. // If a character is not encoded in Unicode and Foxit engine can't // convert to Unicode, // the return value will be zero. // FPDF_EXPORT unsigned int FPDF_CALLCONV FPDFText_GetUnicode(FPDF_TEXTPAGE text_page, int index); // Experimental API. // Function: FPDFText_GetTextObject // Get the FPDF_PAGEOBJECT associated with a given character. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // index - Zero-based index of the character. // Return value: // The associated text object for the character at |index|, or NULL on // error. The returned text object, if non-null, is of type // |FPDF_PAGEOBJ_TEXT|. The caller does not own the returned object. // FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV FPDFText_GetTextObject(FPDF_TEXTPAGE text_page, int index); // Experimental API. // Function: FPDFText_IsGenerated // Get if a character in a page is generated by PDFium. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // index - Zero-based index of the character. // Return value: // 1 if the character is generated by PDFium. // 0 if the character is not generated by PDFium. // -1 if there was an error. // FPDF_EXPORT int FPDF_CALLCONV FPDFText_IsGenerated(FPDF_TEXTPAGE text_page, int index); // Experimental API. // Function: FPDFText_IsHyphen // Get if a character in a page is a hyphen. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // index - Zero-based index of the character. // Return value: // 1 if the character is a hyphen. // 0 if the character is not a hyphen. // -1 if there was an error. // FPDF_EXPORT int FPDF_CALLCONV FPDFText_IsHyphen(FPDF_TEXTPAGE text_page, int index); // Experimental API. // Function: FPDFText_HasUnicodeMapError // Get if a character in a page has an invalid unicode mapping. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // index - Zero-based index of the character. // Return value: // 1 if the character has an invalid unicode mapping. // 0 if the character has no known unicode mapping issues. // -1 if there was an error. // FPDF_EXPORT int FPDF_CALLCONV FPDFText_HasUnicodeMapError(FPDF_TEXTPAGE text_page, int index); // Function: FPDFText_GetFontSize // Get the font size of a particular character. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // index - Zero-based index of the character. // Return value: // The font size of the particular character, measured in points (about // 1/72 inch). This is the typographic size of the font (so called // "em size"). // FPDF_EXPORT double FPDF_CALLCONV FPDFText_GetFontSize(FPDF_TEXTPAGE text_page, int index); // Experimental API. // Function: FPDFText_GetFontInfo // Get the font name and flags of a particular character. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // index - Zero-based index of the character. // buffer - A buffer receiving the font name. // buflen - The length of |buffer| in bytes. // flags - Optional pointer to an int receiving the font flags. // These flags should be interpreted per PDF spec 1.7 // Section 5.7.1 Font Descriptor Flags. // Return value: // On success, return the length of the font name, including the // trailing NUL character, in bytes. If this length is less than or // equal to |length|, |buffer| is set to the font name, |flags| is // set to the font flags. |buffer| is in UTF-8 encoding. Return 0 on // failure. // FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFText_GetFontInfo(FPDF_TEXTPAGE text_page, int index, void* buffer, unsigned long buflen, int* flags); // Experimental API. // Function: FPDFText_GetFontWeight // Get the font weight of a particular character. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // index - Zero-based index of the character. // Return value: // On success, return the font weight of the particular character. If // |text_page| is invalid, if |index| is out of bounds, or if the // character's text object is undefined, return -1. // FPDF_EXPORT int FPDF_CALLCONV FPDFText_GetFontWeight(FPDF_TEXTPAGE text_page, int index); // Experimental API. // Function: FPDFText_GetFillColor // Get the fill color of a particular character. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // index - Zero-based index of the character. // R - Pointer to an unsigned int number receiving the // red value of the fill color. // G - Pointer to an unsigned int number receiving the // green value of the fill color. // B - Pointer to an unsigned int number receiving the // blue value of the fill color. // A - Pointer to an unsigned int number receiving the // alpha value of the fill color. // Return value: // Whether the call succeeded. If false, |R|, |G|, |B| and |A| are // unchanged. // FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFText_GetFillColor(FPDF_TEXTPAGE text_page, int index, unsigned int* R, unsigned int* G, unsigned int* B, unsigned int* A); // Experimental API. // Function: FPDFText_GetStrokeColor // Get the stroke color of a particular character. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // index - Zero-based index of the character. // R - Pointer to an unsigned int number receiving the // red value of the stroke color. // G - Pointer to an unsigned int number receiving the // green value of the stroke color. // B - Pointer to an unsigned int number receiving the // blue value of the stroke color. // A - Pointer to an unsigned int number receiving the // alpha value of the stroke color. // Return value: // Whether the call succeeded. If false, |R|, |G|, |B| and |A| are // unchanged. // FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFText_GetStrokeColor(FPDF_TEXTPAGE text_page, int index, unsigned int* R, unsigned int* G, unsigned int* B, unsigned int* A); // Experimental API. // Function: FPDFText_GetCharAngle // Get character rotation angle. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // index - Zero-based index of the character. // Return Value: // On success, return the angle value in radian. Value will always be // greater or equal to 0. If |text_page| is invalid, or if |index| is // out of bounds, then return -1. // FPDF_EXPORT float FPDF_CALLCONV FPDFText_GetCharAngle(FPDF_TEXTPAGE text_page, int index); // Function: FPDFText_GetCharBox // Get bounding box of a particular character. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // index - Zero-based index of the character. // left - Pointer to a double number receiving left position // of the character box. // right - Pointer to a double number receiving right position // of the character box. // bottom - Pointer to a double number receiving bottom position // of the character box. // top - Pointer to a double number receiving top position of // the character box. // Return Value: // On success, return TRUE and fill in |left|, |right|, |bottom|, and // |top|. If |text_page| is invalid, or if |index| is out of bounds, // then return FALSE, and the out parameters remain unmodified. // Comments: // All positions are measured in PDF "user space". // FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFText_GetCharBox(FPDF_TEXTPAGE text_page, int index, double* left, double* right, double* bottom, double* top); // Experimental API. // Function: FPDFText_GetLooseCharBox // Get a "loose" bounding box of a particular character, i.e., covering // the entire glyph bounds, without taking the actual glyph shape into // account. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // index - Zero-based index of the character. // rect - Pointer to a FS_RECTF receiving the character box. // Return Value: // On success, return TRUE and fill in |rect|. If |text_page| is // invalid, or if |index| is out of bounds, then return FALSE, and the // |rect| out parameter remains unmodified. // Comments: // All positions are measured in PDF "user space". // FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFText_GetLooseCharBox(FPDF_TEXTPAGE text_page, int index, FS_RECTF* rect); // Experimental API. // Function: FPDFText_GetMatrix // Get the effective transformation matrix for a particular character. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage(). // index - Zero-based index of the character. // matrix - Pointer to a FS_MATRIX receiving the transformation // matrix. // Return Value: // On success, return TRUE and fill in |matrix|. If |text_page| is // invalid, or if |index| is out of bounds, or if |matrix| is NULL, // then return FALSE, and |matrix| remains unmodified. // FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFText_GetMatrix(FPDF_TEXTPAGE text_page, int index, FS_MATRIX* matrix); // Function: FPDFText_GetCharOrigin // Get origin of a particular character. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // index - Zero-based index of the character. // x - Pointer to a double number receiving x coordinate of // the character origin. // y - Pointer to a double number receiving y coordinate of // the character origin. // Return Value: // Whether the call succeeded. If false, x and y are unchanged. // Comments: // All positions are measured in PDF "user space". // FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFText_GetCharOrigin(FPDF_TEXTPAGE text_page, int index, double* x, double* y); // Function: FPDFText_GetCharIndexAtPos // Get the index of a character at or nearby a certain position on the // page. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // x - X position in PDF "user space". // y - Y position in PDF "user space". // xTolerance - An x-axis tolerance value for character hit // detection, in point units. // yTolerance - A y-axis tolerance value for character hit // detection, in point units. // Return Value: // The zero-based index of the character at, or nearby the point (x,y). // If there is no character at or nearby the point, return value will // be -1. If an error occurs, -3 will be returned. // FPDF_EXPORT int FPDF_CALLCONV FPDFText_GetCharIndexAtPos(FPDF_TEXTPAGE text_page, double x, double y, double xTolerance, double yTolerance); // Function: FPDFText_GetText // Extract unicode text string from the page. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // start_index - Index for the start characters. // count - Number of UCS-2 values to be extracted. // result - A buffer (allocated by application) receiving the // extracted UCS-2 values. The buffer must be able to // hold `count` UCS-2 values plus a terminator. // Return Value: // Number of characters written into the result buffer, including the // trailing terminator. // Comments: // This function ignores characters without UCS-2 representations. // It considers all characters on the page, even those that are not // visible when the page has a cropbox. To filter out the characters // outside of the cropbox, use FPDF_GetPageBoundingBox() and // FPDFText_GetCharBox(). // FPDF_EXPORT int FPDF_CALLCONV FPDFText_GetText(FPDF_TEXTPAGE text_page, int start_index, int count, unsigned short* result); // Function: FPDFText_CountRects // Counts number of rectangular areas occupied by a segment of text, // and caches the result for subsequent FPDFText_GetRect() calls. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // start_index - Index for the start character. // count - Number of characters, or -1 for all remaining. // Return value: // Number of rectangles, 0 if text_page is null, or -1 on bad // start_index. // Comments: // This function, along with FPDFText_GetRect can be used by // applications to detect the position on the page for a text segment, // so proper areas can be highlighted. The FPDFText_* functions will // automatically merge small character boxes into bigger one if those // characters are on the same line and use same font settings. // FPDF_EXPORT int FPDF_CALLCONV FPDFText_CountRects(FPDF_TEXTPAGE text_page, int start_index, int count); // Function: FPDFText_GetRect // Get a rectangular area from the result generated by // FPDFText_CountRects. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // rect_index - Zero-based index for the rectangle. // left - Pointer to a double value receiving the rectangle // left boundary. // top - Pointer to a double value receiving the rectangle // top boundary. // right - Pointer to a double value receiving the rectangle // right boundary. // bottom - Pointer to a double value receiving the rectangle // bottom boundary. // Return Value: // On success, return TRUE and fill in |left|, |top|, |right|, and // |bottom|. If |text_page| is invalid then return FALSE, and the out // parameters remain unmodified. If |text_page| is valid but // |rect_index| is out of bounds, then return FALSE and set the out // parameters to 0. // FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFText_GetRect(FPDF_TEXTPAGE text_page, int rect_index, double* left, double* top, double* right, double* bottom); // Function: FPDFText_GetBoundedText // Extract unicode text within a rectangular boundary on the page. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // left - Left boundary. // top - Top boundary. // right - Right boundary. // bottom - Bottom boundary. // buffer - Caller-allocated buffer to receive UTF-16 values. // buflen - Number of UTF-16 values (not bytes) that `buffer` // is capable of holding. // Return Value: // If buffer is NULL or buflen is zero, return number of UTF-16 // values (not bytes) of text present within the rectangle, excluding // a terminating NUL. Generally you should pass a buffer at least one // larger than this if you want a terminating NUL, which will be // provided if space is available. Otherwise, return number of UTF-16 // values copied into the buffer, including the terminating NUL when // space for it is available. // Comment: // If the buffer is too small, as much text as will fit is copied into // it. May return a split surrogate in that case. // FPDF_EXPORT int FPDF_CALLCONV FPDFText_GetBoundedText(FPDF_TEXTPAGE text_page, double left, double top, double right, double bottom, unsigned short* buffer, int buflen); // Flags used by FPDFText_FindStart function. // // If not set, it will not match case by default. #define FPDF_MATCHCASE 0x00000001 // If not set, it will not match the whole word by default. #define FPDF_MATCHWHOLEWORD 0x00000002 // If not set, it will skip past the current match to look for the next match. #define FPDF_CONSECUTIVE 0x00000004 // Function: FPDFText_FindStart // Start a search. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // findwhat - A unicode match pattern. // flags - Option flags. // start_index - Start from this character. -1 for end of the page. // Return Value: // A handle for the search context. FPDFText_FindClose must be called // to release this handle. // FPDF_EXPORT FPDF_SCHHANDLE FPDF_CALLCONV FPDFText_FindStart(FPDF_TEXTPAGE text_page, FPDF_WIDESTRING findwhat, unsigned long flags, int start_index); // Function: FPDFText_FindNext // Search in the direction from page start to end. // Parameters: // handle - A search context handle returned by // FPDFText_FindStart. // Return Value: // Whether a match is found. // FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFText_FindNext(FPDF_SCHHANDLE handle); // Function: FPDFText_FindPrev // Search in the direction from page end to start. // Parameters: // handle - A search context handle returned by // FPDFText_FindStart. // Return Value: // Whether a match is found. // FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFText_FindPrev(FPDF_SCHHANDLE handle); // Function: FPDFText_GetSchResultIndex // Get the starting character index of the search result. // Parameters: // handle - A search context handle returned by // FPDFText_FindStart. // Return Value: // Index for the starting character. // FPDF_EXPORT int FPDF_CALLCONV FPDFText_GetSchResultIndex(FPDF_SCHHANDLE handle); // Function: FPDFText_GetSchCount // Get the number of matched characters in the search result. // Parameters: // handle - A search context handle returned by // FPDFText_FindStart. // Return Value: // Number of matched characters. // FPDF_EXPORT int FPDF_CALLCONV FPDFText_GetSchCount(FPDF_SCHHANDLE handle); // Function: FPDFText_FindClose // Release a search context. // Parameters: // handle - A search context handle returned by // FPDFText_FindStart. // Return Value: // None. // FPDF_EXPORT void FPDF_CALLCONV FPDFText_FindClose(FPDF_SCHHANDLE handle); // Function: FPDFLink_LoadWebLinks // Prepare information about weblinks in a page. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // Return Value: // A handle to the page's links information structure, or // NULL if something goes wrong. // Comments: // Weblinks are those links implicitly embedded in PDF pages. PDF also // has a type of annotation called "link" (FPDFTEXT doesn't deal with // that kind of link). FPDFTEXT weblink feature is useful for // automatically detecting links in the page contents. For example, // things like "https://www.example.com" will be detected, so // applications can allow user to click on those characters to activate // the link, even the PDF doesn't come with link annotations. // // FPDFLink_CloseWebLinks must be called to release resources. // FPDF_EXPORT FPDF_PAGELINK FPDF_CALLCONV FPDFLink_LoadWebLinks(FPDF_TEXTPAGE text_page); // Function: FPDFLink_CountWebLinks // Count number of detected web links. // Parameters: // link_page - Handle returned by FPDFLink_LoadWebLinks. // Return Value: // Number of detected web links. // FPDF_EXPORT int FPDF_CALLCONV FPDFLink_CountWebLinks(FPDF_PAGELINK link_page); // Function: FPDFLink_GetURL // Fetch the URL information for a detected web link. // Parameters: // link_page - Handle returned by FPDFLink_LoadWebLinks. // link_index - Zero-based index for the link. // buffer - A unicode buffer for the result. // buflen - Number of 16-bit code units (not bytes) for the // buffer, including an additional terminator. // Return Value: // If |buffer| is NULL or |buflen| is zero, return the number of 16-bit // code units (not bytes) needed to buffer the result (an additional // terminator is included in this count). // Otherwise, copy the result into |buffer|, truncating at |buflen| if // the result is too large to fit, and return the number of 16-bit code // units actually copied into the buffer (the additional terminator is // also included in this count). // If |link_index| does not correspond to a valid link, then the result // is an empty string. // FPDF_EXPORT int FPDF_CALLCONV FPDFLink_GetURL(FPDF_PAGELINK link_page, int link_index, unsigned short* buffer, int buflen); // Function: FPDFLink_CountRects // Count number of rectangular areas for the link. // Parameters: // link_page - Handle returned by FPDFLink_LoadWebLinks. // link_index - Zero-based index for the link. // Return Value: // Number of rectangular areas for the link. If |link_index| does // not correspond to a valid link, then 0 is returned. // FPDF_EXPORT int FPDF_CALLCONV FPDFLink_CountRects(FPDF_PAGELINK link_page, int link_index); // Function: FPDFLink_GetRect // Fetch the boundaries of a rectangle for a link. // Parameters: // link_page - Handle returned by FPDFLink_LoadWebLinks. // link_index - Zero-based index for the link. // rect_index - Zero-based index for a rectangle. // left - Pointer to a double value receiving the rectangle // left boundary. // top - Pointer to a double value receiving the rectangle // top boundary. // right - Pointer to a double value receiving the rectangle // right boundary. // bottom - Pointer to a double value receiving the rectangle // bottom boundary. // Return Value: // On success, return TRUE and fill in |left|, |top|, |right|, and // |bottom|. If |link_page| is invalid or if |link_index| does not // correspond to a valid link, then return FALSE, and the out // parameters remain unmodified. // FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFLink_GetRect(FPDF_PAGELINK link_page, int link_index, int rect_index, double* left, double* top, double* right, double* bottom); // Experimental API. // Function: FPDFLink_GetTextRange // Fetch the start char index and char count for a link. // Parameters: // link_page - Handle returned by FPDFLink_LoadWebLinks. // link_index - Zero-based index for the link. // start_char_index - pointer to int receiving the start char index // char_count - pointer to int receiving the char count // Return Value: // On success, return TRUE and fill in |start_char_index| and // |char_count|. if |link_page| is invalid or if |link_index| does // not correspond to a valid link, then return FALSE and the out // parameters remain unmodified. // FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFLink_GetTextRange(FPDF_PAGELINK link_page, int link_index, int* start_char_index, int* char_count); // Function: FPDFLink_CloseWebLinks // Release resources used by weblink feature. // Parameters: // link_page - Handle returned by FPDFLink_LoadWebLinks. // Return Value: // None. // FPDF_EXPORT void FPDF_CALLCONV FPDFLink_CloseWebLinks(FPDF_PAGELINK link_page); #ifdef __cplusplus } #endif #endif // PUBLIC_FPDF_TEXT_H_ ================================================ FILE: external/pdfium/macos-x64/include/fpdf_thumbnail.h ================================================ // Copyright 2019 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef PUBLIC_FPDF_THUMBNAIL_H_ #define PUBLIC_FPDF_THUMBNAIL_H_ #include // NOLINTNEXTLINE(build/include) #include "fpdfview.h" #ifdef __cplusplus extern "C" { #endif // Experimental API. // Gets the decoded data from the thumbnail of |page| if it exists. // This only modifies |buffer| if |buflen| less than or equal to the // size of the decoded data. Returns the size of the decoded // data or 0 if thumbnail DNE. Optional, pass null to just retrieve // the size of the buffer needed. // // page - handle to a page. // buffer - buffer for holding the decoded image data. // buflen - length of the buffer in bytes. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFPage_GetDecodedThumbnailData(FPDF_PAGE page, void* buffer, unsigned long buflen); // Experimental API. // Gets the raw data from the thumbnail of |page| if it exists. // This only modifies |buffer| if |buflen| is less than or equal to // the size of the raw data. Returns the size of the raw data or 0 // if thumbnail DNE. Optional, pass null to just retrieve the size // of the buffer needed. // // page - handle to a page. // buffer - buffer for holding the raw image data. // buflen - length of the buffer in bytes. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFPage_GetRawThumbnailData(FPDF_PAGE page, void* buffer, unsigned long buflen); // Experimental API. // Returns the thumbnail of |page| as a FPDF_BITMAP. Returns a nullptr // if unable to access the thumbnail's stream. // // page - handle to a page. FPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV FPDFPage_GetThumbnailAsBitmap(FPDF_PAGE page); #ifdef __cplusplus } #endif #endif // PUBLIC_FPDF_THUMBNAIL_H_ ================================================ FILE: external/pdfium/macos-x64/include/fpdf_transformpage.h ================================================ // Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #ifndef PUBLIC_FPDF_TRANSFORMPAGE_H_ #define PUBLIC_FPDF_TRANSFORMPAGE_H_ // NOLINTNEXTLINE(build/include) #include "fpdfview.h" #ifdef __cplusplus extern "C" { #endif // Set "MediaBox" entry to the page dictionary. // // page - Handle to a page. // left - The left of the rectangle. // bottom - The bottom of the rectangle. // right - The right of the rectangle. // top - The top of the rectangle. FPDF_EXPORT void FPDF_CALLCONV FPDFPage_SetMediaBox(FPDF_PAGE page, float left, float bottom, float right, float top); // Set "CropBox" entry to the page dictionary. // // page - Handle to a page. // left - The left of the rectangle. // bottom - The bottom of the rectangle. // right - The right of the rectangle. // top - The top of the rectangle. FPDF_EXPORT void FPDF_CALLCONV FPDFPage_SetCropBox(FPDF_PAGE page, float left, float bottom, float right, float top); // Set "BleedBox" entry to the page dictionary. // // page - Handle to a page. // left - The left of the rectangle. // bottom - The bottom of the rectangle. // right - The right of the rectangle. // top - The top of the rectangle. FPDF_EXPORT void FPDF_CALLCONV FPDFPage_SetBleedBox(FPDF_PAGE page, float left, float bottom, float right, float top); // Set "TrimBox" entry to the page dictionary. // // page - Handle to a page. // left - The left of the rectangle. // bottom - The bottom of the rectangle. // right - The right of the rectangle. // top - The top of the rectangle. FPDF_EXPORT void FPDF_CALLCONV FPDFPage_SetTrimBox(FPDF_PAGE page, float left, float bottom, float right, float top); // Set "ArtBox" entry to the page dictionary. // // page - Handle to a page. // left - The left of the rectangle. // bottom - The bottom of the rectangle. // right - The right of the rectangle. // top - The top of the rectangle. FPDF_EXPORT void FPDF_CALLCONV FPDFPage_SetArtBox(FPDF_PAGE page, float left, float bottom, float right, float top); // Get "MediaBox" entry from the page dictionary. // // page - Handle to a page. // left - Pointer to a float value receiving the left of the rectangle. // bottom - Pointer to a float value receiving the bottom of the rectangle. // right - Pointer to a float value receiving the right of the rectangle. // top - Pointer to a float value receiving the top of the rectangle. // // On success, return true and write to the out parameters. Otherwise return // false and leave the out parameters unmodified. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_GetMediaBox(FPDF_PAGE page, float* left, float* bottom, float* right, float* top); // Get "CropBox" entry from the page dictionary. // // page - Handle to a page. // left - Pointer to a float value receiving the left of the rectangle. // bottom - Pointer to a float value receiving the bottom of the rectangle. // right - Pointer to a float value receiving the right of the rectangle. // top - Pointer to a float value receiving the top of the rectangle. // // On success, return true and write to the out parameters. Otherwise return // false and leave the out parameters unmodified. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_GetCropBox(FPDF_PAGE page, float* left, float* bottom, float* right, float* top); // Get "BleedBox" entry from the page dictionary. // // page - Handle to a page. // left - Pointer to a float value receiving the left of the rectangle. // bottom - Pointer to a float value receiving the bottom of the rectangle. // right - Pointer to a float value receiving the right of the rectangle. // top - Pointer to a float value receiving the top of the rectangle. // // On success, return true and write to the out parameters. Otherwise return // false and leave the out parameters unmodified. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_GetBleedBox(FPDF_PAGE page, float* left, float* bottom, float* right, float* top); // Get "TrimBox" entry from the page dictionary. // // page - Handle to a page. // left - Pointer to a float value receiving the left of the rectangle. // bottom - Pointer to a float value receiving the bottom of the rectangle. // right - Pointer to a float value receiving the right of the rectangle. // top - Pointer to a float value receiving the top of the rectangle. // // On success, return true and write to the out parameters. Otherwise return // false and leave the out parameters unmodified. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_GetTrimBox(FPDF_PAGE page, float* left, float* bottom, float* right, float* top); // Get "ArtBox" entry from the page dictionary. // // page - Handle to a page. // left - Pointer to a float value receiving the left of the rectangle. // bottom - Pointer to a float value receiving the bottom of the rectangle. // right - Pointer to a float value receiving the right of the rectangle. // top - Pointer to a float value receiving the top of the rectangle. // // On success, return true and write to the out parameters. Otherwise return // false and leave the out parameters unmodified. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_GetArtBox(FPDF_PAGE page, float* left, float* bottom, float* right, float* top); // Apply transforms to |page|. // // If |matrix| is provided it will be applied to transform the page. // If |clipRect| is provided it will be used to clip the resulting page. // If neither |matrix| or |clipRect| are provided this method returns |false|. // Returns |true| if transforms are applied. // // This function will transform the whole page, and would take effect to all the // objects in the page. // // page - Page handle. // matrix - Transform matrix. // clipRect - Clipping rectangle. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_TransFormWithClip(FPDF_PAGE page, const FS_MATRIX* matrix, const FS_RECTF* clipRect); // Transform (scale, rotate, shear, move) the clip path of page object. // page_object - Handle to a page object. Returned by // FPDFPageObj_NewImageObj(). // // a - The coefficient "a" of the matrix. // b - The coefficient "b" of the matrix. // c - The coefficient "c" of the matrix. // d - The coefficient "d" of the matrix. // e - The coefficient "e" of the matrix. // f - The coefficient "f" of the matrix. FPDF_EXPORT void FPDF_CALLCONV FPDFPageObj_TransformClipPath(FPDF_PAGEOBJECT page_object, double a, double b, double c, double d, double e, double f); // Experimental API. // Get the clip path of the page object. // // page object - Handle to a page object. Returned by e.g. // FPDFPage_GetObject(). // // Returns the handle to the clip path, or NULL on failure. The caller does not // take ownership of the returned FPDF_CLIPPATH. Instead, it remains valid until // FPDF_ClosePage() is called for the page containing |page_object|. FPDF_EXPORT FPDF_CLIPPATH FPDF_CALLCONV FPDFPageObj_GetClipPath(FPDF_PAGEOBJECT page_object); // Experimental API. // Get number of paths inside |clip_path|. // // clip_path - handle to a clip_path. // // Returns the number of objects in |clip_path| or -1 on failure. FPDF_EXPORT int FPDF_CALLCONV FPDFClipPath_CountPaths(FPDF_CLIPPATH clip_path); // Experimental API. // Get number of segments inside one path of |clip_path|. // // clip_path - handle to a clip_path. // path_index - index into the array of paths of the clip path. // // Returns the number of segments or -1 on failure. FPDF_EXPORT int FPDF_CALLCONV FPDFClipPath_CountPathSegments(FPDF_CLIPPATH clip_path, int path_index); // Experimental API. // Get segment in one specific path of |clip_path| at index. // // clip_path - handle to a clip_path. // path_index - the index of a path. // segment_index - the index of a segment. // // Returns the handle to the segment, or NULL on failure. The caller does not // take ownership of the returned FPDF_PATHSEGMENT. Instead, it remains valid // until FPDF_ClosePage() is called for the page containing |clip_path|. FPDF_EXPORT FPDF_PATHSEGMENT FPDF_CALLCONV FPDFClipPath_GetPathSegment(FPDF_CLIPPATH clip_path, int path_index, int segment_index); // Create a new clip path, with a rectangle inserted. // // Caller takes ownership of the returned FPDF_CLIPPATH. It should be freed with // FPDF_DestroyClipPath(). // // left - The left of the clip box. // bottom - The bottom of the clip box. // right - The right of the clip box. // top - The top of the clip box. FPDF_EXPORT FPDF_CLIPPATH FPDF_CALLCONV FPDF_CreateClipPath(float left, float bottom, float right, float top); // Destroy the clip path. // // clipPath - A handle to the clip path. It will be invalid after this call. FPDF_EXPORT void FPDF_CALLCONV FPDF_DestroyClipPath(FPDF_CLIPPATH clipPath); // Clip the page content, the page content that outside the clipping region // become invisible. // // A clip path will be inserted before the page content stream or content array. // In this way, the page content will be clipped by this clip path. // // page - A page handle. // clipPath - A handle to the clip path. (Does not take ownership.) FPDF_EXPORT void FPDF_CALLCONV FPDFPage_InsertClipPath(FPDF_PAGE page, FPDF_CLIPPATH clipPath); #ifdef __cplusplus } #endif #endif // PUBLIC_FPDF_TRANSFORMPAGE_H_ ================================================ FILE: external/pdfium/macos-x64/include/fpdfview.h ================================================ // Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com // This is the main header file for embedders of PDFium. It provides APIs to // initialize the library, load documents, and render pages, amongst other // things. // // NOTE: None of the PDFium APIs are thread-safe. They expect to be called // from a single thread. Barring that, embedders are required to ensure (via // a mutex or similar) that only a single PDFium call can be made at a time. // // NOTE: External docs refer to this file as "fpdfview.h", so do not rename // despite lack of consistency with other public files. #ifndef PUBLIC_FPDFVIEW_H_ #define PUBLIC_FPDFVIEW_H_ // clang-format off #include #if defined(_WIN32) && !defined(__WINDOWS__) #include #endif #ifdef PDF_ENABLE_XFA // PDF_USE_XFA is set in confirmation that this version of PDFium can support // XFA forms as requested by the PDF_ENABLE_XFA setting. #define PDF_USE_XFA #endif // PDF_ENABLE_XFA // PDF object types #define FPDF_OBJECT_UNKNOWN 0 #define FPDF_OBJECT_BOOLEAN 1 #define FPDF_OBJECT_NUMBER 2 #define FPDF_OBJECT_STRING 3 #define FPDF_OBJECT_NAME 4 #define FPDF_OBJECT_ARRAY 5 #define FPDF_OBJECT_DICTIONARY 6 #define FPDF_OBJECT_STREAM 7 #define FPDF_OBJECT_NULLOBJ 8 #define FPDF_OBJECT_REFERENCE 9 // PDF text rendering modes typedef enum { FPDF_TEXTRENDERMODE_UNKNOWN = -1, FPDF_TEXTRENDERMODE_FILL = 0, FPDF_TEXTRENDERMODE_STROKE = 1, FPDF_TEXTRENDERMODE_FILL_STROKE = 2, FPDF_TEXTRENDERMODE_INVISIBLE = 3, FPDF_TEXTRENDERMODE_FILL_CLIP = 4, FPDF_TEXTRENDERMODE_STROKE_CLIP = 5, FPDF_TEXTRENDERMODE_FILL_STROKE_CLIP = 6, FPDF_TEXTRENDERMODE_CLIP = 7, FPDF_TEXTRENDERMODE_LAST = FPDF_TEXTRENDERMODE_CLIP, } FPDF_TEXT_RENDERMODE; // PDF types - use incomplete types (never completed) to force API type safety. typedef struct fpdf_action_t__* FPDF_ACTION; typedef struct fpdf_annotation_t__* FPDF_ANNOTATION; typedef struct fpdf_attachment_t__* FPDF_ATTACHMENT; typedef struct fpdf_avail_t__* FPDF_AVAIL; typedef struct fpdf_bitmap_t__* FPDF_BITMAP; typedef struct fpdf_bookmark_t__* FPDF_BOOKMARK; typedef struct fpdf_clippath_t__* FPDF_CLIPPATH; typedef struct fpdf_dest_t__* FPDF_DEST; typedef struct fpdf_document_t__* FPDF_DOCUMENT; typedef struct fpdf_font_t__* FPDF_FONT; typedef struct fpdf_form_handle_t__* FPDF_FORMHANDLE; typedef const struct fpdf_glyphpath_t__* FPDF_GLYPHPATH; typedef struct fpdf_javascript_action_t* FPDF_JAVASCRIPT_ACTION; typedef struct fpdf_link_t__* FPDF_LINK; typedef struct fpdf_page_t__* FPDF_PAGE; typedef struct fpdf_pagelink_t__* FPDF_PAGELINK; typedef struct fpdf_pageobject_t__* FPDF_PAGEOBJECT; // (text, path, etc.) typedef struct fpdf_pageobjectmark_t__* FPDF_PAGEOBJECTMARK; typedef const struct fpdf_pagerange_t__* FPDF_PAGERANGE; typedef const struct fpdf_pathsegment_t* FPDF_PATHSEGMENT; typedef struct fpdf_schhandle_t__* FPDF_SCHHANDLE; typedef const struct fpdf_signature_t__* FPDF_SIGNATURE; typedef void* FPDF_SKIA_CANVAS; // Passed into Skia as an SkCanvas. typedef struct fpdf_structelement_t__* FPDF_STRUCTELEMENT; typedef const struct fpdf_structelement_attr_t__* FPDF_STRUCTELEMENT_ATTR; typedef const struct fpdf_structelement_attr_value_t__* FPDF_STRUCTELEMENT_ATTR_VALUE; typedef struct fpdf_structtree_t__* FPDF_STRUCTTREE; typedef struct fpdf_textpage_t__* FPDF_TEXTPAGE; typedef struct fpdf_widget_t__* FPDF_WIDGET; typedef struct fpdf_xobject_t__* FPDF_XOBJECT; // Basic data types typedef int FPDF_BOOL; typedef int FPDF_RESULT; typedef unsigned long FPDF_DWORD; typedef float FS_FLOAT; // Duplex types typedef enum _FPDF_DUPLEXTYPE_ { DuplexUndefined = 0, Simplex, DuplexFlipShortEdge, DuplexFlipLongEdge } FPDF_DUPLEXTYPE; // String types typedef unsigned short FPDF_WCHAR; // The public PDFium API uses three types of strings: byte string, wide string // (UTF-16LE encoded), and platform dependent string. // Public PDFium API type for byte strings. typedef const char* FPDF_BYTESTRING; // The public PDFium API always uses UTF-16LE encoded wide strings, each // character uses 2 bytes (except surrogation), with the low byte first. typedef const FPDF_WCHAR* FPDF_WIDESTRING; // Structure for persisting a string beyond the duration of a callback. // Note: although represented as a char*, string may be interpreted as // a UTF-16LE formated string. Used only by XFA callbacks. typedef struct FPDF_BSTR_ { char* str; // String buffer, manipulate only with FPDF_BStr_* methods. int len; // Length of the string, in bytes. } FPDF_BSTR; // For Windows programmers: In most cases it's OK to treat FPDF_WIDESTRING as a // Windows unicode string, however, special care needs to be taken if you // expect to process Unicode larger than 0xffff. // // For Linux/Unix programmers: most compiler/library environments use 4 bytes // for a Unicode character, and you have to convert between FPDF_WIDESTRING and // system wide string by yourself. typedef const char* FPDF_STRING; // Matrix for transformation, in the form [a b c d e f], equivalent to: // | a b 0 | // | c d 0 | // | e f 1 | // // Translation is performed with [1 0 0 1 tx ty]. // Scaling is performed with [sx 0 0 sy 0 0]. // See PDF Reference 1.7, 4.2.2 Common Transformations for more. typedef struct _FS_MATRIX_ { float a; float b; float c; float d; float e; float f; } FS_MATRIX; // Rectangle area(float) in device or page coordinate system. typedef struct _FS_RECTF_ { // The x-coordinate of the left-top corner. float left; // The y-coordinate of the left-top corner. float top; // The x-coordinate of the right-bottom corner. float right; // The y-coordinate of the right-bottom corner. float bottom; } * FS_LPRECTF, FS_RECTF; // Const Pointer to FS_RECTF structure. typedef const FS_RECTF* FS_LPCRECTF; // Rectangle size. Coordinate system agnostic. typedef struct FS_SIZEF_ { float width; float height; } * FS_LPSIZEF, FS_SIZEF; // Const Pointer to FS_SIZEF structure. typedef const FS_SIZEF* FS_LPCSIZEF; // 2D Point. Coordinate system agnostic. typedef struct FS_POINTF_ { float x; float y; } * FS_LPPOINTF, FS_POINTF; // Const Pointer to FS_POINTF structure. typedef const FS_POINTF* FS_LPCPOINTF; typedef struct _FS_QUADPOINTSF { FS_FLOAT x1; FS_FLOAT y1; FS_FLOAT x2; FS_FLOAT y2; FS_FLOAT x3; FS_FLOAT y3; FS_FLOAT x4; FS_FLOAT y4; } FS_QUADPOINTSF; // Annotation enums. typedef int FPDF_ANNOTATION_SUBTYPE; typedef int FPDF_ANNOT_APPEARANCEMODE; // Dictionary value types. typedef int FPDF_OBJECT_TYPE; #if defined(WIN32) #if defined(FPDF_IMPLEMENTATION) #define FPDF_EXPORT __declspec(dllexport) #else #define FPDF_EXPORT __declspec(dllimport) #endif // defined(FPDF_IMPLEMENTATION) #else #if defined(FPDF_IMPLEMENTATION) #define FPDF_EXPORT __attribute__((visibility("default"))) #else #define FPDF_EXPORT #endif // defined(FPDF_IMPLEMENTATION) #endif // defined(WIN32) #if defined(WIN32) && defined(FPDFSDK_EXPORTS) #define FPDF_CALLCONV __stdcall #else #define FPDF_CALLCONV #endif // Exported Functions #ifdef __cplusplus extern "C" { #endif // PDF renderer types - Experimental. // Selection of 2D graphics library to use for rendering to FPDF_BITMAPs. typedef enum { // Anti-Grain Geometry - https://sourceforge.net/projects/agg/ FPDF_RENDERERTYPE_AGG = 0, // Skia - https://skia.org/ FPDF_RENDERERTYPE_SKIA = 1, } FPDF_RENDERER_TYPE; // PDF font library types - Experimental. // Selection of font backend library to use. typedef enum { // FreeType - https://freetype.org/ FPDF_FONTBACKENDTYPE_FREETYPE = 0, // Fontations - https://github.com/googlefonts/fontations/ FPDF_FONTBACKENDTYPE_FONTATIONS = 1, } FPDF_FONT_BACKEND_TYPE; // Process-wide options for initializing the library. typedef struct FPDF_LIBRARY_CONFIG_ { // Version number of the interface. Currently must be 2. // Support for version 1 will be deprecated in the future. int version; // Array of paths to scan in place of the defaults when using built-in // FXGE font loading code. The array is terminated by a NULL pointer. // The Array may be NULL itself to use the default paths. May be ignored // entirely depending upon the platform. const char** m_pUserFontPaths; // Version 2. // Pointer to the v8::Isolate to use, or NULL to force PDFium to create one. void* m_pIsolate; // The embedder data slot to use in the v8::Isolate to store PDFium's // per-isolate data. The value needs to be in the range // [0, |v8::Internals::kNumIsolateDataLots|). Note that 0 is fine for most // embedders. unsigned int m_v8EmbedderSlot; // Version 3 - Experimental. // Pointer to the V8::Platform to use. void* m_pPlatform; // Version 4 - Experimental. // Explicit specification of 2D graphics rendering library to use. // |m_RendererType| must be a valid value for |FPDF_LIBRARY_CONFIG| versions // of this level or higher, or else the initialization will fail with an // immediate crash. // Note that use of a specified |FPDF_RENDERER_TYPE| value for which the // corresponding 2D graphics rendering library is not included in the build // will similarly fail with an immediate crash. FPDF_RENDERER_TYPE m_RendererType; // Version 5 - Experimental. // Explicit specification of font library to use when |m_RendererType| is set // to |FPDF_RENDERERTYPE_SKIA|. // |m_FontLibraryType| must be a valid value for |FPDF_LIBRARY_CONFIG| // versions of this level or higher, or else the initialization will fail with // an immediate crash. // Note that use of a specified |FPDF_FONT_BACKEND_TYPE| value for which the // corresponding font library is not included in the build will similarly fail // with an immediate crash. FPDF_FONT_BACKEND_TYPE m_FontLibraryType; } FPDF_LIBRARY_CONFIG; // Function: FPDF_InitLibraryWithConfig // Initialize the PDFium library and allocate global resources for it. // Parameters: // config - configuration information as above. // Return value: // None. // Comments: // You have to call this function before you can call any PDF // processing functions. FPDF_EXPORT void FPDF_CALLCONV FPDF_InitLibraryWithConfig(const FPDF_LIBRARY_CONFIG* config); // Function: FPDF_InitLibrary // Initialize the PDFium library (alternative form). // Parameters: // None // Return value: // None. // Comments: // Convenience function to call FPDF_InitLibraryWithConfig() with a // default configuration for backwards compatibility purposes. New // code should call FPDF_InitLibraryWithConfig() instead. This will // be deprecated in the future. FPDF_EXPORT void FPDF_CALLCONV FPDF_InitLibrary(); // Function: FPDF_DestroyLibrary // Release global resources allocated to the PDFium library by // FPDF_InitLibrary() or FPDF_InitLibraryWithConfig(). // Parameters: // None. // Return value: // None. // Comments: // After this function is called, you must not call any PDF // processing functions. // // Calling this function does not automatically close other // objects. It is recommended to close other objects before // closing the library with this function. FPDF_EXPORT void FPDF_CALLCONV FPDF_DestroyLibrary(); // Policy for accessing the local machine time. #define FPDF_POLICY_MACHINETIME_ACCESS 0 // Function: FPDF_SetSandBoxPolicy // Set the policy for the sandbox environment. // Parameters: // policy - The specified policy for setting, for example: // FPDF_POLICY_MACHINETIME_ACCESS. // enable - True to enable, false to disable the policy. // Return value: // None. FPDF_EXPORT void FPDF_CALLCONV FPDF_SetSandBoxPolicy(FPDF_DWORD policy, FPDF_BOOL enable); #if defined(_WIN32) // Experimental API. // Function: FPDF_SetPrintMode // Set printing mode when printing on Windows. // Parameters: // mode - FPDF_PRINTMODE_EMF to output EMF (default) // FPDF_PRINTMODE_TEXTONLY to output text only (for charstream // devices) // FPDF_PRINTMODE_POSTSCRIPT2 to output level 2 PostScript into // EMF as a series of GDI comments. // FPDF_PRINTMODE_POSTSCRIPT3 to output level 3 PostScript into // EMF as a series of GDI comments. // FPDF_PRINTMODE_POSTSCRIPT2_PASSTHROUGH to output level 2 // PostScript via ExtEscape() in PASSTHROUGH mode. // FPDF_PRINTMODE_POSTSCRIPT3_PASSTHROUGH to output level 3 // PostScript via ExtEscape() in PASSTHROUGH mode. // FPDF_PRINTMODE_EMF_IMAGE_MASKS to output EMF, with more // efficient processing of documents containing image masks. // FPDF_PRINTMODE_POSTSCRIPT3_TYPE42 to output level 3 // PostScript with embedded Type 42 fonts, when applicable, into // EMF as a series of GDI comments. // FPDF_PRINTMODE_POSTSCRIPT3_TYPE42_PASSTHROUGH to output level // 3 PostScript with embedded Type 42 fonts, when applicable, // via ExtEscape() in PASSTHROUGH mode. // Return value: // True if successful, false if unsuccessful (typically invalid input). FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_SetPrintMode(int mode); #endif // defined(_WIN32) // Function: FPDF_LoadDocument // Open and load a PDF document. // Parameters: // file_path - Path to the PDF file (including extension). // password - A string used as the password for the PDF file. // If no password is needed, empty or NULL can be used. // See comments below regarding the encoding. // Return value: // A handle to the loaded document, or NULL on failure. // Comments: // Loaded document can be closed by FPDF_CloseDocument(). // If this function fails, you can use FPDF_GetLastError() to retrieve // the reason why it failed. // // The encoding for |file_path| is UTF-8. // // The encoding for |password| can be either UTF-8 or Latin-1. PDFs, // depending on the security handler revision, will only accept one or // the other encoding. If |password|'s encoding and the PDF's expected // encoding do not match, FPDF_LoadDocument() will automatically // convert |password| to the other encoding. FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV FPDF_LoadDocument(FPDF_STRING file_path, FPDF_BYTESTRING password); // Function: FPDF_LoadMemDocument // Open and load a PDF document from memory. // Parameters: // data_buf - Pointer to a buffer containing the PDF document. // size - Number of bytes in the PDF document. // password - A string used as the password for the PDF file. // If no password is needed, empty or NULL can be used. // Return value: // A handle to the loaded document, or NULL on failure. // Comments: // The memory buffer must remain valid when the document is open. // The loaded document can be closed by FPDF_CloseDocument. // If this function fails, you can use FPDF_GetLastError() to retrieve // the reason why it failed. // // See the comments for FPDF_LoadDocument() regarding the encoding for // |password|. // Notes: // If PDFium is built with the XFA module, the application should call // FPDF_LoadXFA() function after the PDF document loaded to support XFA // fields defined in the fpdfformfill.h file. FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV FPDF_LoadMemDocument(const void* data_buf, int size, FPDF_BYTESTRING password); // Experimental API. // Function: FPDF_LoadMemDocument64 // Open and load a PDF document from memory. // Parameters: // data_buf - Pointer to a buffer containing the PDF document. // size - Number of bytes in the PDF document. // password - A string used as the password for the PDF file. // If no password is needed, empty or NULL can be used. // Return value: // A handle to the loaded document, or NULL on failure. // Comments: // The memory buffer must remain valid when the document is open. // The loaded document can be closed by FPDF_CloseDocument. // If this function fails, you can use FPDF_GetLastError() to retrieve // the reason why it failed. // // See the comments for FPDF_LoadDocument() regarding the encoding for // |password|. // Notes: // If PDFium is built with the XFA module, the application should call // FPDF_LoadXFA() function after the PDF document loaded to support XFA // fields defined in the fpdfformfill.h file. FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV FPDF_LoadMemDocument64(const void* data_buf, size_t size, FPDF_BYTESTRING password); // Structure for custom file access. typedef struct { // File length, in bytes. unsigned long m_FileLen; // A function pointer for getting a block of data from a specific position. // Position is specified by byte offset from the beginning of the file. // The pointer to the buffer is never NULL and the size is never 0. // The position and size will never go out of range of the file length. // It may be possible for PDFium to call this function multiple times for // the same position. // Return value: should be non-zero if successful, zero for error. int (*m_GetBlock)(void* param, unsigned long position, unsigned char* pBuf, unsigned long size); // A custom pointer for all implementation specific data. This pointer will // be used as the first parameter to the m_GetBlock callback. void* m_Param; } FPDF_FILEACCESS; // Structure for file reading or writing (I/O). // // Note: This is a handler and should be implemented by callers, // and is only used from XFA. typedef struct FPDF_FILEHANDLER_ { // User-defined data. // Note: Callers can use this field to track controls. void* clientData; // Callback function to release the current file stream object. // // Parameters: // clientData - Pointer to user-defined data. // Returns: // None. void (*Release)(void* clientData); // Callback function to retrieve the current file stream size. // // Parameters: // clientData - Pointer to user-defined data. // Returns: // Size of file stream. FPDF_DWORD (*GetSize)(void* clientData); // Callback function to read data from the current file stream. // // Parameters: // clientData - Pointer to user-defined data. // offset - Offset position starts from the beginning of file // stream. This parameter indicates reading position. // buffer - Memory buffer to store data which are read from // file stream. This parameter should not be NULL. // size - Size of data which should be read from file stream, // in bytes. The buffer indicated by |buffer| must be // large enough to store specified data. // Returns: // 0 for success, other value for failure. FPDF_RESULT (*ReadBlock)(void* clientData, FPDF_DWORD offset, void* buffer, FPDF_DWORD size); // Callback function to write data into the current file stream. // // Parameters: // clientData - Pointer to user-defined data. // offset - Offset position starts from the beginning of file // stream. This parameter indicates writing position. // buffer - Memory buffer contains data which is written into // file stream. This parameter should not be NULL. // size - Size of data which should be written into file // stream, in bytes. // Returns: // 0 for success, other value for failure. FPDF_RESULT (*WriteBlock)(void* clientData, FPDF_DWORD offset, const void* buffer, FPDF_DWORD size); // Callback function to flush all internal accessing buffers. // // Parameters: // clientData - Pointer to user-defined data. // Returns: // 0 for success, other value for failure. FPDF_RESULT (*Flush)(void* clientData); // Callback function to change file size. // // Description: // This function is called under writing mode usually. Implementer // can determine whether to realize it based on application requests. // Parameters: // clientData - Pointer to user-defined data. // size - New size of file stream, in bytes. // Returns: // 0 for success, other value for failure. FPDF_RESULT (*Truncate)(void* clientData, FPDF_DWORD size); } FPDF_FILEHANDLER; // Function: FPDF_LoadCustomDocument // Load PDF document from a custom access descriptor. // Parameters: // pFileAccess - A structure for accessing the file. // password - Optional password for decrypting the PDF file. // Return value: // A handle to the loaded document, or NULL on failure. // Comments: // The application must keep the file resources |pFileAccess| points to // valid until the returned FPDF_DOCUMENT is closed. |pFileAccess| // itself does not need to outlive the FPDF_DOCUMENT. // // The loaded document can be closed with FPDF_CloseDocument(). // // See the comments for FPDF_LoadDocument() regarding the encoding for // |password|. // Notes: // If PDFium is built with the XFA module, the application should call // FPDF_LoadXFA() function after the PDF document loaded to support XFA // fields defined in the fpdfformfill.h file. FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV FPDF_LoadCustomDocument(FPDF_FILEACCESS* pFileAccess, FPDF_BYTESTRING password); // Function: FPDF_GetFileVersion // Get the file version of the given PDF document. // Parameters: // doc - Handle to a document. // fileVersion - The PDF file version. File version: 14 for 1.4, 15 // for 1.5, ... // Return value: // True if succeeds, false otherwise. // Comments: // If the document was created by FPDF_CreateNewDocument, // then this function will always fail. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_GetFileVersion(FPDF_DOCUMENT doc, int* fileVersion); #define FPDF_ERR_SUCCESS 0 // No error. #define FPDF_ERR_UNKNOWN 1 // Unknown error. #define FPDF_ERR_FILE 2 // File not found or could not be opened. #define FPDF_ERR_FORMAT 3 // File not in PDF format or corrupted. #define FPDF_ERR_PASSWORD 4 // Password required or incorrect password. #define FPDF_ERR_SECURITY 5 // Unsupported security scheme. #define FPDF_ERR_PAGE 6 // Page not found or content error. #ifdef PDF_ENABLE_XFA #define FPDF_ERR_XFALOAD 7 // Load XFA error. #define FPDF_ERR_XFALAYOUT 8 // Layout XFA error. #endif // PDF_ENABLE_XFA // Function: FPDF_GetLastError // Get last error code when a function fails. // Parameters: // None. // Return value: // A 32-bit integer indicating error code as defined above. // Comments: // If the previous SDK call succeeded, the return value of this // function is not defined. This function only works in conjunction // with APIs that mention FPDF_GetLastError() in their documentation. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetLastError(); // Experimental API. // Function: FPDF_DocumentHasValidCrossReferenceTable // Whether the document's cross reference table is valid or not. // Parameters: // document - Handle to a document. Returned by FPDF_LoadDocument. // Return value: // True if the PDF parser did not encounter problems parsing the cross // reference table. False if the parser could not parse the cross // reference table and the table had to be rebuild from other data // within the document. // Comments: // The return value can change over time as the PDF parser evolves. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_DocumentHasValidCrossReferenceTable(FPDF_DOCUMENT document); // Experimental API. // Function: FPDF_GetTrailerEnds // Get the byte offsets of trailer ends. // Parameters: // document - Handle to document. Returned by FPDF_LoadDocument(). // buffer - The address of a buffer that receives the // byte offsets. // length - The size, in ints, of |buffer|. // Return value: // Returns the number of ints in the buffer on success, 0 on error. // // |buffer| is an array of integers that describes the exact byte offsets of the // trailer ends in the document. If |length| is less than the returned length, // or |document| or |buffer| is NULL, |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetTrailerEnds(FPDF_DOCUMENT document, unsigned int* buffer, unsigned long length); // Function: FPDF_GetDocPermissions // Get file permission flags of the document. // Parameters: // document - Handle to a document. Returned by FPDF_LoadDocument. // Return value: // A 32-bit integer indicating permission flags. Please refer to the // PDF Reference for detailed descriptions. If the document is not // protected or was unlocked by the owner, 0xffffffff will be returned. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetDocPermissions(FPDF_DOCUMENT document); // Function: FPDF_GetDocUserPermissions // Get user file permission flags of the document. // Parameters: // document - Handle to a document. Returned by FPDF_LoadDocument. // Return value: // A 32-bit integer indicating permission flags. Please refer to the // PDF Reference for detailed descriptions. If the document is not // protected, 0xffffffff will be returned. Always returns user // permissions, even if the document was unlocked by the owner. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetDocUserPermissions(FPDF_DOCUMENT document); // Function: FPDF_GetSecurityHandlerRevision // Get the revision for the security handler. // Parameters: // document - Handle to a document. Returned by FPDF_LoadDocument. // Return value: // The security handler revision number. Please refer to the PDF // Reference for a detailed description. If the document is not // protected, -1 will be returned. FPDF_EXPORT int FPDF_CALLCONV FPDF_GetSecurityHandlerRevision(FPDF_DOCUMENT document); // Function: FPDF_GetPageCount // Get total number of pages in the document. // Parameters: // document - Handle to document. Returned by FPDF_LoadDocument. // Return value: // Total number of pages in the document. FPDF_EXPORT int FPDF_CALLCONV FPDF_GetPageCount(FPDF_DOCUMENT document); // Function: FPDF_LoadPage // Load a page inside the document. // Parameters: // document - Handle to document. Returned by FPDF_LoadDocument // page_index - Index number of the page. 0 for the first page. // Return value: // A handle to the loaded page, or NULL if page load fails. // Comments: // The loaded page can be rendered to devices using FPDF_RenderPage. // The loaded page can be closed using FPDF_ClosePage. FPDF_EXPORT FPDF_PAGE FPDF_CALLCONV FPDF_LoadPage(FPDF_DOCUMENT document, int page_index); // Experimental API // Function: FPDF_GetPageWidthF // Get page width. // Parameters: // page - Handle to the page. Returned by FPDF_LoadPage(). // Return value: // Page width (excluding non-displayable area) measured in points. // One point is 1/72 inch (around 0.3528 mm). // Comments: // Changing the rotation of |page| affects the return value. FPDF_EXPORT float FPDF_CALLCONV FPDF_GetPageWidthF(FPDF_PAGE page); // Function: FPDF_GetPageWidth // Get page width. // Parameters: // page - Handle to the page. Returned by FPDF_LoadPage. // Return value: // Page width (excluding non-displayable area) measured in points. // One point is 1/72 inch (around 0.3528 mm). // Note: // Prefer FPDF_GetPageWidthF() above. This will be deprecated in the // future. // Comments: // Changing the rotation of |page| affects the return value. FPDF_EXPORT double FPDF_CALLCONV FPDF_GetPageWidth(FPDF_PAGE page); // Experimental API // Function: FPDF_GetPageHeightF // Get page height. // Parameters: // page - Handle to the page. Returned by FPDF_LoadPage(). // Return value: // Page height (excluding non-displayable area) measured in points. // One point is 1/72 inch (around 0.3528 mm) // Comments: // Changing the rotation of |page| affects the return value. FPDF_EXPORT float FPDF_CALLCONV FPDF_GetPageHeightF(FPDF_PAGE page); // Function: FPDF_GetPageHeight // Get page height. // Parameters: // page - Handle to the page. Returned by FPDF_LoadPage. // Return value: // Page height (excluding non-displayable area) measured in points. // One point is 1/72 inch (around 0.3528 mm) // Note: // Prefer FPDF_GetPageHeightF() above. This will be deprecated in the // future. // Comments: // Changing the rotation of |page| affects the return value. FPDF_EXPORT double FPDF_CALLCONV FPDF_GetPageHeight(FPDF_PAGE page); // Experimental API. // Function: FPDF_GetPageBoundingBox // Get the bounding box of the page. This is the intersection between // its media box and its crop box. // Parameters: // page - Handle to the page. Returned by FPDF_LoadPage. // rect - Pointer to a rect to receive the page bounding box. // On an error, |rect| won't be filled. // Return value: // True for success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_GetPageBoundingBox(FPDF_PAGE page, FS_RECTF* rect); // Experimental API. // Function: FPDF_GetPageSizeByIndexF // Get the size of the page at the given index. // Parameters: // document - Handle to document. Returned by FPDF_LoadDocument(). // page_index - Page index, zero for the first page. // size - Pointer to a FS_SIZEF to receive the page size. // (in points). // Return value: // Non-zero for success. 0 for error (document or page not found). FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_GetPageSizeByIndexF(FPDF_DOCUMENT document, int page_index, FS_SIZEF* size); // Function: FPDF_GetPageSizeByIndex // Get the size of the page at the given index. // Parameters: // document - Handle to document. Returned by FPDF_LoadDocument. // page_index - Page index, zero for the first page. // width - Pointer to a double to receive the page width // (in points). // height - Pointer to a double to receive the page height // (in points). // Return value: // Non-zero for success. 0 for error (document or page not found). // Note: // Prefer FPDF_GetPageSizeByIndexF() above. This will be deprecated in // the future. FPDF_EXPORT int FPDF_CALLCONV FPDF_GetPageSizeByIndex(FPDF_DOCUMENT document, int page_index, double* width, double* height); // Page rendering flags. They can be combined with bit-wise OR. // // Set if annotations are to be rendered. #define FPDF_ANNOT 0x01 // Set if using text rendering optimized for LCD display. This flag will only // take effect if anti-aliasing is enabled for text. #define FPDF_LCD_TEXT 0x02 // Don't use the native text output available on some platforms #define FPDF_NO_NATIVETEXT 0x04 // Grayscale output. #define FPDF_GRAYSCALE 0x08 // Obsolete, has no effect, retained for compatibility. #define FPDF_DEBUG_INFO 0x80 // Obsolete, has no effect, retained for compatibility. #define FPDF_NO_CATCH 0x100 // Limit image cache size. #define FPDF_RENDER_LIMITEDIMAGECACHE 0x200 // Always use halftone for image stretching. #define FPDF_RENDER_FORCEHALFTONE 0x400 // Render for printing. #define FPDF_PRINTING 0x800 // Set to disable anti-aliasing on text. This flag will also disable LCD // optimization for text rendering. #define FPDF_RENDER_NO_SMOOTHTEXT 0x1000 // Set to disable anti-aliasing on images. #define FPDF_RENDER_NO_SMOOTHIMAGE 0x2000 // Set to disable anti-aliasing on paths. #define FPDF_RENDER_NO_SMOOTHPATH 0x4000 // Set whether to render in a reverse Byte order, this flag is only used when // rendering to a bitmap. #define FPDF_REVERSE_BYTE_ORDER 0x10 // Set whether fill paths need to be stroked. This flag is only used when // FPDF_COLORSCHEME is passed in, since with a single fill color for paths the // boundaries of adjacent fill paths are less visible. #define FPDF_CONVERT_FILL_TO_STROKE 0x20 // Struct for color scheme. // Each should be a 32-bit value specifying the color, in 8888 ARGB format. typedef struct FPDF_COLORSCHEME_ { FPDF_DWORD path_fill_color; FPDF_DWORD path_stroke_color; FPDF_DWORD text_fill_color; FPDF_DWORD text_stroke_color; } FPDF_COLORSCHEME; #ifdef _WIN32 // Function: FPDF_RenderPage // Render contents of a page to a device (screen, bitmap, or printer). // This function is only supported on Windows. // Parameters: // dc - Handle to the device context. // page - Handle to the page. Returned by FPDF_LoadPage. // start_x - Left pixel position of the display area in // device coordinates. // start_y - Top pixel position of the display area in device // coordinates. // size_x - Horizontal size (in pixels) for displaying the page. // size_y - Vertical size (in pixels) for displaying the page. // rotate - Page orientation: // 0 (normal) // 1 (rotated 90 degrees clockwise) // 2 (rotated 180 degrees) // 3 (rotated 90 degrees counter-clockwise) // flags - 0 for normal display, or combination of flags // defined above. // Return value: // Returns true if the page is rendered successfully, false otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_RenderPage(HDC dc, FPDF_PAGE page, int start_x, int start_y, int size_x, int size_y, int rotate, int flags); #endif // Function: FPDF_RenderPageBitmap // Render contents of a page to a device independent bitmap. // Parameters: // bitmap - Handle to the device independent bitmap (as the // output buffer). The bitmap handle can be created // by FPDFBitmap_Create or retrieved from an image // object by FPDFImageObj_GetBitmap. // page - Handle to the page. Returned by FPDF_LoadPage // start_x - Left pixel position of the display area in // bitmap coordinates. // start_y - Top pixel position of the display area in bitmap // coordinates. // size_x - Horizontal size (in pixels) for displaying the page. // size_y - Vertical size (in pixels) for displaying the page. // rotate - Page orientation: // 0 (normal) // 1 (rotated 90 degrees clockwise) // 2 (rotated 180 degrees) // 3 (rotated 90 degrees counter-clockwise) // flags - 0 for normal display, or combination of the Page // Rendering flags defined above. With the FPDF_ANNOT // flag, it renders all annotations that do not require // user-interaction, which are all annotations except // widget and popup annotations. // Return value: // None. FPDF_EXPORT void FPDF_CALLCONV FPDF_RenderPageBitmap(FPDF_BITMAP bitmap, FPDF_PAGE page, int start_x, int start_y, int size_x, int size_y, int rotate, int flags); // Function: FPDF_RenderPageBitmapWithMatrix // Render contents of a page to a device independent bitmap. // Parameters: // bitmap - Handle to the device independent bitmap (as the // output buffer). The bitmap handle can be created // by FPDFBitmap_Create or retrieved by // FPDFImageObj_GetBitmap. // page - Handle to the page. Returned by FPDF_LoadPage. // matrix - The transform matrix, which must be invertible. // See PDF Reference 1.7, 4.2.2 Common Transformations. // clipping - The rect to clip to in device coords. // flags - 0 for normal display, or combination of the Page // Rendering flags defined above. With the FPDF_ANNOT // flag, it renders all annotations that do not require // user-interaction, which are all annotations except // widget and popup annotations. // Return value: // None. Note that behavior is undefined if det of |matrix| is 0. FPDF_EXPORT void FPDF_CALLCONV FPDF_RenderPageBitmapWithMatrix(FPDF_BITMAP bitmap, FPDF_PAGE page, const FS_MATRIX* matrix, const FS_RECTF* clipping, int flags); #if defined(PDF_USE_SKIA) // Experimental API. // Function: FPDF_RenderPageSkia // Render contents of a page to a Skia SkCanvas. // Parameters: // canvas - SkCanvas to render to. // page - Handle to the page. // size_x - Horizontal size (in pixels) for displaying the page. // size_y - Vertical size (in pixels) for displaying the page. // Return value: // None. FPDF_EXPORT void FPDF_CALLCONV FPDF_RenderPageSkia(FPDF_SKIA_CANVAS canvas, FPDF_PAGE page, int size_x, int size_y); #endif // Function: FPDF_ClosePage // Close a loaded PDF page. // Parameters: // page - Handle to the loaded page. // Return value: // None. FPDF_EXPORT void FPDF_CALLCONV FPDF_ClosePage(FPDF_PAGE page); // Function: FPDF_CloseDocument // Close a loaded PDF document. // Parameters: // document - Handle to the loaded document. // Return value: // None. FPDF_EXPORT void FPDF_CALLCONV FPDF_CloseDocument(FPDF_DOCUMENT document); // Function: FPDF_DeviceToPage // Convert the screen coordinates of a point to page coordinates. // Parameters: // page - Handle to the page. Returned by FPDF_LoadPage. // start_x - Left pixel position of the display area in // device coordinates. // start_y - Top pixel position of the display area in device // coordinates. // size_x - Horizontal size (in pixels) for displaying the page. // size_y - Vertical size (in pixels) for displaying the page. // rotate - Page orientation: // 0 (normal) // 1 (rotated 90 degrees clockwise) // 2 (rotated 180 degrees) // 3 (rotated 90 degrees counter-clockwise) // device_x - X value in device coordinates to be converted. // device_y - Y value in device coordinates to be converted. // page_x - A pointer to a double receiving the converted X // value in page coordinates. // page_y - A pointer to a double receiving the converted Y // value in page coordinates. // Return value: // Returns true if the conversion succeeds, and |page_x| and |page_y| // successfully receives the converted coordinates. // Comments: // The page coordinate system has its origin at the left-bottom corner // of the page, with the X-axis on the bottom going to the right, and // the Y-axis on the left side going up. // // NOTE: this coordinate system can be altered when you zoom, scroll, // or rotate a page, however, a point on the page should always have // the same coordinate values in the page coordinate system. // // The device coordinate system is device dependent. For screen device, // its origin is at the left-top corner of the window. However this // origin can be altered by the Windows coordinate transformation // utilities. // // You must make sure the start_x, start_y, size_x, size_y // and rotate parameters have exactly same values as you used in // the FPDF_RenderPage() function call. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_DeviceToPage(FPDF_PAGE page, int start_x, int start_y, int size_x, int size_y, int rotate, int device_x, int device_y, double* page_x, double* page_y); // Function: FPDF_PageToDevice // Convert the page coordinates of a point to screen coordinates. // Parameters: // page - Handle to the page. Returned by FPDF_LoadPage. // start_x - Left pixel position of the display area in // device coordinates. // start_y - Top pixel position of the display area in device // coordinates. // size_x - Horizontal size (in pixels) for displaying the page. // size_y - Vertical size (in pixels) for displaying the page. // rotate - Page orientation: // 0 (normal) // 1 (rotated 90 degrees clockwise) // 2 (rotated 180 degrees) // 3 (rotated 90 degrees counter-clockwise) // page_x - X value in page coordinates. // page_y - Y value in page coordinate. // device_x - A pointer to an integer receiving the result X // value in device coordinates. // device_y - A pointer to an integer receiving the result Y // value in device coordinates. // Return value: // Returns true if the conversion succeeds, and |device_x| and // |device_y| successfully receives the converted coordinates. // Comments: // See comments for FPDF_DeviceToPage(). FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_PageToDevice(FPDF_PAGE page, int start_x, int start_y, int size_x, int size_y, int rotate, double page_x, double page_y, int* device_x, int* device_y); // Function: FPDFBitmap_Create // Create a device independent bitmap (FXDIB). // Parameters: // width - The number of pixels in width for the bitmap. // Must be greater than 0. // height - The number of pixels in height for the bitmap. // Must be greater than 0. // alpha - A flag indicating whether the alpha channel is used. // Non-zero for using alpha, zero for not using. // Return value: // The created bitmap handle, or NULL if a parameter error or out of // memory. // Comments: // The bitmap always uses 4 bytes per pixel. The first byte is always // double word aligned. // // The byte order is BGRx (the last byte unused if no alpha channel) or // BGRA. // // The pixels in a horizontal line are stored side by side, with the // left most pixel stored first (with lower memory address). // Each line uses width * 4 bytes. // // Lines are stored one after another, with the top most line stored // first. There is no gap between adjacent lines. // // This function allocates enough memory for holding all pixels in the // bitmap, but it doesn't initialize the buffer. Applications can use // FPDFBitmap_FillRect() to fill the bitmap using any color. If the OS // allows it, this function can allocate up to 4 GB of memory. FPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV FPDFBitmap_Create(int width, int height, int alpha); // More DIB formats // Unknown or unsupported format. // All of the colors are listed in order of LSB to MSB. #define FPDFBitmap_Unknown 0 // Gray scale bitmap, one byte per pixel. #define FPDFBitmap_Gray 1 // 3 bytes per pixel, byte order: blue, green, red. #define FPDFBitmap_BGR 2 // 4 bytes per pixel, byte order: blue, green, red, unused. #define FPDFBitmap_BGRx 3 // 4 bytes per pixel, byte order: blue, green, red, alpha. // Pixel components are independent of alpha. #define FPDFBitmap_BGRA 4 // 4 bytes per pixel, byte order: blue, green, red, alpha. // Pixel components are premultiplied by alpha. // Note that this is experimental and only supported when rendering with // |FPDF_RENDERER_TYPE| is set to |FPDF_RENDERERTYPE_SKIA|. #define FPDFBitmap_BGRA_Premul 5 // Function: FPDFBitmap_CreateEx // Create a device independent bitmap (FXDIB) // Parameters: // width - The number of pixels in width for the bitmap. // Must be greater than 0. // height - The number of pixels in height for the bitmap. // Must be greater than 0. // format - A number indicating for bitmap format, as defined // above. // first_scan - A pointer to the first byte of the first line if // using an external buffer. If this parameter is NULL, // then a new buffer will be created. // stride - Number of bytes for each scan line. The value must // be 0 or greater. When the value is 0, // FPDFBitmap_CreateEx() will automatically calculate // the appropriate value using |width| and |format|. // When using an external buffer, it is recommended for // the caller to pass in the value. // When not using an external buffer, it is recommended // for the caller to pass in 0. // Return value: // The bitmap handle, or NULL if parameter error or out of memory. // Comments: // Similar to FPDFBitmap_Create function, but allows for more formats // and an external buffer is supported. The bitmap created by this // function can be used in any place that a FPDF_BITMAP handle is // required. // // If an external buffer is used, then the caller should destroy the // buffer. FPDFBitmap_Destroy() will not destroy the buffer. // // It is recommended to use FPDFBitmap_GetStride() to get the stride // value. FPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV FPDFBitmap_CreateEx(int width, int height, int format, void* first_scan, int stride); // Function: FPDFBitmap_GetFormat // Get the format of the bitmap. // Parameters: // bitmap - Handle to the bitmap. Returned by FPDFBitmap_Create // or FPDFImageObj_GetBitmap. // Return value: // The format of the bitmap. // Comments: // Only formats supported by FPDFBitmap_CreateEx are supported by this // function; see the list of such formats above. FPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetFormat(FPDF_BITMAP bitmap); // Function: FPDFBitmap_FillRect // Fill a rectangle in a bitmap. // Parameters: // bitmap - The handle to the bitmap. Returned by // FPDFBitmap_Create. // left - The left position. Starting from 0 at the // left-most pixel. // top - The top position. Starting from 0 at the // top-most line. // width - Width in pixels to be filled. // height - Height in pixels to be filled. // color - A 32-bit value specifing the color, in 8888 ARGB // format. // Return value: // Returns whether the operation succeeded or not. // Comments: // This function sets the color and (optionally) alpha value in the // specified region of the bitmap. // // NOTE: If the alpha channel is used, this function does NOT // composite the background with the source color, instead the // background will be replaced by the source color and the alpha. // // If the alpha channel is not used, the alpha parameter is ignored. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFBitmap_FillRect(FPDF_BITMAP bitmap, int left, int top, int width, int height, FPDF_DWORD color); // Function: FPDFBitmap_GetBuffer // Get data buffer of a bitmap. // Parameters: // bitmap - Handle to the bitmap. Returned by FPDFBitmap_Create // or FPDFImageObj_GetBitmap. // Return value: // The pointer to the first byte of the bitmap buffer. // Comments: // The stride may be more than width * number of bytes per pixel // // Applications can use this function to get the bitmap buffer pointer, // then manipulate any color and/or alpha values for any pixels in the // bitmap. // // Use FPDFBitmap_GetFormat() to find out the format of the data. FPDF_EXPORT void* FPDF_CALLCONV FPDFBitmap_GetBuffer(FPDF_BITMAP bitmap); // Function: FPDFBitmap_GetWidth // Get width of a bitmap. // Parameters: // bitmap - Handle to the bitmap. Returned by FPDFBitmap_Create // or FPDFImageObj_GetBitmap. // Return value: // The width of the bitmap in pixels. FPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetWidth(FPDF_BITMAP bitmap); // Function: FPDFBitmap_GetHeight // Get height of a bitmap. // Parameters: // bitmap - Handle to the bitmap. Returned by FPDFBitmap_Create // or FPDFImageObj_GetBitmap. // Return value: // The height of the bitmap in pixels. FPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetHeight(FPDF_BITMAP bitmap); // Function: FPDFBitmap_GetStride // Get number of bytes for each line in the bitmap buffer. // Parameters: // bitmap - Handle to the bitmap. Returned by FPDFBitmap_Create // or FPDFImageObj_GetBitmap. // Return value: // The number of bytes for each line in the bitmap buffer. // Comments: // The stride may be more than width * number of bytes per pixel. FPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetStride(FPDF_BITMAP bitmap); // Function: FPDFBitmap_Destroy // Destroy a bitmap and release all related buffers. // Parameters: // bitmap - Handle to the bitmap. Returned by FPDFBitmap_Create // or FPDFImageObj_GetBitmap. // Return value: // None. // Comments: // This function will not destroy any external buffers provided when // the bitmap was created. FPDF_EXPORT void FPDF_CALLCONV FPDFBitmap_Destroy(FPDF_BITMAP bitmap); // Function: FPDF_VIEWERREF_GetPrintScaling // Whether the PDF document prefers to be scaled or not. // Parameters: // document - Handle to the loaded document. // Return value: // None. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_VIEWERREF_GetPrintScaling(FPDF_DOCUMENT document); // Function: FPDF_VIEWERREF_GetNumCopies // Returns the number of copies to be printed. // Parameters: // document - Handle to the loaded document. // Return value: // The number of copies to be printed. FPDF_EXPORT int FPDF_CALLCONV FPDF_VIEWERREF_GetNumCopies(FPDF_DOCUMENT document); // Function: FPDF_VIEWERREF_GetPrintPageRange // Page numbers to initialize print dialog box when file is printed. // Parameters: // document - Handle to the loaded document. // Return value: // The print page range to be used for printing. FPDF_EXPORT FPDF_PAGERANGE FPDF_CALLCONV FPDF_VIEWERREF_GetPrintPageRange(FPDF_DOCUMENT document); // Experimental API. // Function: FPDF_VIEWERREF_GetPrintPageRangeCount // Returns the number of elements in a FPDF_PAGERANGE. // Parameters: // pagerange - Handle to the page range. // Return value: // The number of elements in the page range. Returns 0 on error. FPDF_EXPORT size_t FPDF_CALLCONV FPDF_VIEWERREF_GetPrintPageRangeCount(FPDF_PAGERANGE pagerange); // Experimental API. // Function: FPDF_VIEWERREF_GetPrintPageRangeElement // Returns an element from a FPDF_PAGERANGE. // Parameters: // pagerange - Handle to the page range. // index - Index of the element. // Return value: // The value of the element in the page range at a given index. // Returns -1 on error. FPDF_EXPORT int FPDF_CALLCONV FPDF_VIEWERREF_GetPrintPageRangeElement(FPDF_PAGERANGE pagerange, size_t index); // Function: FPDF_VIEWERREF_GetDuplex // Returns the paper handling option to be used when printing from // the print dialog. // Parameters: // document - Handle to the loaded document. // Return value: // The paper handling option to be used when printing. FPDF_EXPORT FPDF_DUPLEXTYPE FPDF_CALLCONV FPDF_VIEWERREF_GetDuplex(FPDF_DOCUMENT document); // Function: FPDF_VIEWERREF_GetName // Gets the contents for a viewer ref, with a given key. The value must // be of type "name". // Parameters: // document - Handle to the loaded document. // key - Name of the key in the viewer pref dictionary, // encoded in UTF-8. // buffer - Caller-allocate buffer to receive the key, or NULL // - to query the required length. // length - Length of the buffer. // Return value: // The number of bytes in the contents, including the NULL terminator. // Thus if the return value is 0, then that indicates an error, such // as when |document| is invalid. If |length| is less than the required // length, or |buffer| is NULL, |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_VIEWERREF_GetName(FPDF_DOCUMENT document, FPDF_BYTESTRING key, char* buffer, unsigned long length); // Function: FPDF_CountNamedDests // Get the count of named destinations in the PDF document. // Parameters: // document - Handle to a document // Return value: // The count of named destinations. FPDF_EXPORT FPDF_DWORD FPDF_CALLCONV FPDF_CountNamedDests(FPDF_DOCUMENT document); // Function: FPDF_GetNamedDestByName // Get a the destination handle for the given name. // Parameters: // document - Handle to the loaded document. // name - The name of a destination. // Return value: // The handle to the destination. FPDF_EXPORT FPDF_DEST FPDF_CALLCONV FPDF_GetNamedDestByName(FPDF_DOCUMENT document, FPDF_BYTESTRING name); // Function: FPDF_GetNamedDest // Get the named destination by index. // Parameters: // document - Handle to a document // index - The index of a named destination. // buffer - The buffer to store the destination name, // used as wchar_t*. // buflen [in/out] - Size of the buffer in bytes on input, // length of the result in bytes on output // or -1 if the buffer is too small. // Return value: // The destination handle for a given index, or NULL if there is no // named destination corresponding to |index|. // Comments: // Call this function twice to get the name of the named destination: // 1) First time pass in |buffer| as NULL and get buflen. // 2) Second time pass in allocated |buffer| and buflen to retrieve // |buffer|, which should be used as wchar_t*. // // If buflen is not sufficiently large, it will be set to -1 upon // return. FPDF_EXPORT FPDF_DEST FPDF_CALLCONV FPDF_GetNamedDest(FPDF_DOCUMENT document, int index, void* buffer, long* buflen); // Experimental API. // Function: FPDF_GetXFAPacketCount // Get the number of valid packets in the XFA entry. // Parameters: // document - Handle to the document. // Return value: // The number of valid packets, or -1 on error. FPDF_EXPORT int FPDF_CALLCONV FPDF_GetXFAPacketCount(FPDF_DOCUMENT document); // Experimental API. // Function: FPDF_GetXFAPacketName // Get the name of a packet in the XFA array. // Parameters: // document - Handle to the document. // index - Index number of the packet. 0 for the first packet. // buffer - Buffer for holding the name of the XFA packet. // buflen - Length of |buffer| in bytes. // Return value: // The length of the packet name in bytes, or 0 on error. // // |document| must be valid and |index| must be in the range [0, N), where N is // the value returned by FPDF_GetXFAPacketCount(). // |buffer| is only modified if it is non-NULL and |buflen| is greater than or // equal to the length of the packet name. The packet name includes a // terminating NUL character. |buffer| is unmodified on error. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetXFAPacketName( FPDF_DOCUMENT document, int index, void* buffer, unsigned long buflen); // Experimental API. // Function: FPDF_GetXFAPacketContent // Get the content of a packet in the XFA array. // Parameters: // document - Handle to the document. // index - Index number of the packet. 0 for the first packet. // buffer - Buffer for holding the content of the XFA packet. // buflen - Length of |buffer| in bytes. // out_buflen - Pointer to the variable that will receive the minimum // buffer size needed to contain the content of the XFA // packet. // Return value: // Whether the operation succeeded or not. // // |document| must be valid and |index| must be in the range [0, N), where N is // the value returned by FPDF_GetXFAPacketCount(). |out_buflen| must not be // NULL. When the aforementioned arguments are valid, the operation succeeds, // and |out_buflen| receives the content size. |buffer| is only modified if // |buffer| is non-null and long enough to contain the content. Callers must // check both the return value and the input |buflen| is no less than the // returned |out_buflen| before using the data in |buffer|. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_GetXFAPacketContent( FPDF_DOCUMENT document, int index, void* buffer, unsigned long buflen, unsigned long* out_buflen); #ifdef PDF_ENABLE_V8 // Function: FPDF_GetRecommendedV8Flags // Returns a space-separated string of command line flags that are // recommended to be passed into V8 via V8::SetFlagsFromString() // prior to initializing the PDFium library. // Parameters: // None. // Return value: // NUL-terminated string of the form "--flag1 --flag2". // The caller must not attempt to modify or free the result. FPDF_EXPORT const char* FPDF_CALLCONV FPDF_GetRecommendedV8Flags(); // Experimental API. // Function: FPDF_GetArrayBufferAllocatorSharedInstance() // Helper function for initializing V8 isolates that will // use PDFium's internal memory management. // Parameters: // None. // Return Value: // Pointer to a suitable v8::ArrayBuffer::Allocator, returned // as void for C compatibility. // Notes: // Use is optional, but allows external creation of isolates // matching the ones PDFium will make when none is provided // via |FPDF_LIBRARY_CONFIG::m_pIsolate|. // // Can only be called when the library is in an uninitialized or // destroyed state. FPDF_EXPORT void* FPDF_CALLCONV FPDF_GetArrayBufferAllocatorSharedInstance(); #endif // PDF_ENABLE_V8 #ifdef PDF_ENABLE_XFA // Function: FPDF_BStr_Init // Helper function to initialize a FPDF_BSTR. FPDF_EXPORT FPDF_RESULT FPDF_CALLCONV FPDF_BStr_Init(FPDF_BSTR* bstr); // Function: FPDF_BStr_Set // Helper function to copy string data into the FPDF_BSTR. FPDF_EXPORT FPDF_RESULT FPDF_CALLCONV FPDF_BStr_Set(FPDF_BSTR* bstr, const char* cstr, int length); // Function: FPDF_BStr_Clear // Helper function to clear a FPDF_BSTR. FPDF_EXPORT FPDF_RESULT FPDF_CALLCONV FPDF_BStr_Clear(FPDF_BSTR* bstr); #endif // PDF_ENABLE_XFA #ifdef __cplusplus } #endif #endif // PUBLIC_FPDFVIEW_H_ ================================================ FILE: external/pdfium/macos-x64/include/fpdfview.h.orig ================================================ // Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com // This is the main header file for embedders of PDFium. It provides APIs to // initialize the library, load documents, and render pages, amongst other // things. // // NOTE: None of the PDFium APIs are thread-safe. They expect to be called // from a single thread. Barring that, embedders are required to ensure (via // a mutex or similar) that only a single PDFium call can be made at a time. // // NOTE: External docs refer to this file as "fpdfview.h", so do not rename // despite lack of consistency with other public files. #ifndef PUBLIC_FPDFVIEW_H_ #define PUBLIC_FPDFVIEW_H_ // clang-format off #include #if defined(_WIN32) && !defined(__WINDOWS__) #include #endif #ifdef PDF_ENABLE_XFA // PDF_USE_XFA is set in confirmation that this version of PDFium can support // XFA forms as requested by the PDF_ENABLE_XFA setting. #define PDF_USE_XFA #endif // PDF_ENABLE_XFA // PDF object types #define FPDF_OBJECT_UNKNOWN 0 #define FPDF_OBJECT_BOOLEAN 1 #define FPDF_OBJECT_NUMBER 2 #define FPDF_OBJECT_STRING 3 #define FPDF_OBJECT_NAME 4 #define FPDF_OBJECT_ARRAY 5 #define FPDF_OBJECT_DICTIONARY 6 #define FPDF_OBJECT_STREAM 7 #define FPDF_OBJECT_NULLOBJ 8 #define FPDF_OBJECT_REFERENCE 9 // PDF text rendering modes typedef enum { FPDF_TEXTRENDERMODE_UNKNOWN = -1, FPDF_TEXTRENDERMODE_FILL = 0, FPDF_TEXTRENDERMODE_STROKE = 1, FPDF_TEXTRENDERMODE_FILL_STROKE = 2, FPDF_TEXTRENDERMODE_INVISIBLE = 3, FPDF_TEXTRENDERMODE_FILL_CLIP = 4, FPDF_TEXTRENDERMODE_STROKE_CLIP = 5, FPDF_TEXTRENDERMODE_FILL_STROKE_CLIP = 6, FPDF_TEXTRENDERMODE_CLIP = 7, FPDF_TEXTRENDERMODE_LAST = FPDF_TEXTRENDERMODE_CLIP, } FPDF_TEXT_RENDERMODE; // PDF types - use incomplete types (never completed) to force API type safety. typedef struct fpdf_action_t__* FPDF_ACTION; typedef struct fpdf_annotation_t__* FPDF_ANNOTATION; typedef struct fpdf_attachment_t__* FPDF_ATTACHMENT; typedef struct fpdf_avail_t__* FPDF_AVAIL; typedef struct fpdf_bitmap_t__* FPDF_BITMAP; typedef struct fpdf_bookmark_t__* FPDF_BOOKMARK; typedef struct fpdf_clippath_t__* FPDF_CLIPPATH; typedef struct fpdf_dest_t__* FPDF_DEST; typedef struct fpdf_document_t__* FPDF_DOCUMENT; typedef struct fpdf_font_t__* FPDF_FONT; typedef struct fpdf_form_handle_t__* FPDF_FORMHANDLE; typedef const struct fpdf_glyphpath_t__* FPDF_GLYPHPATH; typedef struct fpdf_javascript_action_t* FPDF_JAVASCRIPT_ACTION; typedef struct fpdf_link_t__* FPDF_LINK; typedef struct fpdf_page_t__* FPDF_PAGE; typedef struct fpdf_pagelink_t__* FPDF_PAGELINK; typedef struct fpdf_pageobject_t__* FPDF_PAGEOBJECT; // (text, path, etc.) typedef struct fpdf_pageobjectmark_t__* FPDF_PAGEOBJECTMARK; typedef const struct fpdf_pagerange_t__* FPDF_PAGERANGE; typedef const struct fpdf_pathsegment_t* FPDF_PATHSEGMENT; typedef struct fpdf_schhandle_t__* FPDF_SCHHANDLE; typedef const struct fpdf_signature_t__* FPDF_SIGNATURE; typedef void* FPDF_SKIA_CANVAS; // Passed into Skia as an SkCanvas. typedef struct fpdf_structelement_t__* FPDF_STRUCTELEMENT; typedef const struct fpdf_structelement_attr_t__* FPDF_STRUCTELEMENT_ATTR; typedef const struct fpdf_structelement_attr_value_t__* FPDF_STRUCTELEMENT_ATTR_VALUE; typedef struct fpdf_structtree_t__* FPDF_STRUCTTREE; typedef struct fpdf_textpage_t__* FPDF_TEXTPAGE; typedef struct fpdf_widget_t__* FPDF_WIDGET; typedef struct fpdf_xobject_t__* FPDF_XOBJECT; // Basic data types typedef int FPDF_BOOL; typedef int FPDF_RESULT; typedef unsigned long FPDF_DWORD; typedef float FS_FLOAT; // Duplex types typedef enum _FPDF_DUPLEXTYPE_ { DuplexUndefined = 0, Simplex, DuplexFlipShortEdge, DuplexFlipLongEdge } FPDF_DUPLEXTYPE; // String types typedef unsigned short FPDF_WCHAR; // The public PDFium API uses three types of strings: byte string, wide string // (UTF-16LE encoded), and platform dependent string. // Public PDFium API type for byte strings. typedef const char* FPDF_BYTESTRING; // The public PDFium API always uses UTF-16LE encoded wide strings, each // character uses 2 bytes (except surrogation), with the low byte first. typedef const FPDF_WCHAR* FPDF_WIDESTRING; // Structure for persisting a string beyond the duration of a callback. // Note: although represented as a char*, string may be interpreted as // a UTF-16LE formated string. Used only by XFA callbacks. typedef struct FPDF_BSTR_ { char* str; // String buffer, manipulate only with FPDF_BStr_* methods. int len; // Length of the string, in bytes. } FPDF_BSTR; // For Windows programmers: In most cases it's OK to treat FPDF_WIDESTRING as a // Windows unicode string, however, special care needs to be taken if you // expect to process Unicode larger than 0xffff. // // For Linux/Unix programmers: most compiler/library environments use 4 bytes // for a Unicode character, and you have to convert between FPDF_WIDESTRING and // system wide string by yourself. typedef const char* FPDF_STRING; // Matrix for transformation, in the form [a b c d e f], equivalent to: // | a b 0 | // | c d 0 | // | e f 1 | // // Translation is performed with [1 0 0 1 tx ty]. // Scaling is performed with [sx 0 0 sy 0 0]. // See PDF Reference 1.7, 4.2.2 Common Transformations for more. typedef struct _FS_MATRIX_ { float a; float b; float c; float d; float e; float f; } FS_MATRIX; // Rectangle area(float) in device or page coordinate system. typedef struct _FS_RECTF_ { // The x-coordinate of the left-top corner. float left; // The y-coordinate of the left-top corner. float top; // The x-coordinate of the right-bottom corner. float right; // The y-coordinate of the right-bottom corner. float bottom; } * FS_LPRECTF, FS_RECTF; // Const Pointer to FS_RECTF structure. typedef const FS_RECTF* FS_LPCRECTF; // Rectangle size. Coordinate system agnostic. typedef struct FS_SIZEF_ { float width; float height; } * FS_LPSIZEF, FS_SIZEF; // Const Pointer to FS_SIZEF structure. typedef const FS_SIZEF* FS_LPCSIZEF; // 2D Point. Coordinate system agnostic. typedef struct FS_POINTF_ { float x; float y; } * FS_LPPOINTF, FS_POINTF; // Const Pointer to FS_POINTF structure. typedef const FS_POINTF* FS_LPCPOINTF; typedef struct _FS_QUADPOINTSF { FS_FLOAT x1; FS_FLOAT y1; FS_FLOAT x2; FS_FLOAT y2; FS_FLOAT x3; FS_FLOAT y3; FS_FLOAT x4; FS_FLOAT y4; } FS_QUADPOINTSF; // Annotation enums. typedef int FPDF_ANNOTATION_SUBTYPE; typedef int FPDF_ANNOT_APPEARANCEMODE; // Dictionary value types. typedef int FPDF_OBJECT_TYPE; #if defined(COMPONENT_BUILD) // FPDF_EXPORT should be consistent with |export| in the pdfium_fuzzer // template in testing/fuzzers/BUILD.gn. #if defined(WIN32) #if defined(FPDF_IMPLEMENTATION) #define FPDF_EXPORT __declspec(dllexport) #else #define FPDF_EXPORT __declspec(dllimport) #endif // defined(FPDF_IMPLEMENTATION) #else #if defined(FPDF_IMPLEMENTATION) #define FPDF_EXPORT __attribute__((visibility("default"))) #else #define FPDF_EXPORT #endif // defined(FPDF_IMPLEMENTATION) #endif // defined(WIN32) #else #define FPDF_EXPORT #endif // defined(COMPONENT_BUILD) #if defined(WIN32) && defined(FPDFSDK_EXPORTS) #define FPDF_CALLCONV __stdcall #else #define FPDF_CALLCONV #endif // Exported Functions #ifdef __cplusplus extern "C" { #endif // PDF renderer types - Experimental. // Selection of 2D graphics library to use for rendering to FPDF_BITMAPs. typedef enum { // Anti-Grain Geometry - https://sourceforge.net/projects/agg/ FPDF_RENDERERTYPE_AGG = 0, // Skia - https://skia.org/ FPDF_RENDERERTYPE_SKIA = 1, } FPDF_RENDERER_TYPE; // PDF font library types - Experimental. // Selection of font backend library to use. typedef enum { // FreeType - https://freetype.org/ FPDF_FONTBACKENDTYPE_FREETYPE = 0, // Fontations - https://github.com/googlefonts/fontations/ FPDF_FONTBACKENDTYPE_FONTATIONS = 1, } FPDF_FONT_BACKEND_TYPE; // Process-wide options for initializing the library. typedef struct FPDF_LIBRARY_CONFIG_ { // Version number of the interface. Currently must be 2. // Support for version 1 will be deprecated in the future. int version; // Array of paths to scan in place of the defaults when using built-in // FXGE font loading code. The array is terminated by a NULL pointer. // The Array may be NULL itself to use the default paths. May be ignored // entirely depending upon the platform. const char** m_pUserFontPaths; // Version 2. // Pointer to the v8::Isolate to use, or NULL to force PDFium to create one. void* m_pIsolate; // The embedder data slot to use in the v8::Isolate to store PDFium's // per-isolate data. The value needs to be in the range // [0, |v8::Internals::kNumIsolateDataLots|). Note that 0 is fine for most // embedders. unsigned int m_v8EmbedderSlot; // Version 3 - Experimental. // Pointer to the V8::Platform to use. void* m_pPlatform; // Version 4 - Experimental. // Explicit specification of 2D graphics rendering library to use. // |m_RendererType| must be a valid value for |FPDF_LIBRARY_CONFIG| versions // of this level or higher, or else the initialization will fail with an // immediate crash. // Note that use of a specified |FPDF_RENDERER_TYPE| value for which the // corresponding 2D graphics rendering library is not included in the build // will similarly fail with an immediate crash. FPDF_RENDERER_TYPE m_RendererType; // Version 5 - Experimental. // Explicit specification of font library to use when |m_RendererType| is set // to |FPDF_RENDERERTYPE_SKIA|. // |m_FontLibraryType| must be a valid value for |FPDF_LIBRARY_CONFIG| // versions of this level or higher, or else the initialization will fail with // an immediate crash. // Note that use of a specified |FPDF_FONT_BACKEND_TYPE| value for which the // corresponding font library is not included in the build will similarly fail // with an immediate crash. FPDF_FONT_BACKEND_TYPE m_FontLibraryType; } FPDF_LIBRARY_CONFIG; // Function: FPDF_InitLibraryWithConfig // Initialize the PDFium library and allocate global resources for it. // Parameters: // config - configuration information as above. // Return value: // None. // Comments: // You have to call this function before you can call any PDF // processing functions. FPDF_EXPORT void FPDF_CALLCONV FPDF_InitLibraryWithConfig(const FPDF_LIBRARY_CONFIG* config); // Function: FPDF_InitLibrary // Initialize the PDFium library (alternative form). // Parameters: // None // Return value: // None. // Comments: // Convenience function to call FPDF_InitLibraryWithConfig() with a // default configuration for backwards compatibility purposes. New // code should call FPDF_InitLibraryWithConfig() instead. This will // be deprecated in the future. FPDF_EXPORT void FPDF_CALLCONV FPDF_InitLibrary(); // Function: FPDF_DestroyLibrary // Release global resources allocated to the PDFium library by // FPDF_InitLibrary() or FPDF_InitLibraryWithConfig(). // Parameters: // None. // Return value: // None. // Comments: // After this function is called, you must not call any PDF // processing functions. // // Calling this function does not automatically close other // objects. It is recommended to close other objects before // closing the library with this function. FPDF_EXPORT void FPDF_CALLCONV FPDF_DestroyLibrary(); // Policy for accessing the local machine time. #define FPDF_POLICY_MACHINETIME_ACCESS 0 // Function: FPDF_SetSandBoxPolicy // Set the policy for the sandbox environment. // Parameters: // policy - The specified policy for setting, for example: // FPDF_POLICY_MACHINETIME_ACCESS. // enable - True to enable, false to disable the policy. // Return value: // None. FPDF_EXPORT void FPDF_CALLCONV FPDF_SetSandBoxPolicy(FPDF_DWORD policy, FPDF_BOOL enable); #if defined(_WIN32) // Experimental API. // Function: FPDF_SetPrintMode // Set printing mode when printing on Windows. // Parameters: // mode - FPDF_PRINTMODE_EMF to output EMF (default) // FPDF_PRINTMODE_TEXTONLY to output text only (for charstream // devices) // FPDF_PRINTMODE_POSTSCRIPT2 to output level 2 PostScript into // EMF as a series of GDI comments. // FPDF_PRINTMODE_POSTSCRIPT3 to output level 3 PostScript into // EMF as a series of GDI comments. // FPDF_PRINTMODE_POSTSCRIPT2_PASSTHROUGH to output level 2 // PostScript via ExtEscape() in PASSTHROUGH mode. // FPDF_PRINTMODE_POSTSCRIPT3_PASSTHROUGH to output level 3 // PostScript via ExtEscape() in PASSTHROUGH mode. // FPDF_PRINTMODE_EMF_IMAGE_MASKS to output EMF, with more // efficient processing of documents containing image masks. // FPDF_PRINTMODE_POSTSCRIPT3_TYPE42 to output level 3 // PostScript with embedded Type 42 fonts, when applicable, into // EMF as a series of GDI comments. // FPDF_PRINTMODE_POSTSCRIPT3_TYPE42_PASSTHROUGH to output level // 3 PostScript with embedded Type 42 fonts, when applicable, // via ExtEscape() in PASSTHROUGH mode. // Return value: // True if successful, false if unsuccessful (typically invalid input). FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_SetPrintMode(int mode); #endif // defined(_WIN32) // Function: FPDF_LoadDocument // Open and load a PDF document. // Parameters: // file_path - Path to the PDF file (including extension). // password - A string used as the password for the PDF file. // If no password is needed, empty or NULL can be used. // See comments below regarding the encoding. // Return value: // A handle to the loaded document, or NULL on failure. // Comments: // Loaded document can be closed by FPDF_CloseDocument(). // If this function fails, you can use FPDF_GetLastError() to retrieve // the reason why it failed. // // The encoding for |file_path| is UTF-8. // // The encoding for |password| can be either UTF-8 or Latin-1. PDFs, // depending on the security handler revision, will only accept one or // the other encoding. If |password|'s encoding and the PDF's expected // encoding do not match, FPDF_LoadDocument() will automatically // convert |password| to the other encoding. FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV FPDF_LoadDocument(FPDF_STRING file_path, FPDF_BYTESTRING password); // Function: FPDF_LoadMemDocument // Open and load a PDF document from memory. // Parameters: // data_buf - Pointer to a buffer containing the PDF document. // size - Number of bytes in the PDF document. // password - A string used as the password for the PDF file. // If no password is needed, empty or NULL can be used. // Return value: // A handle to the loaded document, or NULL on failure. // Comments: // The memory buffer must remain valid when the document is open. // The loaded document can be closed by FPDF_CloseDocument. // If this function fails, you can use FPDF_GetLastError() to retrieve // the reason why it failed. // // See the comments for FPDF_LoadDocument() regarding the encoding for // |password|. // Notes: // If PDFium is built with the XFA module, the application should call // FPDF_LoadXFA() function after the PDF document loaded to support XFA // fields defined in the fpdfformfill.h file. FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV FPDF_LoadMemDocument(const void* data_buf, int size, FPDF_BYTESTRING password); // Experimental API. // Function: FPDF_LoadMemDocument64 // Open and load a PDF document from memory. // Parameters: // data_buf - Pointer to a buffer containing the PDF document. // size - Number of bytes in the PDF document. // password - A string used as the password for the PDF file. // If no password is needed, empty or NULL can be used. // Return value: // A handle to the loaded document, or NULL on failure. // Comments: // The memory buffer must remain valid when the document is open. // The loaded document can be closed by FPDF_CloseDocument. // If this function fails, you can use FPDF_GetLastError() to retrieve // the reason why it failed. // // See the comments for FPDF_LoadDocument() regarding the encoding for // |password|. // Notes: // If PDFium is built with the XFA module, the application should call // FPDF_LoadXFA() function after the PDF document loaded to support XFA // fields defined in the fpdfformfill.h file. FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV FPDF_LoadMemDocument64(const void* data_buf, size_t size, FPDF_BYTESTRING password); // Structure for custom file access. typedef struct { // File length, in bytes. unsigned long m_FileLen; // A function pointer for getting a block of data from a specific position. // Position is specified by byte offset from the beginning of the file. // The pointer to the buffer is never NULL and the size is never 0. // The position and size will never go out of range of the file length. // It may be possible for PDFium to call this function multiple times for // the same position. // Return value: should be non-zero if successful, zero for error. int (*m_GetBlock)(void* param, unsigned long position, unsigned char* pBuf, unsigned long size); // A custom pointer for all implementation specific data. This pointer will // be used as the first parameter to the m_GetBlock callback. void* m_Param; } FPDF_FILEACCESS; // Structure for file reading or writing (I/O). // // Note: This is a handler and should be implemented by callers, // and is only used from XFA. typedef struct FPDF_FILEHANDLER_ { // User-defined data. // Note: Callers can use this field to track controls. void* clientData; // Callback function to release the current file stream object. // // Parameters: // clientData - Pointer to user-defined data. // Returns: // None. void (*Release)(void* clientData); // Callback function to retrieve the current file stream size. // // Parameters: // clientData - Pointer to user-defined data. // Returns: // Size of file stream. FPDF_DWORD (*GetSize)(void* clientData); // Callback function to read data from the current file stream. // // Parameters: // clientData - Pointer to user-defined data. // offset - Offset position starts from the beginning of file // stream. This parameter indicates reading position. // buffer - Memory buffer to store data which are read from // file stream. This parameter should not be NULL. // size - Size of data which should be read from file stream, // in bytes. The buffer indicated by |buffer| must be // large enough to store specified data. // Returns: // 0 for success, other value for failure. FPDF_RESULT (*ReadBlock)(void* clientData, FPDF_DWORD offset, void* buffer, FPDF_DWORD size); // Callback function to write data into the current file stream. // // Parameters: // clientData - Pointer to user-defined data. // offset - Offset position starts from the beginning of file // stream. This parameter indicates writing position. // buffer - Memory buffer contains data which is written into // file stream. This parameter should not be NULL. // size - Size of data which should be written into file // stream, in bytes. // Returns: // 0 for success, other value for failure. FPDF_RESULT (*WriteBlock)(void* clientData, FPDF_DWORD offset, const void* buffer, FPDF_DWORD size); // Callback function to flush all internal accessing buffers. // // Parameters: // clientData - Pointer to user-defined data. // Returns: // 0 for success, other value for failure. FPDF_RESULT (*Flush)(void* clientData); // Callback function to change file size. // // Description: // This function is called under writing mode usually. Implementer // can determine whether to realize it based on application requests. // Parameters: // clientData - Pointer to user-defined data. // size - New size of file stream, in bytes. // Returns: // 0 for success, other value for failure. FPDF_RESULT (*Truncate)(void* clientData, FPDF_DWORD size); } FPDF_FILEHANDLER; // Function: FPDF_LoadCustomDocument // Load PDF document from a custom access descriptor. // Parameters: // pFileAccess - A structure for accessing the file. // password - Optional password for decrypting the PDF file. // Return value: // A handle to the loaded document, or NULL on failure. // Comments: // The application must keep the file resources |pFileAccess| points to // valid until the returned FPDF_DOCUMENT is closed. |pFileAccess| // itself does not need to outlive the FPDF_DOCUMENT. // // The loaded document can be closed with FPDF_CloseDocument(). // // See the comments for FPDF_LoadDocument() regarding the encoding for // |password|. // Notes: // If PDFium is built with the XFA module, the application should call // FPDF_LoadXFA() function after the PDF document loaded to support XFA // fields defined in the fpdfformfill.h file. FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV FPDF_LoadCustomDocument(FPDF_FILEACCESS* pFileAccess, FPDF_BYTESTRING password); // Function: FPDF_GetFileVersion // Get the file version of the given PDF document. // Parameters: // doc - Handle to a document. // fileVersion - The PDF file version. File version: 14 for 1.4, 15 // for 1.5, ... // Return value: // True if succeeds, false otherwise. // Comments: // If the document was created by FPDF_CreateNewDocument, // then this function will always fail. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_GetFileVersion(FPDF_DOCUMENT doc, int* fileVersion); #define FPDF_ERR_SUCCESS 0 // No error. #define FPDF_ERR_UNKNOWN 1 // Unknown error. #define FPDF_ERR_FILE 2 // File not found or could not be opened. #define FPDF_ERR_FORMAT 3 // File not in PDF format or corrupted. #define FPDF_ERR_PASSWORD 4 // Password required or incorrect password. #define FPDF_ERR_SECURITY 5 // Unsupported security scheme. #define FPDF_ERR_PAGE 6 // Page not found or content error. #ifdef PDF_ENABLE_XFA #define FPDF_ERR_XFALOAD 7 // Load XFA error. #define FPDF_ERR_XFALAYOUT 8 // Layout XFA error. #endif // PDF_ENABLE_XFA // Function: FPDF_GetLastError // Get last error code when a function fails. // Parameters: // None. // Return value: // A 32-bit integer indicating error code as defined above. // Comments: // If the previous SDK call succeeded, the return value of this // function is not defined. This function only works in conjunction // with APIs that mention FPDF_GetLastError() in their documentation. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetLastError(); // Experimental API. // Function: FPDF_DocumentHasValidCrossReferenceTable // Whether the document's cross reference table is valid or not. // Parameters: // document - Handle to a document. Returned by FPDF_LoadDocument. // Return value: // True if the PDF parser did not encounter problems parsing the cross // reference table. False if the parser could not parse the cross // reference table and the table had to be rebuild from other data // within the document. // Comments: // The return value can change over time as the PDF parser evolves. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_DocumentHasValidCrossReferenceTable(FPDF_DOCUMENT document); // Experimental API. // Function: FPDF_GetTrailerEnds // Get the byte offsets of trailer ends. // Parameters: // document - Handle to document. Returned by FPDF_LoadDocument(). // buffer - The address of a buffer that receives the // byte offsets. // length - The size, in ints, of |buffer|. // Return value: // Returns the number of ints in the buffer on success, 0 on error. // // |buffer| is an array of integers that describes the exact byte offsets of the // trailer ends in the document. If |length| is less than the returned length, // or |document| or |buffer| is NULL, |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetTrailerEnds(FPDF_DOCUMENT document, unsigned int* buffer, unsigned long length); // Function: FPDF_GetDocPermissions // Get file permission flags of the document. // Parameters: // document - Handle to a document. Returned by FPDF_LoadDocument. // Return value: // A 32-bit integer indicating permission flags. Please refer to the // PDF Reference for detailed descriptions. If the document is not // protected or was unlocked by the owner, 0xffffffff will be returned. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetDocPermissions(FPDF_DOCUMENT document); // Function: FPDF_GetDocUserPermissions // Get user file permission flags of the document. // Parameters: // document - Handle to a document. Returned by FPDF_LoadDocument. // Return value: // A 32-bit integer indicating permission flags. Please refer to the // PDF Reference for detailed descriptions. If the document is not // protected, 0xffffffff will be returned. Always returns user // permissions, even if the document was unlocked by the owner. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetDocUserPermissions(FPDF_DOCUMENT document); // Function: FPDF_GetSecurityHandlerRevision // Get the revision for the security handler. // Parameters: // document - Handle to a document. Returned by FPDF_LoadDocument. // Return value: // The security handler revision number. Please refer to the PDF // Reference for a detailed description. If the document is not // protected, -1 will be returned. FPDF_EXPORT int FPDF_CALLCONV FPDF_GetSecurityHandlerRevision(FPDF_DOCUMENT document); // Function: FPDF_GetPageCount // Get total number of pages in the document. // Parameters: // document - Handle to document. Returned by FPDF_LoadDocument. // Return value: // Total number of pages in the document. FPDF_EXPORT int FPDF_CALLCONV FPDF_GetPageCount(FPDF_DOCUMENT document); // Function: FPDF_LoadPage // Load a page inside the document. // Parameters: // document - Handle to document. Returned by FPDF_LoadDocument // page_index - Index number of the page. 0 for the first page. // Return value: // A handle to the loaded page, or NULL if page load fails. // Comments: // The loaded page can be rendered to devices using FPDF_RenderPage. // The loaded page can be closed using FPDF_ClosePage. FPDF_EXPORT FPDF_PAGE FPDF_CALLCONV FPDF_LoadPage(FPDF_DOCUMENT document, int page_index); // Experimental API // Function: FPDF_GetPageWidthF // Get page width. // Parameters: // page - Handle to the page. Returned by FPDF_LoadPage(). // Return value: // Page width (excluding non-displayable area) measured in points. // One point is 1/72 inch (around 0.3528 mm). // Comments: // Changing the rotation of |page| affects the return value. FPDF_EXPORT float FPDF_CALLCONV FPDF_GetPageWidthF(FPDF_PAGE page); // Function: FPDF_GetPageWidth // Get page width. // Parameters: // page - Handle to the page. Returned by FPDF_LoadPage. // Return value: // Page width (excluding non-displayable area) measured in points. // One point is 1/72 inch (around 0.3528 mm). // Note: // Prefer FPDF_GetPageWidthF() above. This will be deprecated in the // future. // Comments: // Changing the rotation of |page| affects the return value. FPDF_EXPORT double FPDF_CALLCONV FPDF_GetPageWidth(FPDF_PAGE page); // Experimental API // Function: FPDF_GetPageHeightF // Get page height. // Parameters: // page - Handle to the page. Returned by FPDF_LoadPage(). // Return value: // Page height (excluding non-displayable area) measured in points. // One point is 1/72 inch (around 0.3528 mm) // Comments: // Changing the rotation of |page| affects the return value. FPDF_EXPORT float FPDF_CALLCONV FPDF_GetPageHeightF(FPDF_PAGE page); // Function: FPDF_GetPageHeight // Get page height. // Parameters: // page - Handle to the page. Returned by FPDF_LoadPage. // Return value: // Page height (excluding non-displayable area) measured in points. // One point is 1/72 inch (around 0.3528 mm) // Note: // Prefer FPDF_GetPageHeightF() above. This will be deprecated in the // future. // Comments: // Changing the rotation of |page| affects the return value. FPDF_EXPORT double FPDF_CALLCONV FPDF_GetPageHeight(FPDF_PAGE page); // Experimental API. // Function: FPDF_GetPageBoundingBox // Get the bounding box of the page. This is the intersection between // its media box and its crop box. // Parameters: // page - Handle to the page. Returned by FPDF_LoadPage. // rect - Pointer to a rect to receive the page bounding box. // On an error, |rect| won't be filled. // Return value: // True for success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_GetPageBoundingBox(FPDF_PAGE page, FS_RECTF* rect); // Experimental API. // Function: FPDF_GetPageSizeByIndexF // Get the size of the page at the given index. // Parameters: // document - Handle to document. Returned by FPDF_LoadDocument(). // page_index - Page index, zero for the first page. // size - Pointer to a FS_SIZEF to receive the page size. // (in points). // Return value: // Non-zero for success. 0 for error (document or page not found). FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_GetPageSizeByIndexF(FPDF_DOCUMENT document, int page_index, FS_SIZEF* size); // Function: FPDF_GetPageSizeByIndex // Get the size of the page at the given index. // Parameters: // document - Handle to document. Returned by FPDF_LoadDocument. // page_index - Page index, zero for the first page. // width - Pointer to a double to receive the page width // (in points). // height - Pointer to a double to receive the page height // (in points). // Return value: // Non-zero for success. 0 for error (document or page not found). // Note: // Prefer FPDF_GetPageSizeByIndexF() above. This will be deprecated in // the future. FPDF_EXPORT int FPDF_CALLCONV FPDF_GetPageSizeByIndex(FPDF_DOCUMENT document, int page_index, double* width, double* height); // Page rendering flags. They can be combined with bit-wise OR. // // Set if annotations are to be rendered. #define FPDF_ANNOT 0x01 // Set if using text rendering optimized for LCD display. This flag will only // take effect if anti-aliasing is enabled for text. #define FPDF_LCD_TEXT 0x02 // Don't use the native text output available on some platforms #define FPDF_NO_NATIVETEXT 0x04 // Grayscale output. #define FPDF_GRAYSCALE 0x08 // Obsolete, has no effect, retained for compatibility. #define FPDF_DEBUG_INFO 0x80 // Obsolete, has no effect, retained for compatibility. #define FPDF_NO_CATCH 0x100 // Limit image cache size. #define FPDF_RENDER_LIMITEDIMAGECACHE 0x200 // Always use halftone for image stretching. #define FPDF_RENDER_FORCEHALFTONE 0x400 // Render for printing. #define FPDF_PRINTING 0x800 // Set to disable anti-aliasing on text. This flag will also disable LCD // optimization for text rendering. #define FPDF_RENDER_NO_SMOOTHTEXT 0x1000 // Set to disable anti-aliasing on images. #define FPDF_RENDER_NO_SMOOTHIMAGE 0x2000 // Set to disable anti-aliasing on paths. #define FPDF_RENDER_NO_SMOOTHPATH 0x4000 // Set whether to render in a reverse Byte order, this flag is only used when // rendering to a bitmap. #define FPDF_REVERSE_BYTE_ORDER 0x10 // Set whether fill paths need to be stroked. This flag is only used when // FPDF_COLORSCHEME is passed in, since with a single fill color for paths the // boundaries of adjacent fill paths are less visible. #define FPDF_CONVERT_FILL_TO_STROKE 0x20 // Struct for color scheme. // Each should be a 32-bit value specifying the color, in 8888 ARGB format. typedef struct FPDF_COLORSCHEME_ { FPDF_DWORD path_fill_color; FPDF_DWORD path_stroke_color; FPDF_DWORD text_fill_color; FPDF_DWORD text_stroke_color; } FPDF_COLORSCHEME; #ifdef _WIN32 // Function: FPDF_RenderPage // Render contents of a page to a device (screen, bitmap, or printer). // This function is only supported on Windows. // Parameters: // dc - Handle to the device context. // page - Handle to the page. Returned by FPDF_LoadPage. // start_x - Left pixel position of the display area in // device coordinates. // start_y - Top pixel position of the display area in device // coordinates. // size_x - Horizontal size (in pixels) for displaying the page. // size_y - Vertical size (in pixels) for displaying the page. // rotate - Page orientation: // 0 (normal) // 1 (rotated 90 degrees clockwise) // 2 (rotated 180 degrees) // 3 (rotated 90 degrees counter-clockwise) // flags - 0 for normal display, or combination of flags // defined above. // Return value: // Returns true if the page is rendered successfully, false otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_RenderPage(HDC dc, FPDF_PAGE page, int start_x, int start_y, int size_x, int size_y, int rotate, int flags); #endif // Function: FPDF_RenderPageBitmap // Render contents of a page to a device independent bitmap. // Parameters: // bitmap - Handle to the device independent bitmap (as the // output buffer). The bitmap handle can be created // by FPDFBitmap_Create or retrieved from an image // object by FPDFImageObj_GetBitmap. // page - Handle to the page. Returned by FPDF_LoadPage // start_x - Left pixel position of the display area in // bitmap coordinates. // start_y - Top pixel position of the display area in bitmap // coordinates. // size_x - Horizontal size (in pixels) for displaying the page. // size_y - Vertical size (in pixels) for displaying the page. // rotate - Page orientation: // 0 (normal) // 1 (rotated 90 degrees clockwise) // 2 (rotated 180 degrees) // 3 (rotated 90 degrees counter-clockwise) // flags - 0 for normal display, or combination of the Page // Rendering flags defined above. With the FPDF_ANNOT // flag, it renders all annotations that do not require // user-interaction, which are all annotations except // widget and popup annotations. // Return value: // None. FPDF_EXPORT void FPDF_CALLCONV FPDF_RenderPageBitmap(FPDF_BITMAP bitmap, FPDF_PAGE page, int start_x, int start_y, int size_x, int size_y, int rotate, int flags); // Function: FPDF_RenderPageBitmapWithMatrix // Render contents of a page to a device independent bitmap. // Parameters: // bitmap - Handle to the device independent bitmap (as the // output buffer). The bitmap handle can be created // by FPDFBitmap_Create or retrieved by // FPDFImageObj_GetBitmap. // page - Handle to the page. Returned by FPDF_LoadPage. // matrix - The transform matrix, which must be invertible. // See PDF Reference 1.7, 4.2.2 Common Transformations. // clipping - The rect to clip to in device coords. // flags - 0 for normal display, or combination of the Page // Rendering flags defined above. With the FPDF_ANNOT // flag, it renders all annotations that do not require // user-interaction, which are all annotations except // widget and popup annotations. // Return value: // None. Note that behavior is undefined if det of |matrix| is 0. FPDF_EXPORT void FPDF_CALLCONV FPDF_RenderPageBitmapWithMatrix(FPDF_BITMAP bitmap, FPDF_PAGE page, const FS_MATRIX* matrix, const FS_RECTF* clipping, int flags); #if defined(PDF_USE_SKIA) // Experimental API. // Function: FPDF_RenderPageSkia // Render contents of a page to a Skia SkCanvas. // Parameters: // canvas - SkCanvas to render to. // page - Handle to the page. // size_x - Horizontal size (in pixels) for displaying the page. // size_y - Vertical size (in pixels) for displaying the page. // Return value: // None. FPDF_EXPORT void FPDF_CALLCONV FPDF_RenderPageSkia(FPDF_SKIA_CANVAS canvas, FPDF_PAGE page, int size_x, int size_y); #endif // Function: FPDF_ClosePage // Close a loaded PDF page. // Parameters: // page - Handle to the loaded page. // Return value: // None. FPDF_EXPORT void FPDF_CALLCONV FPDF_ClosePage(FPDF_PAGE page); // Function: FPDF_CloseDocument // Close a loaded PDF document. // Parameters: // document - Handle to the loaded document. // Return value: // None. FPDF_EXPORT void FPDF_CALLCONV FPDF_CloseDocument(FPDF_DOCUMENT document); // Function: FPDF_DeviceToPage // Convert the screen coordinates of a point to page coordinates. // Parameters: // page - Handle to the page. Returned by FPDF_LoadPage. // start_x - Left pixel position of the display area in // device coordinates. // start_y - Top pixel position of the display area in device // coordinates. // size_x - Horizontal size (in pixels) for displaying the page. // size_y - Vertical size (in pixels) for displaying the page. // rotate - Page orientation: // 0 (normal) // 1 (rotated 90 degrees clockwise) // 2 (rotated 180 degrees) // 3 (rotated 90 degrees counter-clockwise) // device_x - X value in device coordinates to be converted. // device_y - Y value in device coordinates to be converted. // page_x - A pointer to a double receiving the converted X // value in page coordinates. // page_y - A pointer to a double receiving the converted Y // value in page coordinates. // Return value: // Returns true if the conversion succeeds, and |page_x| and |page_y| // successfully receives the converted coordinates. // Comments: // The page coordinate system has its origin at the left-bottom corner // of the page, with the X-axis on the bottom going to the right, and // the Y-axis on the left side going up. // // NOTE: this coordinate system can be altered when you zoom, scroll, // or rotate a page, however, a point on the page should always have // the same coordinate values in the page coordinate system. // // The device coordinate system is device dependent. For screen device, // its origin is at the left-top corner of the window. However this // origin can be altered by the Windows coordinate transformation // utilities. // // You must make sure the start_x, start_y, size_x, size_y // and rotate parameters have exactly same values as you used in // the FPDF_RenderPage() function call. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_DeviceToPage(FPDF_PAGE page, int start_x, int start_y, int size_x, int size_y, int rotate, int device_x, int device_y, double* page_x, double* page_y); // Function: FPDF_PageToDevice // Convert the page coordinates of a point to screen coordinates. // Parameters: // page - Handle to the page. Returned by FPDF_LoadPage. // start_x - Left pixel position of the display area in // device coordinates. // start_y - Top pixel position of the display area in device // coordinates. // size_x - Horizontal size (in pixels) for displaying the page. // size_y - Vertical size (in pixels) for displaying the page. // rotate - Page orientation: // 0 (normal) // 1 (rotated 90 degrees clockwise) // 2 (rotated 180 degrees) // 3 (rotated 90 degrees counter-clockwise) // page_x - X value in page coordinates. // page_y - Y value in page coordinate. // device_x - A pointer to an integer receiving the result X // value in device coordinates. // device_y - A pointer to an integer receiving the result Y // value in device coordinates. // Return value: // Returns true if the conversion succeeds, and |device_x| and // |device_y| successfully receives the converted coordinates. // Comments: // See comments for FPDF_DeviceToPage(). FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_PageToDevice(FPDF_PAGE page, int start_x, int start_y, int size_x, int size_y, int rotate, double page_x, double page_y, int* device_x, int* device_y); // Function: FPDFBitmap_Create // Create a device independent bitmap (FXDIB). // Parameters: // width - The number of pixels in width for the bitmap. // Must be greater than 0. // height - The number of pixels in height for the bitmap. // Must be greater than 0. // alpha - A flag indicating whether the alpha channel is used. // Non-zero for using alpha, zero for not using. // Return value: // The created bitmap handle, or NULL if a parameter error or out of // memory. // Comments: // The bitmap always uses 4 bytes per pixel. The first byte is always // double word aligned. // // The byte order is BGRx (the last byte unused if no alpha channel) or // BGRA. // // The pixels in a horizontal line are stored side by side, with the // left most pixel stored first (with lower memory address). // Each line uses width * 4 bytes. // // Lines are stored one after another, with the top most line stored // first. There is no gap between adjacent lines. // // This function allocates enough memory for holding all pixels in the // bitmap, but it doesn't initialize the buffer. Applications can use // FPDFBitmap_FillRect() to fill the bitmap using any color. If the OS // allows it, this function can allocate up to 4 GB of memory. FPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV FPDFBitmap_Create(int width, int height, int alpha); // More DIB formats // Unknown or unsupported format. // All of the colors are listed in order of LSB to MSB. #define FPDFBitmap_Unknown 0 // Gray scale bitmap, one byte per pixel. #define FPDFBitmap_Gray 1 // 3 bytes per pixel, byte order: blue, green, red. #define FPDFBitmap_BGR 2 // 4 bytes per pixel, byte order: blue, green, red, unused. #define FPDFBitmap_BGRx 3 // 4 bytes per pixel, byte order: blue, green, red, alpha. // Pixel components are independent of alpha. #define FPDFBitmap_BGRA 4 // 4 bytes per pixel, byte order: blue, green, red, alpha. // Pixel components are premultiplied by alpha. // Note that this is experimental and only supported when rendering with // |FPDF_RENDERER_TYPE| is set to |FPDF_RENDERERTYPE_SKIA|. #define FPDFBitmap_BGRA_Premul 5 // Function: FPDFBitmap_CreateEx // Create a device independent bitmap (FXDIB) // Parameters: // width - The number of pixels in width for the bitmap. // Must be greater than 0. // height - The number of pixels in height for the bitmap. // Must be greater than 0. // format - A number indicating for bitmap format, as defined // above. // first_scan - A pointer to the first byte of the first line if // using an external buffer. If this parameter is NULL, // then a new buffer will be created. // stride - Number of bytes for each scan line. The value must // be 0 or greater. When the value is 0, // FPDFBitmap_CreateEx() will automatically calculate // the appropriate value using |width| and |format|. // When using an external buffer, it is recommended for // the caller to pass in the value. // When not using an external buffer, it is recommended // for the caller to pass in 0. // Return value: // The bitmap handle, or NULL if parameter error or out of memory. // Comments: // Similar to FPDFBitmap_Create function, but allows for more formats // and an external buffer is supported. The bitmap created by this // function can be used in any place that a FPDF_BITMAP handle is // required. // // If an external buffer is used, then the caller should destroy the // buffer. FPDFBitmap_Destroy() will not destroy the buffer. // // It is recommended to use FPDFBitmap_GetStride() to get the stride // value. FPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV FPDFBitmap_CreateEx(int width, int height, int format, void* first_scan, int stride); // Function: FPDFBitmap_GetFormat // Get the format of the bitmap. // Parameters: // bitmap - Handle to the bitmap. Returned by FPDFBitmap_Create // or FPDFImageObj_GetBitmap. // Return value: // The format of the bitmap. // Comments: // Only formats supported by FPDFBitmap_CreateEx are supported by this // function; see the list of such formats above. FPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetFormat(FPDF_BITMAP bitmap); // Function: FPDFBitmap_FillRect // Fill a rectangle in a bitmap. // Parameters: // bitmap - The handle to the bitmap. Returned by // FPDFBitmap_Create. // left - The left position. Starting from 0 at the // left-most pixel. // top - The top position. Starting from 0 at the // top-most line. // width - Width in pixels to be filled. // height - Height in pixels to be filled. // color - A 32-bit value specifing the color, in 8888 ARGB // format. // Return value: // Returns whether the operation succeeded or not. // Comments: // This function sets the color and (optionally) alpha value in the // specified region of the bitmap. // // NOTE: If the alpha channel is used, this function does NOT // composite the background with the source color, instead the // background will be replaced by the source color and the alpha. // // If the alpha channel is not used, the alpha parameter is ignored. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFBitmap_FillRect(FPDF_BITMAP bitmap, int left, int top, int width, int height, FPDF_DWORD color); // Function: FPDFBitmap_GetBuffer // Get data buffer of a bitmap. // Parameters: // bitmap - Handle to the bitmap. Returned by FPDFBitmap_Create // or FPDFImageObj_GetBitmap. // Return value: // The pointer to the first byte of the bitmap buffer. // Comments: // The stride may be more than width * number of bytes per pixel // // Applications can use this function to get the bitmap buffer pointer, // then manipulate any color and/or alpha values for any pixels in the // bitmap. // // Use FPDFBitmap_GetFormat() to find out the format of the data. FPDF_EXPORT void* FPDF_CALLCONV FPDFBitmap_GetBuffer(FPDF_BITMAP bitmap); // Function: FPDFBitmap_GetWidth // Get width of a bitmap. // Parameters: // bitmap - Handle to the bitmap. Returned by FPDFBitmap_Create // or FPDFImageObj_GetBitmap. // Return value: // The width of the bitmap in pixels. FPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetWidth(FPDF_BITMAP bitmap); // Function: FPDFBitmap_GetHeight // Get height of a bitmap. // Parameters: // bitmap - Handle to the bitmap. Returned by FPDFBitmap_Create // or FPDFImageObj_GetBitmap. // Return value: // The height of the bitmap in pixels. FPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetHeight(FPDF_BITMAP bitmap); // Function: FPDFBitmap_GetStride // Get number of bytes for each line in the bitmap buffer. // Parameters: // bitmap - Handle to the bitmap. Returned by FPDFBitmap_Create // or FPDFImageObj_GetBitmap. // Return value: // The number of bytes for each line in the bitmap buffer. // Comments: // The stride may be more than width * number of bytes per pixel. FPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetStride(FPDF_BITMAP bitmap); // Function: FPDFBitmap_Destroy // Destroy a bitmap and release all related buffers. // Parameters: // bitmap - Handle to the bitmap. Returned by FPDFBitmap_Create // or FPDFImageObj_GetBitmap. // Return value: // None. // Comments: // This function will not destroy any external buffers provided when // the bitmap was created. FPDF_EXPORT void FPDF_CALLCONV FPDFBitmap_Destroy(FPDF_BITMAP bitmap); // Function: FPDF_VIEWERREF_GetPrintScaling // Whether the PDF document prefers to be scaled or not. // Parameters: // document - Handle to the loaded document. // Return value: // None. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_VIEWERREF_GetPrintScaling(FPDF_DOCUMENT document); // Function: FPDF_VIEWERREF_GetNumCopies // Returns the number of copies to be printed. // Parameters: // document - Handle to the loaded document. // Return value: // The number of copies to be printed. FPDF_EXPORT int FPDF_CALLCONV FPDF_VIEWERREF_GetNumCopies(FPDF_DOCUMENT document); // Function: FPDF_VIEWERREF_GetPrintPageRange // Page numbers to initialize print dialog box when file is printed. // Parameters: // document - Handle to the loaded document. // Return value: // The print page range to be used for printing. FPDF_EXPORT FPDF_PAGERANGE FPDF_CALLCONV FPDF_VIEWERREF_GetPrintPageRange(FPDF_DOCUMENT document); // Experimental API. // Function: FPDF_VIEWERREF_GetPrintPageRangeCount // Returns the number of elements in a FPDF_PAGERANGE. // Parameters: // pagerange - Handle to the page range. // Return value: // The number of elements in the page range. Returns 0 on error. FPDF_EXPORT size_t FPDF_CALLCONV FPDF_VIEWERREF_GetPrintPageRangeCount(FPDF_PAGERANGE pagerange); // Experimental API. // Function: FPDF_VIEWERREF_GetPrintPageRangeElement // Returns an element from a FPDF_PAGERANGE. // Parameters: // pagerange - Handle to the page range. // index - Index of the element. // Return value: // The value of the element in the page range at a given index. // Returns -1 on error. FPDF_EXPORT int FPDF_CALLCONV FPDF_VIEWERREF_GetPrintPageRangeElement(FPDF_PAGERANGE pagerange, size_t index); // Function: FPDF_VIEWERREF_GetDuplex // Returns the paper handling option to be used when printing from // the print dialog. // Parameters: // document - Handle to the loaded document. // Return value: // The paper handling option to be used when printing. FPDF_EXPORT FPDF_DUPLEXTYPE FPDF_CALLCONV FPDF_VIEWERREF_GetDuplex(FPDF_DOCUMENT document); // Function: FPDF_VIEWERREF_GetName // Gets the contents for a viewer ref, with a given key. The value must // be of type "name". // Parameters: // document - Handle to the loaded document. // key - Name of the key in the viewer pref dictionary, // encoded in UTF-8. // buffer - Caller-allocate buffer to receive the key, or NULL // - to query the required length. // length - Length of the buffer. // Return value: // The number of bytes in the contents, including the NULL terminator. // Thus if the return value is 0, then that indicates an error, such // as when |document| is invalid. If |length| is less than the required // length, or |buffer| is NULL, |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_VIEWERREF_GetName(FPDF_DOCUMENT document, FPDF_BYTESTRING key, char* buffer, unsigned long length); // Function: FPDF_CountNamedDests // Get the count of named destinations in the PDF document. // Parameters: // document - Handle to a document // Return value: // The count of named destinations. FPDF_EXPORT FPDF_DWORD FPDF_CALLCONV FPDF_CountNamedDests(FPDF_DOCUMENT document); // Function: FPDF_GetNamedDestByName // Get a the destination handle for the given name. // Parameters: // document - Handle to the loaded document. // name - The name of a destination. // Return value: // The handle to the destination. FPDF_EXPORT FPDF_DEST FPDF_CALLCONV FPDF_GetNamedDestByName(FPDF_DOCUMENT document, FPDF_BYTESTRING name); // Function: FPDF_GetNamedDest // Get the named destination by index. // Parameters: // document - Handle to a document // index - The index of a named destination. // buffer - The buffer to store the destination name, // used as wchar_t*. // buflen [in/out] - Size of the buffer in bytes on input, // length of the result in bytes on output // or -1 if the buffer is too small. // Return value: // The destination handle for a given index, or NULL if there is no // named destination corresponding to |index|. // Comments: // Call this function twice to get the name of the named destination: // 1) First time pass in |buffer| as NULL and get buflen. // 2) Second time pass in allocated |buffer| and buflen to retrieve // |buffer|, which should be used as wchar_t*. // // If buflen is not sufficiently large, it will be set to -1 upon // return. FPDF_EXPORT FPDF_DEST FPDF_CALLCONV FPDF_GetNamedDest(FPDF_DOCUMENT document, int index, void* buffer, long* buflen); // Experimental API. // Function: FPDF_GetXFAPacketCount // Get the number of valid packets in the XFA entry. // Parameters: // document - Handle to the document. // Return value: // The number of valid packets, or -1 on error. FPDF_EXPORT int FPDF_CALLCONV FPDF_GetXFAPacketCount(FPDF_DOCUMENT document); // Experimental API. // Function: FPDF_GetXFAPacketName // Get the name of a packet in the XFA array. // Parameters: // document - Handle to the document. // index - Index number of the packet. 0 for the first packet. // buffer - Buffer for holding the name of the XFA packet. // buflen - Length of |buffer| in bytes. // Return value: // The length of the packet name in bytes, or 0 on error. // // |document| must be valid and |index| must be in the range [0, N), where N is // the value returned by FPDF_GetXFAPacketCount(). // |buffer| is only modified if it is non-NULL and |buflen| is greater than or // equal to the length of the packet name. The packet name includes a // terminating NUL character. |buffer| is unmodified on error. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetXFAPacketName( FPDF_DOCUMENT document, int index, void* buffer, unsigned long buflen); // Experimental API. // Function: FPDF_GetXFAPacketContent // Get the content of a packet in the XFA array. // Parameters: // document - Handle to the document. // index - Index number of the packet. 0 for the first packet. // buffer - Buffer for holding the content of the XFA packet. // buflen - Length of |buffer| in bytes. // out_buflen - Pointer to the variable that will receive the minimum // buffer size needed to contain the content of the XFA // packet. // Return value: // Whether the operation succeeded or not. // // |document| must be valid and |index| must be in the range [0, N), where N is // the value returned by FPDF_GetXFAPacketCount(). |out_buflen| must not be // NULL. When the aforementioned arguments are valid, the operation succeeds, // and |out_buflen| receives the content size. |buffer| is only modified if // |buffer| is non-null and long enough to contain the content. Callers must // check both the return value and the input |buflen| is no less than the // returned |out_buflen| before using the data in |buffer|. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_GetXFAPacketContent( FPDF_DOCUMENT document, int index, void* buffer, unsigned long buflen, unsigned long* out_buflen); #ifdef PDF_ENABLE_V8 // Function: FPDF_GetRecommendedV8Flags // Returns a space-separated string of command line flags that are // recommended to be passed into V8 via V8::SetFlagsFromString() // prior to initializing the PDFium library. // Parameters: // None. // Return value: // NUL-terminated string of the form "--flag1 --flag2". // The caller must not attempt to modify or free the result. FPDF_EXPORT const char* FPDF_CALLCONV FPDF_GetRecommendedV8Flags(); // Experimental API. // Function: FPDF_GetArrayBufferAllocatorSharedInstance() // Helper function for initializing V8 isolates that will // use PDFium's internal memory management. // Parameters: // None. // Return Value: // Pointer to a suitable v8::ArrayBuffer::Allocator, returned // as void for C compatibility. // Notes: // Use is optional, but allows external creation of isolates // matching the ones PDFium will make when none is provided // via |FPDF_LIBRARY_CONFIG::m_pIsolate|. // // Can only be called when the library is in an uninitialized or // destroyed state. FPDF_EXPORT void* FPDF_CALLCONV FPDF_GetArrayBufferAllocatorSharedInstance(); #endif // PDF_ENABLE_V8 #ifdef PDF_ENABLE_XFA // Function: FPDF_BStr_Init // Helper function to initialize a FPDF_BSTR. FPDF_EXPORT FPDF_RESULT FPDF_CALLCONV FPDF_BStr_Init(FPDF_BSTR* bstr); // Function: FPDF_BStr_Set // Helper function to copy string data into the FPDF_BSTR. FPDF_EXPORT FPDF_RESULT FPDF_CALLCONV FPDF_BStr_Set(FPDF_BSTR* bstr, const char* cstr, int length); // Function: FPDF_BStr_Clear // Helper function to clear a FPDF_BSTR. FPDF_EXPORT FPDF_RESULT FPDF_CALLCONV FPDF_BStr_Clear(FPDF_BSTR* bstr); #endif // PDF_ENABLE_XFA #ifdef __cplusplus } #endif #endif // PUBLIC_FPDFVIEW_H_ ================================================ FILE: external/pdfium/macos-x64/licenses/abseil.txt ================================================ Apache License Version 2.0, January 2004 https://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: external/pdfium/macos-x64/licenses/agg23.txt ================================================ //---------------------------------------------------------------------------- // Anti-Grain Geometry - Version 2.3 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) // // Permission to copy, use, modify, sell and distribute this software // is granted provided this copyright notice appears in all copies. // This software is provided "as is" without express or implied // warranty, and with no claim as to its suitability for any purpose. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- ================================================ FILE: external/pdfium/macos-x64/licenses/fast_float.txt ================================================ MIT License Copyright (c) 2021 The fast_float authors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: external/pdfium/macos-x64/licenses/freetype.txt ================================================ The FreeType Project LICENSE ---------------------------- 2006-Jan-27 Copyright 1996-2002, 2006 by David Turner, Robert Wilhelm, and Werner Lemberg Introduction ============ The FreeType Project is distributed in several archive packages; some of them may contain, in addition to the FreeType font engine, various tools and contributions which rely on, or relate to, the FreeType Project. This license applies to all files found in such packages, and which do not fall under their own explicit license. The license affects thus the FreeType font engine, the test programs, documentation and makefiles, at the very least. This license was inspired by the BSD, Artistic, and IJG (Independent JPEG Group) licenses, which all encourage inclusion and use of free software in commercial and freeware products alike. As a consequence, its main points are that: o We don't promise that this software works. However, we will be interested in any kind of bug reports. (`as is' distribution) o You can use this software for whatever you want, in parts or full form, without having to pay us. (`royalty-free' usage) o You may not pretend that you wrote this software. If you use it, or only parts of it, in a program, you must acknowledge somewhere in your documentation that you have used the FreeType code. (`credits') We specifically permit and encourage the inclusion of this software, with or without modifications, in commercial products. We disclaim all warranties covering The FreeType Project and assume no liability related to The FreeType Project. Finally, many people asked us for a preferred form for a credit/disclaimer to use in compliance with this license. We thus encourage you to use the following text: """ Portions of this software are copyright The FreeType Project (www.freetype.org). All rights reserved. """ Please replace with the value from the FreeType version you actually use. Legal Terms =========== 0. Definitions -------------- Throughout this license, the terms `package', `FreeType Project', and `FreeType archive' refer to the set of files originally distributed by the authors (David Turner, Robert Wilhelm, and Werner Lemberg) as the `FreeType Project', be they named as alpha, beta or final release. `You' refers to the licensee, or person using the project, where `using' is a generic term including compiling the project's source code as well as linking it to form a `program' or `executable'. This program is referred to as `a program using the FreeType engine'. This license applies to all files distributed in the original FreeType Project, including all source code, binaries and documentation, unless otherwise stated in the file in its original, unmodified form as distributed in the original archive. If you are unsure whether or not a particular file is covered by this license, you must contact us to verify this. The FreeType Project is copyright (C) 1996-2000 by David Turner, Robert Wilhelm, and Werner Lemberg. All rights reserved except as specified below. 1. No Warranty -------------- THE FREETYPE PROJECT IS PROVIDED `AS IS' WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL ANY OF THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY DAMAGES CAUSED BY THE USE OR THE INABILITY TO USE, OF THE FREETYPE PROJECT. 2. Redistribution ----------------- This license grants a worldwide, royalty-free, perpetual and irrevocable right and license to use, execute, perform, compile, display, copy, create derivative works of, distribute and sublicense the FreeType Project (in both source and object code forms) and derivative works thereof for any purpose; and to authorize others to exercise some or all of the rights granted herein, subject to the following conditions: o Redistribution of source code must retain this license file (`FTL.TXT') unaltered; any additions, deletions or changes to the original files must be clearly indicated in accompanying documentation. The copyright notices of the unaltered, original files must be preserved in all copies of source files. o Redistribution in binary form must provide a disclaimer that states that the software is based in part of the work of the FreeType Team, in the distribution documentation. We also encourage you to put an URL to the FreeType web page in your documentation, though this isn't mandatory. These conditions apply to any software derived from or based on the FreeType Project, not just the unmodified files. If you use our work, you must acknowledge us. However, no fee need be paid to us. 3. Advertising -------------- Neither the FreeType authors and contributors nor you shall use the name of the other for commercial, advertising, or promotional purposes without specific prior written permission. We suggest, but do not require, that you use one or more of the following phrases to refer to this software in your documentation or advertising materials: `FreeType Project', `FreeType Engine', `FreeType library', or `FreeType Distribution'. As you have not signed this license, you are not required to accept it. However, as the FreeType Project is copyrighted material, only this license, or another one contracted with the authors, grants you the right to use, distribute, and modify it. Therefore, by using, distributing, or modifying the FreeType Project, you indicate that you understand and accept all the terms of this license. 4. Contacts ----------- There are two mailing lists related to FreeType: o freetype@nongnu.org Discusses general use and applications of FreeType, as well as future and wanted additions to the library and distribution. If you are looking for support, start in this list if you haven't found anything to help you in the documentation. o freetype-devel@nongnu.org Discusses bugs, as well as engine internals, design issues, specific licenses, porting, etc. Our home page can be found at http://www.freetype.org --- end of FTL.TXT --- ================================================ FILE: external/pdfium/macos-x64/licenses/icu.txt ================================================ UNICODE LICENSE V3 COPYRIGHT AND PERMISSION NOTICE Copyright © 2016-2025 Unicode, Inc. NOTICE TO USER: Carefully read the following legal agreement. BY DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING DATA FILES, AND/OR SOFTWARE, YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE TERMS AND CONDITIONS OF THIS AGREEMENT. IF YOU DO NOT AGREE, DO NOT DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE THE DATA FILES OR SOFTWARE. Permission is hereby granted, free of charge, to any person obtaining a copy of data files and any associated documentation (the "Data Files") or software and any associated documentation (the "Software") to deal in the Data Files or Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, and/or sell copies of the Data Files or Software, and to permit persons to whom the Data Files or Software are furnished to do so, provided that either (a) this copyright and permission notice appear with all copies of the Data Files or Software, or (b) this copyright and permission notice appear in associated Documentation. THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE DATA FILES OR SOFTWARE. Except as contained in this notice, the name of a copyright holder shall not be used in advertising or otherwise to promote the sale, use or other dealings in these Data Files or Software without prior written authorization of the copyright holder. SPDX-License-Identifier: Unicode-3.0 ---------------------------------------------------------------------- Third-Party Software Licenses This section contains third-party software notices and/or additional terms for licensed third-party software components included within ICU libraries. ---------------------------------------------------------------------- ICU License - ICU 1.8.1 to ICU 57.1 COPYRIGHT AND PERMISSION NOTICE Copyright (c) 1995-2016 International Business Machines Corporation and others All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, provided that the above copyright notice(s) and this permission notice appear in all copies of the Software and that both the above copyright notice(s) and this permission notice appear in supporting documentation. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. Except as contained in this notice, the name of a copyright holder shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization of the copyright holder. All trademarks and registered trademarks mentioned herein are the property of their respective owners. ---------------------------------------------------------------------- Chinese/Japanese Word Break Dictionary Data (cjdict.txt) # The Google Chrome software developed by Google is licensed under # the BSD license. Other software included in this distribution is # provided under other licenses, as set forth below. # # The BSD License # http://opensource.org/licenses/bsd-license.php # Copyright (C) 2006-2008, Google Inc. # # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # Redistributions of source code must retain the above copyright notice, # this list of conditions and the following disclaimer. # Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided with # the distribution. # Neither the name of Google Inc. nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. # # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND # CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR # BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # # The word list in cjdict.txt are generated by combining three word lists # listed below with further processing for compound word breaking. The # frequency is generated with an iterative training against Google web # corpora. # # * Libtabe (Chinese) # - https://sourceforge.net/project/?group_id=1519 # - Its license terms and conditions are shown below. # # * IPADIC (Japanese) # - http://chasen.aist-nara.ac.jp/chasen/distribution.html # - Its license terms and conditions are shown below. # # ---------COPYING.libtabe ---- BEGIN-------------------- # # /* # * Copyright (c) 1999 TaBE Project. # * Copyright (c) 1999 Pai-Hsiang Hsiao. # * All rights reserved. # * # * Redistribution and use in source and binary forms, with or without # * modification, are permitted provided that the following conditions # * are met: # * # * . Redistributions of source code must retain the above copyright # * notice, this list of conditions and the following disclaimer. # * . Redistributions in binary form must reproduce the above copyright # * notice, this list of conditions and the following disclaimer in # * the documentation and/or other materials provided with the # * distribution. # * . Neither the name of the TaBE Project nor the names of its # * contributors may be used to endorse or promote products derived # * from this software without specific prior written permission. # * # * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # * REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES # * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR # * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, # * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED # * OF THE POSSIBILITY OF SUCH DAMAGE. # */ # # /* # * Copyright (c) 1999 Computer Systems and Communication Lab, # * Institute of Information Science, Academia # * Sinica. All rights reserved. # * # * Redistribution and use in source and binary forms, with or without # * modification, are permitted provided that the following conditions # * are met: # * # * . Redistributions of source code must retain the above copyright # * notice, this list of conditions and the following disclaimer. # * . Redistributions in binary form must reproduce the above copyright # * notice, this list of conditions and the following disclaimer in # * the documentation and/or other materials provided with the # * distribution. # * . Neither the name of the Computer Systems and Communication Lab # * nor the names of its contributors may be used to endorse or # * promote products derived from this software without specific # * prior written permission. # * # * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # * REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES # * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR # * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, # * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED # * OF THE POSSIBILITY OF SUCH DAMAGE. # */ # # Copyright 1996 Chih-Hao Tsai @ Beckman Institute, # University of Illinois # c-tsai4@uiuc.edu http://casper.beckman.uiuc.edu/~c-tsai4 # # ---------------COPYING.libtabe-----END-------------------------------- # # # ---------------COPYING.ipadic-----BEGIN------------------------------- # # Copyright 2000, 2001, 2002, 2003 Nara Institute of Science # and Technology. All Rights Reserved. # # Use, reproduction, and distribution of this software is permitted. # Any copy of this software, whether in its original form or modified, # must include both the above copyright notice and the following # paragraphs. # # Nara Institute of Science and Technology (NAIST), # the copyright holders, disclaims all warranties with regard to this # software, including all implied warranties of merchantability and # fitness, in no event shall NAIST be liable for # any special, indirect or consequential damages or any damages # whatsoever resulting from loss of use, data or profits, whether in an # action of contract, negligence or other tortuous action, arising out # of or in connection with the use or performance of this software. # # A large portion of the dictionary entries # originate from ICOT Free Software. The following conditions for ICOT # Free Software applies to the current dictionary as well. # # Each User may also freely distribute the Program, whether in its # original form or modified, to any third party or parties, PROVIDED # that the provisions of Section 3 ("NO WARRANTY") will ALWAYS appear # on, or be attached to, the Program, which is distributed substantially # in the same form as set out herein and that such intended # distribution, if actually made, will neither violate or otherwise # contravene any of the laws and regulations of the countries having # jurisdiction over the User or the intended distribution itself. # # NO WARRANTY # # The program was produced on an experimental basis in the course of the # research and development conducted during the project and is provided # to users as so produced on an experimental basis. Accordingly, the # program is provided without any warranty whatsoever, whether express, # implied, statutory or otherwise. The term "warranty" used herein # includes, but is not limited to, any warranty of the quality, # performance, merchantability and fitness for a particular purpose of # the program and the nonexistence of any infringement or violation of # any right of any third party. # # Each user of the program will agree and understand, and be deemed to # have agreed and understood, that there is no warranty whatsoever for # the program and, accordingly, the entire risk arising from or # otherwise connected with the program is assumed by the user. # # Therefore, neither ICOT, the copyright holder, or any other # organization that participated in or was otherwise related to the # development of the program and their respective officials, directors, # officers and other employees shall be held liable for any and all # damages, including, without limitation, general, special, incidental # and consequential damages, arising out of or otherwise in connection # with the use or inability to use the program or any product, material # or result produced or otherwise obtained by using the program, # regardless of whether they have been advised of, or otherwise had # knowledge of, the possibility of such damages at any time during the # project or thereafter. Each user will be deemed to have agreed to the # foregoing by his or her commencement of use of the program. The term # "use" as used herein includes, but is not limited to, the use, # modification, copying and distribution of the program and the # production of secondary products from the program. # # In the case where the program, whether in its original form or # modified, was distributed or delivered to or received by a user from # any person, organization or entity other than ICOT, unless it makes or # grants independently of ICOT any specific warranty to the user in # writing, such person, organization or entity, will also be exempted # from and not be held liable to the user for any such damages as noted # above as far as the program is concerned. # # ---------------COPYING.ipadic-----END---------------------------------- ---------------------------------------------------------------------- Lao Word Break Dictionary Data (laodict.txt) # Copyright (C) 2016 and later: Unicode, Inc. and others. # License & terms of use: http://www.unicode.org/copyright.html # Copyright (c) 2015 International Business Machines Corporation # and others. All Rights Reserved. # # Project: https://github.com/rober42539/lao-dictionary # Dictionary: https://github.com/rober42539/lao-dictionary/laodict.txt # License: https://github.com/rober42539/lao-dictionary/LICENSE.txt # (copied below) # # This file is derived from the above dictionary version of Nov 22, 2020 # ---------------------------------------------------------------------- # Copyright (C) 2013 Brian Eugene Wilson, Robert Martin Campbell. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # Redistributions of source code must retain the above copyright notice, this # list of conditions and the following disclaimer. Redistributions in binary # form must reproduce the above copyright notice, this list of conditions and # the following disclaimer in the documentation and/or other materials # provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, # INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED # OF THE POSSIBILITY OF SUCH DAMAGE. # -------------------------------------------------------------------------- ---------------------------------------------------------------------- Burmese Word Break Dictionary Data (burmesedict.txt) # Copyright (c) 2014 International Business Machines Corporation # and others. All Rights Reserved. # # This list is part of a project hosted at: # github.com/kanyawtech/myanmar-karen-word-lists # # -------------------------------------------------------------------------- # Copyright (c) 2013, LeRoy Benjamin Sharon # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: Redistributions of source code must retain the above # copyright notice, this list of conditions and the following # disclaimer. Redistributions in binary form must reproduce the # above copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # # Neither the name Myanmar Karen Word Lists, nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND # CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED # TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR # TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF # THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # -------------------------------------------------------------------------- ---------------------------------------------------------------------- Time Zone Database ICU uses the public domain data and code derived from Time Zone Database for its time zone support. The ownership of the TZ database is explained in BCP 175: Procedure for Maintaining the Time Zone Database section 7. # 7. Database Ownership # # The TZ database itself is not an IETF Contribution or an IETF # document. Rather it is a pre-existing and regularly updated work # that is in the public domain, and is intended to remain in the # public domain. Therefore, BCPs 78 [RFC5378] and 79 [RFC3979] do # not apply to the TZ Database or contributions that individuals make # to it. Should any claims be made and substantiated against the TZ # Database, the organization that is providing the IANA # Considerations defined in this RFC, under the memorandum of # understanding with the IETF, currently ICANN, may act in accordance # with all competent court orders. No ownership claims will be made # by ICANN or the IETF Trust on the database or the code. Any person # making a contribution to the database or code waives all rights to # future claims in that contribution or in the TZ Database. ---------------------------------------------------------------------- Google double-conversion Copyright 2006-2011, the V8 project authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Google Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- JSON parsing library (nlohmann/json) File: vendor/json/upstream/single_include/nlohmann/json.hpp (only for ICU4C) MIT License Copyright (c) 2013-2022 Niels Lohmann Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ---------------------------------------------------------------------- File: aclocal.m4 (only for ICU4C) Section: pkg.m4 - Macros to locate and utilise pkg-config. Copyright © 2004 Scott James Remnant . Copyright © 2012-2015 Dan Nicholson 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 2 of the License, or (at your option) 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. As a special exception to the GNU General Public License, if you distribute this file as part of a program that contains a configuration script generated by Autoconf, you may include it under the same distribution terms that you use for the rest of that program. (The condition for the exception is fulfilled because ICU4C includes a configuration script generated by Autoconf, namely the `configure` script.) ---------------------------------------------------------------------- File: config.guess (only for ICU4C) This file 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 (at your option) 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, see . As a special exception to the GNU General Public License, if you distribute this file as part of a program that contains a configuration script generated by Autoconf, you may include it under the same distribution terms that you use for the rest of that program. This Exception is an additional permission under section 7 of the GNU General Public License, version 3 ("GPLv3"). (The condition for the exception is fulfilled because ICU4C includes a configuration script generated by Autoconf, namely the `configure` script.) ---------------------------------------------------------------------- File: install-sh (only for ICU4C) Copyright 1991 by the Massachusetts Institute of Technology Permission to use, copy, modify, distribute, and sell this software and its documentation for any purpose is hereby granted without fee, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the name of M.I.T. not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. M.I.T. makes no representations about the suitability of this software for any purpose. It is provided "as is" without express or implied warranty. ================================================ FILE: external/pdfium/macos-x64/licenses/lcms.txt ================================================ //--------------------------------------------------------------------------------- // // Little Color Management System // Copyright (c) 1998-2023 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), // to deal in the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the Software // is furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO // THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // //--------------------------------------------------------------------------------- // // Version 2.15 // ================================================ FILE: external/pdfium/macos-x64/licenses/libjpeg_turbo.ijg ================================================ libjpeg-turbo note: This file has been modified by The libjpeg-turbo Project to include only information relevant to libjpeg-turbo, to wordsmith certain sections, and to remove impolitic language that existed in the libjpeg v8 README. It is included only for reference. Please see README.md for information specific to libjpeg-turbo. The Independent JPEG Group's JPEG software ========================================== This distribution contains a release of the Independent JPEG Group's free JPEG software. You are welcome to redistribute this software and to use it for any purpose, subject to the conditions under LEGAL ISSUES, below. This software is the work of Tom Lane, Guido Vollbeding, Philip Gladstone, Bill Allombert, Jim Boucher, Lee Crocker, Bob Friesenhahn, Ben Jackson, Julian Minguillon, Luis Ortiz, George Phillips, Davide Rossi, Ge' Weijers, and other members of the Independent JPEG Group. IJG is not affiliated with the ISO/IEC JTC1/SC29/WG1 standards committee (also known as JPEG, together with ITU-T SG16). DOCUMENTATION ROADMAP ===================== This file contains the following sections: OVERVIEW General description of JPEG and the IJG software. LEGAL ISSUES Copyright, lack of warranty, terms of distribution. REFERENCES Where to learn more about JPEG. ARCHIVE LOCATIONS Where to find newer versions of this software. FILE FORMAT WARS Software *not* to get. TO DO Plans for future IJG releases. Other documentation files in the distribution are: User documentation: doc/usage.txt Usage instructions for cjpeg, djpeg, jpegtran, rdjpgcom, and wrjpgcom. doc/*.1 Unix-style man pages for programs (same info as usage.txt). doc/wizard.txt Advanced usage instructions for JPEG wizards only. doc/change.log Version-to-version change highlights. Programmer and internal documentation: doc/libjpeg.txt How to use the JPEG library in your own programs. src/example.c Sample code for calling the JPEG library. doc/structure.txt Overview of the JPEG library's internal structure. doc/coderules.txt Coding style rules --- please read if you contribute code. Please read at least usage.txt. Some information can also be found in the JPEG FAQ (Frequently Asked Questions) article. See ARCHIVE LOCATIONS below to find out where to obtain the FAQ article. If you want to understand how the JPEG code works, we suggest reading one or more of the REFERENCES, then looking at the documentation files (in roughly the order listed) before diving into the code. OVERVIEW ======== This package contains C software to implement JPEG image encoding, decoding, and transcoding. JPEG (pronounced "jay-peg") is a standardized compression method for full-color and grayscale images. JPEG's strong suit is compressing photographic images or other types of images that have smooth color and brightness transitions between neighboring pixels. Images with sharp lines or other abrupt features may not compress well with JPEG, and a higher JPEG quality may have to be used to avoid visible compression artifacts with such images. JPEG is normally lossy, meaning that the output pixels are not necessarily identical to the input pixels. However, on photographic content and other "smooth" images, very good compression ratios can be obtained with no visible compression artifacts, and extremely high compression ratios are possible if you are willing to sacrifice image quality (by reducing the "quality" setting in the compressor.) This software implements JPEG baseline, extended-sequential, progressive, and lossless compression processes. Provision is made for supporting all variants of these processes, although some uncommon parameter settings aren't implemented yet. We have made no provision for supporting the hierarchical processes defined in the standard. We provide a set of library routines for reading and writing JPEG image files, plus two sample applications "cjpeg" and "djpeg", which use the library to perform conversion between JPEG and some other popular image file formats. The library is intended to be reused in other applications. In order to support file conversion and viewing software, we have included considerable functionality beyond the bare JPEG coding/decoding capability; for example, the color quantization modules are not strictly part of JPEG decoding, but they are essential for output to colormapped file formats. These extra functions can be compiled out of the library if not required for a particular application. We have also included "jpegtran", a utility for lossless transcoding between different JPEG processes, and "rdjpgcom" and "wrjpgcom", two simple applications for inserting and extracting textual comments in JFIF files. The emphasis in designing this software has been on achieving portability and flexibility, while also making it fast enough to be useful. In particular, the software is not intended to be read as a tutorial on JPEG. (See the REFERENCES section for introductory material.) Rather, it is intended to be reliable, portable, industrial-strength code. We do not claim to have achieved that goal in every aspect of the software, but we strive for it. We welcome the use of this software as a component of commercial products. No royalty is required, but we do ask for an acknowledgement in product documentation, as described under LEGAL ISSUES. LEGAL ISSUES ============ In plain English: 1. We don't promise that this software works. (But if you find any bugs, please let us know!) 2. You can use this software for whatever you want. You don't have to pay us. 3. You may not pretend that you wrote this software. If you use it in a program, you must acknowledge somewhere in your documentation that you've used the IJG code. In legalese: The authors make NO WARRANTY or representation, either express or implied, with respect to this software, its quality, accuracy, merchantability, or fitness for a particular purpose. This software is provided "AS IS", and you, its user, assume the entire risk as to its quality and accuracy. This software is copyright (C) 1991-2020, Thomas G. Lane, Guido Vollbeding. All Rights Reserved except as specified below. Permission is hereby granted to use, copy, modify, and distribute this software (or portions thereof) for any purpose, without fee, subject to these conditions: (1) If any part of the source code for this software is distributed, then this README file must be included, with this copyright and no-warranty notice unaltered; and any additions, deletions, or changes to the original files must be clearly indicated in accompanying documentation. (2) If only executable code is distributed, then the accompanying documentation must state that "this software is based in part on the work of the Independent JPEG Group". (3) Permission for use of this software is granted only if the user accepts full responsibility for any undesirable consequences; the authors accept NO LIABILITY for damages of any kind. These conditions apply to any software derived from or based on the IJG code, not just to the unmodified library. If you use our work, you ought to acknowledge us. Permission is NOT granted for the use of any IJG author's name or company name in advertising or publicity relating to this software or products derived from it. This software may be referred to only as "the Independent JPEG Group's software". We specifically permit and encourage the use of this software as the basis of commercial products, provided that all warranty or liability claims are assumed by the product vendor. REFERENCES ========== We recommend reading one or more of these references before trying to understand the innards of the JPEG software. The best short technical introduction to the JPEG compression algorithm is Wallace, Gregory K. "The JPEG Still Picture Compression Standard", Communications of the ACM, April 1991 (vol. 34 no. 4), pp. 30-44. (Adjacent articles in that issue discuss MPEG motion picture compression, applications of JPEG, and related topics.) If you don't have the CACM issue handy, a PDF file containing a revised version of Wallace's article is available at http://www.ijg.org/files/Wallace.JPEG.pdf. The file (actually a preprint for an article that appeared in IEEE Trans. Consumer Electronics) omits the sample images that appeared in CACM, but it includes corrections and some added material. Note: the Wallace article is copyright ACM and IEEE, and it may not be used for commercial purposes. A somewhat less technical, more leisurely introduction to JPEG can be found in "The Data Compression Book" by Mark Nelson and Jean-loup Gailly, published by M&T Books (New York), 2nd ed. 1996, ISBN 1-55851-434-1. This book provides good explanations and example C code for a multitude of compression methods including JPEG. It is an excellent source if you are comfortable reading C code but don't know much about data compression in general. The book's JPEG sample code is far from industrial-strength, but when you are ready to look at a full implementation, you've got one here... The best currently available description of JPEG is the textbook "JPEG Still Image Data Compression Standard" by William B. Pennebaker and Joan L. Mitchell, published by Van Nostrand Reinhold, 1993, ISBN 0-442-01272-1. Price US$59.95, 638 pp. The book includes the complete text of the ISO JPEG standards (DIS 10918-1 and draft DIS 10918-2). The original JPEG standard is divided into two parts, Part 1 being the actual specification, while Part 2 covers compliance testing methods. Part 1 is titled "Digital Compression and Coding of Continuous-tone Still Images, Part 1: Requirements and guidelines" and has document numbers ISO/IEC IS 10918-1, ITU-T T.81. Part 2 is titled "Digital Compression and Coding of Continuous-tone Still Images, Part 2: Compliance testing" and has document numbers ISO/IEC IS 10918-2, ITU-T T.83. The JPEG standard does not specify all details of an interchangeable file format. For the omitted details, we follow the "JFIF" conventions, revision 1.02. JFIF version 1 has been adopted as ISO/IEC 10918-5 (05/2013) and Recommendation ITU-T T.871 (05/2011): Information technology - Digital compression and coding of continuous-tone still images: JPEG File Interchange Format (JFIF). It is available as a free download in PDF file format from https://www.iso.org/standard/54989.html and http://www.itu.int/rec/T-REC-T.871. A PDF file of the older JFIF 1.02 specification is available at http://www.w3.org/Graphics/JPEG/jfif3.pdf. The TIFF 6.0 file format specification can be obtained from http://mirrors.ctan.org/graphics/tiff/TIFF6.ps.gz. The JPEG incorporation scheme found in the TIFF 6.0 spec of 3-June-92 has a number of serious problems. IJG does not recommend use of the TIFF 6.0 design (TIFF Compression tag 6). Instead, we recommend the JPEG design proposed by TIFF Technical Note #2 (Compression tag 7). Copies of this Note can be obtained from http://www.ijg.org/files/. It is expected that the next revision of the TIFF spec will replace the 6.0 JPEG design with the Note's design. Although IJG's own code does not support TIFF/JPEG, the free libtiff library uses our library to implement TIFF/JPEG per the Note. ARCHIVE LOCATIONS ================= The "official" archive site for this software is www.ijg.org. The most recent released version can always be found there in directory "files". The JPEG FAQ (Frequently Asked Questions) article is a source of some general information about JPEG. It is available at http://www.faqs.org/faqs/jpeg-faq. FILE FORMAT COMPATIBILITY ========================= This software implements ITU T.81 | ISO/IEC 10918 with some extensions from ITU T.871 | ISO/IEC 10918-5 (JPEG File Interchange Format-- see REFERENCES). Informally, the term "JPEG image" or "JPEG file" most often refers to JFIF or a subset thereof, but there are other formats containing the name "JPEG" that are incompatible with the original JPEG standard or with JFIF (for instance, JPEG 2000 and JPEG XR). This software therefore does not support these formats. Indeed, one of the original reasons for developing this free software was to help force convergence on a common, interoperable format standard for JPEG files. JFIF is a minimal or "low end" representation. TIFF/JPEG (TIFF revision 6.0 as modified by TIFF Technical Note #2) can be used for "high end" applications that need to record a lot of additional data about an image. TO DO ===== Please send bug reports, offers of help, etc. to jpeg-info@jpegclub.org. ================================================ FILE: external/pdfium/macos-x64/licenses/libjpeg_turbo.md ================================================ libjpeg-turbo Licenses ====================== libjpeg-turbo is covered by two compatible BSD-style open source licenses: - The IJG (Independent JPEG Group) License, which is listed in [README.ijg](README.ijg) This license applies to the libjpeg API library and associated programs, including any code inherited from libjpeg and any modifications to that code. Note that the libjpeg-turbo SIMD source code bears the [zlib License](https://opensource.org/licenses/Zlib), but in the context of the overall libjpeg API library, the terms of the zlib License are subsumed by the terms of the IJG License. - The Modified (3-clause) BSD License, which is listed below This license applies to the TurboJPEG API library and associated programs, as well as the build system. Note that the TurboJPEG API library wraps the libjpeg API library, so in the context of the overall TurboJPEG API library, both the terms of the IJG License and the terms of the Modified (3-clause) BSD License apply. Complying with the libjpeg-turbo Licenses ========================================= This section provides a roll-up of the libjpeg-turbo licensing terms, to the best of our understanding. This is not a license in and of itself. It is intended solely for clarification. 1. If you are distributing a modified version of the libjpeg-turbo source, then: 1. You cannot alter or remove any existing copyright or license notices from the source. **Origin** - Clause 1 of the IJG License - Clause 1 of the Modified BSD License - Clauses 1 and 3 of the zlib License 2. You must add your own copyright notice to the header of each source file you modified, so others can tell that you modified that file. (If there is not an existing copyright header in that file, then you can simply add a notice stating that you modified the file.) **Origin** - Clause 1 of the IJG License - Clause 2 of the zlib License 3. You must include the IJG README file, and you must not alter any of the copyright or license text in that file. **Origin** - Clause 1 of the IJG License 2. If you are distributing only libjpeg-turbo binaries without the source, or if you are distributing an application that statically links with libjpeg-turbo, then: 1. Your product documentation must include a message stating: This software is based in part on the work of the Independent JPEG Group. **Origin** - Clause 2 of the IJG license 2. If your binary distribution includes or uses the TurboJPEG API, then your product documentation must include the text of the Modified BSD License (see below.) **Origin** - Clause 2 of the Modified BSD License 3. You cannot use the name of the IJG or The libjpeg-turbo Project or the contributors thereof in advertising, publicity, etc. **Origin** - IJG License - Clause 3 of the Modified BSD License 4. The IJG and The libjpeg-turbo Project do not warrant libjpeg-turbo to be free of defects, nor do we accept any liability for undesirable consequences resulting from your use of the software. **Origin** - IJG License - Modified BSD License - zlib License The Modified (3-clause) BSD License =================================== Copyright (C)2009-2024 D. R. Commander. All Rights Reserved.
Copyright (C)2015 Viktor Szathmáry. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - Neither the name of the libjpeg-turbo Project nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Why Two Licenses? ================= The zlib License could have been used instead of the Modified (3-clause) BSD License, and since the IJG License effectively subsumes the distribution conditions of the zlib License, this would have effectively placed libjpeg-turbo binary distributions under the IJG License. However, the IJG License specifically refers to the Independent JPEG Group and does not extend attribution and endorsement protections to other entities. Thus, it was desirable to choose a license that granted us the same protections for new code that were granted to the IJG for code derived from their software. ================================================ FILE: external/pdfium/macos-x64/licenses/libopenjpeg.txt ================================================ /* * The copyright in this software is being made available under the 2-clauses * BSD License, included below. This software may be subject to other third * party and contributor rights, including patent rights, and no such rights * are granted under this license. * * Copyright (c) 2005, Herve Drolon, FreeImage Team * Copyright (c) 2008, 2011-2012, Centre National d'Etudes Spatiales (CNES), FR * Copyright (c) 2012, CS Systemes d'Information, France * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ ================================================ FILE: external/pdfium/macos-x64/licenses/libpng.txt ================================================ COPYRIGHT NOTICE, DISCLAIMER, and LICENSE ========================================= PNG Reference Library License version 2 --------------------------------------- * Copyright (c) 1995-2019 The PNG Reference Library Authors. * Copyright (c) 2018-2019 Cosmin Truta. * Copyright (c) 2000-2002, 2004, 2006-2018 Glenn Randers-Pehrson. * Copyright (c) 1996-1997 Andreas Dilger. * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. The software is supplied "as is", without warranty of any kind, express or implied, including, without limitation, the warranties of merchantability, fitness for a particular purpose, title, and non-infringement. In no event shall the Copyright owners, or anyone distributing the software, be liable for any damages or other liability, whether in contract, tort or otherwise, arising from, out of, or in connection with the software, or the use or other dealings in the software, even if advised of the possibility of such damage. Permission is hereby granted to use, copy, modify, and distribute this software, or portions hereof, for any purpose, without fee, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated, but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This Copyright notice may not be removed or altered from any source or altered source distribution. PNG Reference Library License version 1 (for libpng 0.5 through 1.6.35) ----------------------------------------------------------------------- libpng versions 1.0.7, July 1, 2000, through 1.6.35, July 15, 2018 are Copyright (c) 2000-2002, 2004, 2006-2018 Glenn Randers-Pehrson, are derived from libpng-1.0.6, and are distributed according to the same disclaimer and license as libpng-1.0.6 with the following individuals added to the list of Contributing Authors: Simon-Pierre Cadieux Eric S. Raymond Mans Rullgard Cosmin Truta Gilles Vollant James Yu Mandar Sahastrabuddhe Google Inc. Vadim Barkov and with the following additions to the disclaimer: There is no warranty against interference with your enjoyment of the library or against infringement. There is no warranty that our efforts or the library will fulfill any of your particular purposes or needs. This library is provided with all faults, and the entire risk of satisfactory quality, performance, accuracy, and effort is with the user. Some files in the "contrib" directory and some configure-generated files that are distributed with libpng have other copyright owners, and are released under other open source licenses. libpng versions 0.97, January 1998, through 1.0.6, March 20, 2000, are Copyright (c) 1998-2000 Glenn Randers-Pehrson, are derived from libpng-0.96, and are distributed according to the same disclaimer and license as libpng-0.96, with the following individuals added to the list of Contributing Authors: Tom Lane Glenn Randers-Pehrson Willem van Schaik libpng versions 0.89, June 1996, through 0.96, May 1997, are Copyright (c) 1996-1997 Andreas Dilger, are derived from libpng-0.88, and are distributed according to the same disclaimer and license as libpng-0.88, with the following individuals added to the list of Contributing Authors: John Bowler Kevin Bracey Sam Bushell Magnus Holmgren Greg Roelofs Tom Tanner Some files in the "scripts" directory have other copyright owners, but are released under this license. libpng versions 0.5, May 1995, through 0.88, January 1996, are Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. For the purposes of this copyright and license, "Contributing Authors" is defined as the following set of individuals: Andreas Dilger Dave Martindale Guy Eric Schalnat Paul Schmidt Tim Wegner The PNG Reference Library is supplied "AS IS". The Contributing Authors and Group 42, Inc. disclaim all warranties, expressed or implied, including, without limitation, the warranties of merchantability and of fitness for any purpose. The Contributing Authors and Group 42, Inc. assume no liability for direct, indirect, incidental, special, exemplary, or consequential damages, which may result from the use of the PNG Reference Library, even if advised of the possibility of such damage. Permission is hereby granted to use, copy, modify, and distribute this source code, or portions hereof, for any purpose, without fee, subject to the following restrictions: 1. The origin of this source code must not be misrepresented. 2. Altered versions must be plainly marked as such and must not be misrepresented as being the original source. 3. This Copyright notice may not be removed or altered from any source or altered source distribution. The Contributing Authors and Group 42, Inc. specifically permit, without fee, and encourage the use of this source code as a component to supporting the PNG file format in commercial products. If you use this source code in a product, acknowledgment is not required but would be appreciated. ================================================ FILE: external/pdfium/macos-x64/licenses/libtiff.txt ================================================ Copyright (c) 1988-1997 Sam Leffler Copyright (c) 1991-1997 Silicon Graphics, Inc. Permission to use, copy, modify, distribute, and sell this software and its documentation for any purpose is hereby granted without fee, provided that (i) the above copyright notices and this permission notice appear in all copies of the software and related documentation, and (ii) the names of Sam Leffler and Silicon Graphics may not be used in any advertising or publicity relating to the software without the specific, prior written permission of Sam Leffler and Silicon Graphics. THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ================================================ FILE: external/pdfium/macos-x64/licenses/llvm-libc.txt ================================================ ============================================================================== The LLVM Project is under the Apache License v2.0 with LLVM Exceptions: ============================================================================== Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ---- LLVM Exceptions to the Apache 2.0 License ---- As an exception, if, as a result of your compiling your source code, portions of this Software are embedded into an Object form of such source code, you may redistribute such embedded portions in such Object form without complying with the conditions of Sections 4(a), 4(b) and 4(d) of the License. In addition, if you combine or link compiled forms of this Software with software that is licensed under the GPLv2 ("Combined Software") and if a court of competent jurisdiction determines that the patent provision (Section 3), the indemnity provision (Section 9) or other Section of the License conflicts with the conditions of the GPLv2, you may retroactively and prospectively choose to deem waived or otherwise exclude such Section(s) of the License, but only in their entirety and only with respect to the Combined Software. ============================================================================== Software from third parties included in the LLVM Project: ============================================================================== The LLVM Project contains third party software which is under different license terms. All such code will be identified clearly using at least one of two mechanisms: 1) It will be in a separate directory tree with its own `LICENSE.txt` or `LICENSE` file at the top containing the specific license and restrictions which apply to that software, or 2) It will contain specific license and restriction terms at the top of every file. ============================================================================== Legacy LLVM License (https://llvm.org/docs/DeveloperPolicy.html#legacy): ============================================================================== University of Illinois/NCSA Open Source License Copyright (c) 2007-2019 University of Illinois at Urbana-Champaign. All rights reserved. Developed by: LLVM Team University of Illinois at Urbana-Champaign http://llvm.org Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal with the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimers. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimers in the documentation and/or other materials provided with the distribution. * Neither the names of the LLVM Team, University of Illinois at Urbana-Champaign, nor the names of its contributors may be used to endorse or promote products derived from this Software without specific prior written permission. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE. ================================================ FILE: external/pdfium/macos-x64/licenses/pdfium.txt ================================================ // Copyright 2014 The PDFium Authors // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Apache License Version 2.0, January 2004 https://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: external/pdfium/macos-x64/licenses/simdutf.txt ================================================ Copyright 2021 The simdutf authors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: external/pdfium/macos-x64/licenses/zlib.txt ================================================ /* zlib.h -- interface of the 'zlib' general purpose compression library version 1.3.1, January 22nd, 2024 Copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. Jean-loup Gailly Mark Adler jloup@gzip.org madler@alumni.caltech.edu The data format used by the zlib library is described by RFCs (Request for Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950 (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format). */ ================================================ FILE: external/pdfium/windows-x64/LICENSE ================================================ Copyright 2014-2025 Benoit Blanchon Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. This package also includes third-party software. See the licenses/ directory for their respective licenses. ================================================ FILE: external/pdfium/windows-x64/PDFiumConfig.cmake ================================================ # PDFium Package Configuration for CMake # # To use PDFium in your CMake project: # # 1. set the environment variable PDFium_DIR to the folder containing this file. # 2. in your CMakeLists.txt, add # find_package(PDFium) # 3. then link your executable with PDFium # target_link_libraries(my_exe pdfium) include(FindPackageHandleStandardArgs) find_path(PDFium_INCLUDE_DIR NAMES "fpdfview.h" PATHS "${CMAKE_CURRENT_LIST_DIR}" PATH_SUFFIXES "include" ) set(PDFium_VERSION "147.0.7713.0") if(WIN32) find_file(PDFium_LIBRARY NAMES "pdfium.dll" PATHS "${CMAKE_CURRENT_LIST_DIR}" PATH_SUFFIXES "bin") find_file(PDFium_IMPLIB NAMES "pdfium.dll.lib" PATHS "${CMAKE_CURRENT_LIST_DIR}" PATH_SUFFIXES "lib") add_library(pdfium SHARED IMPORTED) set_target_properties(pdfium PROPERTIES IMPORTED_LOCATION "${PDFium_LIBRARY}" IMPORTED_IMPLIB "${PDFium_IMPLIB}" INTERFACE_INCLUDE_DIRECTORIES "${PDFium_INCLUDE_DIR};${PDFium_INCLUDE_DIR}/cpp" ) find_package_handle_standard_args(PDFium REQUIRED_VARS PDFium_LIBRARY PDFium_IMPLIB PDFium_INCLUDE_DIR VERSION_VAR PDFium_VERSION ) else() find_library(PDFium_LIBRARY NAMES "pdfium" PATHS "${CMAKE_CURRENT_LIST_DIR}" PATH_SUFFIXES "lib") add_library(pdfium SHARED IMPORTED) set_target_properties(pdfium PROPERTIES IMPORTED_LOCATION "${PDFium_LIBRARY}" INTERFACE_INCLUDE_DIRECTORIES "${PDFium_INCLUDE_DIR};${PDFium_INCLUDE_DIR}/cpp" ) find_package_handle_standard_args(PDFium REQUIRED_VARS PDFium_LIBRARY PDFium_INCLUDE_DIR VERSION_VAR PDFium_VERSION ) endif() ================================================ FILE: external/pdfium/windows-x64/VERSION ================================================ MAJOR=147 MINOR=0 BUILD=7713 PATCH=0 ================================================ FILE: external/pdfium/windows-x64/args.gn ================================================ is_component_build = false is_debug = false pdf_enable_v8 = false pdf_enable_xfa = false pdf_is_standalone = true pdf_use_partition_alloc = false target_cpu = "x64" target_os = "win" treat_warnings_as_errors = false ================================================ FILE: external/pdfium/windows-x64/include/cpp/fpdf_deleters.h ================================================ // Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef PUBLIC_CPP_FPDF_DELETERS_H_ #define PUBLIC_CPP_FPDF_DELETERS_H_ #include "../fpdf_annot.h" #include "../fpdf_dataavail.h" #include "../fpdf_edit.h" #include "../fpdf_formfill.h" #include "../fpdf_javascript.h" #include "../fpdf_structtree.h" #include "../fpdf_text.h" #include "../fpdf_transformpage.h" #include "../fpdfview.h" // Custom deleters for using FPDF_* types with std::unique_ptr<>. struct FPDFAnnotationDeleter { inline void operator()(FPDF_ANNOTATION annot) { FPDFPage_CloseAnnot(annot); } }; struct FPDFAvailDeleter { inline void operator()(FPDF_AVAIL avail) { FPDFAvail_Destroy(avail); } }; struct FPDFBitmapDeleter { inline void operator()(FPDF_BITMAP bitmap) { FPDFBitmap_Destroy(bitmap); } }; struct FPDFClipPathDeleter { inline void operator()(FPDF_CLIPPATH clip_path) { FPDF_DestroyClipPath(clip_path); } }; struct FPDFDocumentDeleter { inline void operator()(FPDF_DOCUMENT doc) { FPDF_CloseDocument(doc); } }; struct FPDFFontDeleter { inline void operator()(FPDF_FONT font) { FPDFFont_Close(font); } }; struct FPDFFormHandleDeleter { inline void operator()(FPDF_FORMHANDLE form) { FPDFDOC_ExitFormFillEnvironment(form); } }; struct FPDFJavaScriptActionDeleter { inline void operator()(FPDF_JAVASCRIPT_ACTION javascript) { FPDFDoc_CloseJavaScriptAction(javascript); } }; struct FPDFPageDeleter { inline void operator()(FPDF_PAGE page) { FPDF_ClosePage(page); } }; struct FPDFPageLinkDeleter { inline void operator()(FPDF_PAGELINK pagelink) { FPDFLink_CloseWebLinks(pagelink); } }; struct FPDFPageObjectDeleter { inline void operator()(FPDF_PAGEOBJECT object) { FPDFPageObj_Destroy(object); } }; struct FPDFStructTreeDeleter { inline void operator()(FPDF_STRUCTTREE tree) { FPDF_StructTree_Close(tree); } }; struct FPDFTextFindDeleter { inline void operator()(FPDF_SCHHANDLE handle) { FPDFText_FindClose(handle); } }; struct FPDFTextPageDeleter { inline void operator()(FPDF_TEXTPAGE text) { FPDFText_ClosePage(text); } }; #endif // PUBLIC_CPP_FPDF_DELETERS_H_ ================================================ FILE: external/pdfium/windows-x64/include/cpp/fpdf_scopers.h ================================================ // Copyright 2018 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef PUBLIC_CPP_FPDF_SCOPERS_H_ #define PUBLIC_CPP_FPDF_SCOPERS_H_ #include #include #include "fpdf_deleters.h" // Versions of FPDF types that clean up the object at scope exit. using ScopedFPDFAnnotation = std::unique_ptr::type, FPDFAnnotationDeleter>; using ScopedFPDFAvail = std::unique_ptr::type, FPDFAvailDeleter>; using ScopedFPDFBitmap = std::unique_ptr::type, FPDFBitmapDeleter>; using ScopedFPDFClipPath = std::unique_ptr::type, FPDFClipPathDeleter>; using ScopedFPDFDocument = std::unique_ptr::type, FPDFDocumentDeleter>; using ScopedFPDFFont = std::unique_ptr::type, FPDFFontDeleter>; using ScopedFPDFFormHandle = std::unique_ptr::type, FPDFFormHandleDeleter>; using ScopedFPDFJavaScriptAction = std::unique_ptr::type, FPDFJavaScriptActionDeleter>; using ScopedFPDFPage = std::unique_ptr::type, FPDFPageDeleter>; using ScopedFPDFPageLink = std::unique_ptr::type, FPDFPageLinkDeleter>; using ScopedFPDFPageObject = std::unique_ptr::type, FPDFPageObjectDeleter>; using ScopedFPDFStructTree = std::unique_ptr::type, FPDFStructTreeDeleter>; using ScopedFPDFTextFind = std::unique_ptr::type, FPDFTextFindDeleter>; using ScopedFPDFTextPage = std::unique_ptr::type, FPDFTextPageDeleter>; #endif // PUBLIC_CPP_FPDF_SCOPERS_H_ ================================================ FILE: external/pdfium/windows-x64/include/fpdf_annot.h ================================================ // Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef PUBLIC_FPDF_ANNOT_H_ #define PUBLIC_FPDF_ANNOT_H_ #include // NOLINTNEXTLINE(build/include) #include "fpdfview.h" // NOLINTNEXTLINE(build/include) #include "fpdf_formfill.h" #ifdef __cplusplus extern "C" { #endif // __cplusplus #define FPDF_ANNOT_UNKNOWN 0 #define FPDF_ANNOT_TEXT 1 #define FPDF_ANNOT_LINK 2 #define FPDF_ANNOT_FREETEXT 3 #define FPDF_ANNOT_LINE 4 #define FPDF_ANNOT_SQUARE 5 #define FPDF_ANNOT_CIRCLE 6 #define FPDF_ANNOT_POLYGON 7 #define FPDF_ANNOT_POLYLINE 8 #define FPDF_ANNOT_HIGHLIGHT 9 #define FPDF_ANNOT_UNDERLINE 10 #define FPDF_ANNOT_SQUIGGLY 11 #define FPDF_ANNOT_STRIKEOUT 12 #define FPDF_ANNOT_STAMP 13 #define FPDF_ANNOT_CARET 14 #define FPDF_ANNOT_INK 15 #define FPDF_ANNOT_POPUP 16 #define FPDF_ANNOT_FILEATTACHMENT 17 #define FPDF_ANNOT_SOUND 18 #define FPDF_ANNOT_MOVIE 19 #define FPDF_ANNOT_WIDGET 20 #define FPDF_ANNOT_SCREEN 21 #define FPDF_ANNOT_PRINTERMARK 22 #define FPDF_ANNOT_TRAPNET 23 #define FPDF_ANNOT_WATERMARK 24 #define FPDF_ANNOT_THREED 25 #define FPDF_ANNOT_RICHMEDIA 26 #define FPDF_ANNOT_XFAWIDGET 27 #define FPDF_ANNOT_REDACT 28 // Refer to PDF Reference (6th edition) table 8.16 for all annotation flags. #define FPDF_ANNOT_FLAG_NONE 0 #define FPDF_ANNOT_FLAG_INVISIBLE (1 << 0) #define FPDF_ANNOT_FLAG_HIDDEN (1 << 1) #define FPDF_ANNOT_FLAG_PRINT (1 << 2) #define FPDF_ANNOT_FLAG_NOZOOM (1 << 3) #define FPDF_ANNOT_FLAG_NOROTATE (1 << 4) #define FPDF_ANNOT_FLAG_NOVIEW (1 << 5) #define FPDF_ANNOT_FLAG_READONLY (1 << 6) #define FPDF_ANNOT_FLAG_LOCKED (1 << 7) #define FPDF_ANNOT_FLAG_TOGGLENOVIEW (1 << 8) #define FPDF_ANNOT_APPEARANCEMODE_NORMAL 0 #define FPDF_ANNOT_APPEARANCEMODE_ROLLOVER 1 #define FPDF_ANNOT_APPEARANCEMODE_DOWN 2 #define FPDF_ANNOT_APPEARANCEMODE_COUNT 3 // Refer to PDF Reference version 1.7 table 8.70 for field flags common to all // interactive form field types. #define FPDF_FORMFLAG_NONE 0 #define FPDF_FORMFLAG_READONLY (1 << 0) #define FPDF_FORMFLAG_REQUIRED (1 << 1) #define FPDF_FORMFLAG_NOEXPORT (1 << 2) // Refer to PDF Reference version 1.7 table 8.77 for field flags specific to // interactive form text fields. #define FPDF_FORMFLAG_TEXT_MULTILINE (1 << 12) #define FPDF_FORMFLAG_TEXT_PASSWORD (1 << 13) // Refer to PDF Reference version 1.7 table 8.79 for field flags specific to // interactive form choice fields. #define FPDF_FORMFLAG_CHOICE_COMBO (1 << 17) #define FPDF_FORMFLAG_CHOICE_EDIT (1 << 18) #define FPDF_FORMFLAG_CHOICE_MULTI_SELECT (1 << 21) // Additional actions type of form field: // K, on key stroke, JavaScript action. // F, on format, JavaScript action. // V, on validate, JavaScript action. // C, on calculate, JavaScript action. #define FPDF_ANNOT_AACTION_KEY_STROKE 12 #define FPDF_ANNOT_AACTION_FORMAT 13 #define FPDF_ANNOT_AACTION_VALIDATE 14 #define FPDF_ANNOT_AACTION_CALCULATE 15 typedef enum FPDFANNOT_COLORTYPE { FPDFANNOT_COLORTYPE_Color = 0, FPDFANNOT_COLORTYPE_InteriorColor } FPDFANNOT_COLORTYPE; // Experimental API. // Check if an annotation subtype is currently supported for creation. // Currently supported subtypes: // - circle // - fileattachment // - freetext // - highlight // - ink // - link // - popup // - square, // - squiggly // - stamp // - strikeout // - text // - underline // // subtype - the subtype to be checked. // // Returns true if this subtype supported. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_IsSupportedSubtype(FPDF_ANNOTATION_SUBTYPE subtype); // Experimental API. // Create an annotation in |page| of the subtype |subtype|. If the specified // subtype is illegal or unsupported, then a new annotation will not be created. // Must call FPDFPage_CloseAnnot() when the annotation returned by this // function is no longer needed. // // page - handle to a page. // subtype - the subtype of the new annotation. // // Returns a handle to the new annotation object, or NULL on failure. FPDF_EXPORT FPDF_ANNOTATION FPDF_CALLCONV FPDFPage_CreateAnnot(FPDF_PAGE page, FPDF_ANNOTATION_SUBTYPE subtype); // Experimental API. // Get the number of annotations in |page|. // // page - handle to a page. // // Returns the number of annotations in |page|. FPDF_EXPORT int FPDF_CALLCONV FPDFPage_GetAnnotCount(FPDF_PAGE page); // Experimental API. // Get annotation in |page| at |index|. Must call FPDFPage_CloseAnnot() when the // annotation returned by this function is no longer needed. // // page - handle to a page. // index - the index of the annotation. // // Returns a handle to the annotation object, or NULL on failure. FPDF_EXPORT FPDF_ANNOTATION FPDF_CALLCONV FPDFPage_GetAnnot(FPDF_PAGE page, int index); // Experimental API. // Get the index of |annot| in |page|. This is the opposite of // FPDFPage_GetAnnot(). // // page - handle to the page that the annotation is on. // annot - handle to an annotation. // // Returns the index of |annot|, or -1 on failure. FPDF_EXPORT int FPDF_CALLCONV FPDFPage_GetAnnotIndex(FPDF_PAGE page, FPDF_ANNOTATION annot); // Experimental API. // Close an annotation. Must be called when the annotation returned by // FPDFPage_CreateAnnot() or FPDFPage_GetAnnot() is no longer needed. This // function does not remove the annotation from the document. // // annot - handle to an annotation. FPDF_EXPORT void FPDF_CALLCONV FPDFPage_CloseAnnot(FPDF_ANNOTATION annot); // Experimental API. // Remove the annotation in |page| at |index|. // // page - handle to a page. // index - the index of the annotation. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_RemoveAnnot(FPDF_PAGE page, int index); // Experimental API. // Get the subtype of an annotation. // // annot - handle to an annotation. // // Returns the annotation subtype. FPDF_EXPORT FPDF_ANNOTATION_SUBTYPE FPDF_CALLCONV FPDFAnnot_GetSubtype(FPDF_ANNOTATION annot); // Experimental API. // Check if an annotation subtype is currently supported for object extraction, // update, and removal. // Currently supported subtypes: ink and stamp. // // subtype - the subtype to be checked. // // Returns true if this subtype supported. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_IsObjectSupportedSubtype(FPDF_ANNOTATION_SUBTYPE subtype); // Experimental API. // Update |obj| in |annot|. |obj| must be in |annot| already and must have // been retrieved by FPDFAnnot_GetObject(). Currently, only ink and stamp // annotations are supported by this API. Also note that only path, image, and // text objects have APIs for modification; see FPDFPath_*(), FPDFText_*(), and // FPDFImageObj_*(). // // annot - handle to an annotation. // obj - handle to the object that |annot| needs to update. // // Return true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_UpdateObject(FPDF_ANNOTATION annot, FPDF_PAGEOBJECT obj); // Experimental API. // Add a new InkStroke, represented by an array of points, to the InkList of // |annot|. The API creates an InkList if one doesn't already exist in |annot|. // This API works only for ink annotations. Please refer to ISO 32000-1:2008 // spec, section 12.5.6.13. // // annot - handle to an annotation. // points - pointer to a FS_POINTF array representing input points. // point_count - number of elements in |points| array. This should not exceed // the maximum value that can be represented by an int32_t). // // Returns the 0-based index at which the new InkStroke is added in the InkList // of the |annot|. Returns -1 on failure. FPDF_EXPORT int FPDF_CALLCONV FPDFAnnot_AddInkStroke(FPDF_ANNOTATION annot, const FS_POINTF* points, size_t point_count); // Experimental API. // Removes an InkList in |annot|. // This API works only for ink annotations. // // annot - handle to an annotation. // // Return true on successful removal of /InkList entry from context of the // non-null ink |annot|. Returns false on failure. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_RemoveInkList(FPDF_ANNOTATION annot); // Experimental API. // Add |obj| to |annot|. |obj| must have been created by // FPDFPageObj_CreateNew{Path|Rect}() or FPDFPageObj_New{Text|Image}Obj(), and // will be owned by |annot|. Note that an |obj| cannot belong to more than one // |annot|. Currently, only ink and stamp annotations are supported by this API. // Also note that only path, image, and text objects have APIs for creation. // // annot - handle to an annotation. // obj - handle to the object that is to be added to |annot|. // // Return true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_AppendObject(FPDF_ANNOTATION annot, FPDF_PAGEOBJECT obj); // Experimental API. // Get the total number of objects in |annot|, including path objects, text // objects, external objects, image objects, and shading objects. // // annot - handle to an annotation. // // Returns the number of objects in |annot|. FPDF_EXPORT int FPDF_CALLCONV FPDFAnnot_GetObjectCount(FPDF_ANNOTATION annot); // Experimental API. // Get the object in |annot| at |index|. // // annot - handle to an annotation. // index - the index of the object. // // Return a handle to the object, or NULL on failure. FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV FPDFAnnot_GetObject(FPDF_ANNOTATION annot, int index); // Experimental API. // Remove the object in |annot| at |index|. // // annot - handle to an annotation. // index - the index of the object to be removed. // // Return true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_RemoveObject(FPDF_ANNOTATION annot, int index); // Experimental API. // Set the color of an annotation. Fails when called on annotations with // appearance streams already defined; instead use // FPDFPageObj_Set{Stroke|Fill}Color(). // // annot - handle to an annotation. // type - type of the color to be set. // R, G, B - buffer to hold the RGB value of the color. Ranges from 0 to 255. // A - buffer to hold the opacity. Ranges from 0 to 255. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetColor(FPDF_ANNOTATION annot, FPDFANNOT_COLORTYPE type, unsigned int R, unsigned int G, unsigned int B, unsigned int A); // Experimental API. // Get the color of an annotation. If no color is specified, default to yellow // for highlight annotation, black for all else. Fails when called on // annotations with appearance streams already defined; instead use // FPDFPageObj_Get{Stroke|Fill}Color(). // // annot - handle to an annotation. // type - type of the color requested. // R, G, B - buffer to hold the RGB value of the color. Ranges from 0 to 255. // A - buffer to hold the opacity. Ranges from 0 to 255. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_GetColor(FPDF_ANNOTATION annot, FPDFANNOT_COLORTYPE type, unsigned int* R, unsigned int* G, unsigned int* B, unsigned int* A); // Experimental API. // Check if the annotation is of a type that has attachment points // (i.e. quadpoints). Quadpoints are the vertices of the rectangle that // encompasses the texts affected by the annotation. They provide the // coordinates in the page where the annotation is attached. Only text markup // annotations (i.e. highlight, strikeout, squiggly, and underline) and link // annotations have quadpoints. // // annot - handle to an annotation. // // Returns true if the annotation is of a type that has quadpoints, false // otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_HasAttachmentPoints(FPDF_ANNOTATION annot); // Experimental API. // Replace the attachment points (i.e. quadpoints) set of an annotation at // |quad_index|. This index needs to be within the result of // FPDFAnnot_CountAttachmentPoints(). // If the annotation's appearance stream is defined and this annotation is of a // type with quadpoints, then update the bounding box too if the new quadpoints // define a bigger one. // // annot - handle to an annotation. // quad_index - index of the set of quadpoints. // quad_points - the quadpoints to be set. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetAttachmentPoints(FPDF_ANNOTATION annot, size_t quad_index, const FS_QUADPOINTSF* quad_points); // Experimental API. // Append to the list of attachment points (i.e. quadpoints) of an annotation. // If the annotation's appearance stream is defined and this annotation is of a // type with quadpoints, then update the bounding box too if the new quadpoints // define a bigger one. // // annot - handle to an annotation. // quad_points - the quadpoints to be set. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_AppendAttachmentPoints(FPDF_ANNOTATION annot, const FS_QUADPOINTSF* quad_points); // Experimental API. // Get the number of sets of quadpoints of an annotation. // // annot - handle to an annotation. // // Returns the number of sets of quadpoints, or 0 on failure. FPDF_EXPORT size_t FPDF_CALLCONV FPDFAnnot_CountAttachmentPoints(FPDF_ANNOTATION annot); // Experimental API. // Get the attachment points (i.e. quadpoints) of an annotation. // // annot - handle to an annotation. // quad_index - index of the set of quadpoints. // quad_points - receives the quadpoints; must not be NULL. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_GetAttachmentPoints(FPDF_ANNOTATION annot, size_t quad_index, FS_QUADPOINTSF* quad_points); // Experimental API. // Set the annotation rectangle defining the location of the annotation. If the // annotation's appearance stream is defined and this annotation is of a type // without quadpoints, then update the bounding box too if the new rectangle // defines a bigger one. // // annot - handle to an annotation. // rect - the annotation rectangle to be set. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetRect(FPDF_ANNOTATION annot, const FS_RECTF* rect); // Experimental API. // Get the annotation rectangle defining the location of the annotation. // // annot - handle to an annotation. // rect - receives the rectangle; must not be NULL. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_GetRect(FPDF_ANNOTATION annot, FS_RECTF* rect); // Experimental API. // Get the vertices of a polygon or polyline annotation. |buffer| is an array of // points of the annotation. If |length| is less than the returned length, or // |annot| or |buffer| is NULL, |buffer| will not be modified. // // annot - handle to an annotation, as returned by e.g. FPDFPage_GetAnnot() // buffer - buffer for holding the points. // length - length of the buffer in points. // // Returns the number of points if the annotation is of type polygon or // polyline, 0 otherwise. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFAnnot_GetVertices(FPDF_ANNOTATION annot, FS_POINTF* buffer, unsigned long length); // Experimental API. // Get the number of paths in the ink list of an ink annotation. // // annot - handle to an annotation, as returned by e.g. FPDFPage_GetAnnot() // // Returns the number of paths in the ink list if the annotation is of type ink, // 0 otherwise. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFAnnot_GetInkListCount(FPDF_ANNOTATION annot); // Experimental API. // Get a path in the ink list of an ink annotation. |buffer| is an array of // points of the path. If |length| is less than the returned length, or |annot| // or |buffer| is NULL, |buffer| will not be modified. // // annot - handle to an annotation, as returned by e.g. FPDFPage_GetAnnot() // path_index - index of the path // buffer - buffer for holding the points. // length - length of the buffer in points. // // Returns the number of points of the path if the annotation is of type ink, 0 // otherwise. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFAnnot_GetInkListPath(FPDF_ANNOTATION annot, unsigned long path_index, FS_POINTF* buffer, unsigned long length); // Experimental API. // Get the starting and ending coordinates of a line annotation. // // annot - handle to an annotation, as returned by e.g. FPDFPage_GetAnnot() // start - starting point // end - ending point // // Returns true if the annotation is of type line, |start| and |end| are not // NULL, false otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_GetLine(FPDF_ANNOTATION annot, FS_POINTF* start, FS_POINTF* end); // Experimental API. // Set the characteristics of the annotation's border (rounded rectangle). // // annot - handle to an annotation // horizontal_radius - horizontal corner radius, in default user space units // vertical_radius - vertical corner radius, in default user space units // border_width - border width, in default user space units // // Returns true if setting the border for |annot| succeeds, false otherwise. // // If |annot| contains an appearance stream that overrides the border values, // then the appearance stream will be removed on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetBorder(FPDF_ANNOTATION annot, float horizontal_radius, float vertical_radius, float border_width); // Experimental API. // Get the characteristics of the annotation's border (rounded rectangle). // // annot - handle to an annotation // horizontal_radius - horizontal corner radius, in default user space units // vertical_radius - vertical corner radius, in default user space units // border_width - border width, in default user space units // // Returns true if |horizontal_radius|, |vertical_radius| and |border_width| are // not NULL, false otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_GetBorder(FPDF_ANNOTATION annot, float* horizontal_radius, float* vertical_radius, float* border_width); // Experimental API. // Get the JavaScript of an event of the annotation's additional actions. // |buffer| is only modified if |buflen| is large enough to hold the whole // JavaScript string. If |buflen| is smaller, the total size of the JavaScript // is still returned, but nothing is copied. If there is no JavaScript for // |event| in |annot|, an empty string is written to |buf| and 2 is returned, // denoting the size of the null terminator in the buffer. On other errors, // nothing is written to |buffer| and 0 is returned. // // hHandle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment(). // annot - handle to an interactive form annotation. // event - event type, one of the FPDF_ANNOT_AACTION_* values. // buffer - buffer for holding the value string, encoded in UTF-16LE. // buflen - length of the buffer in bytes. // // Returns the length of the string value in bytes, including the 2-byte // null terminator. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFAnnot_GetFormAdditionalActionJavaScript(FPDF_FORMHANDLE hHandle, FPDF_ANNOTATION annot, int event, FPDF_WCHAR* buffer, unsigned long buflen); // Experimental API. // Check if |annot|'s dictionary has |key| as a key. // // annot - handle to an annotation. // key - the key to look for, encoded in UTF-8. // // Returns true if |key| exists. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_HasKey(FPDF_ANNOTATION annot, FPDF_BYTESTRING key); // Experimental API. // Get the type of the value corresponding to |key| in |annot|'s dictionary. // // annot - handle to an annotation. // key - the key to look for, encoded in UTF-8. // // Returns the type of the dictionary value. FPDF_EXPORT FPDF_OBJECT_TYPE FPDF_CALLCONV FPDFAnnot_GetValueType(FPDF_ANNOTATION annot, FPDF_BYTESTRING key); // Experimental API. // Set the string value corresponding to |key| in |annot|'s dictionary, // overwriting the existing value if any. The value type would be // FPDF_OBJECT_STRING after this function call succeeds. // // annot - handle to an annotation. // key - the key to the dictionary entry to be set, encoded in UTF-8. // value - the string value to be set, encoded in UTF-16LE. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetStringValue(FPDF_ANNOTATION annot, FPDF_BYTESTRING key, FPDF_WIDESTRING value); // Experimental API. // Get the string value corresponding to |key| in |annot|'s dictionary. |buffer| // is only modified if |buflen| is longer than the length of contents. Note that // if |key| does not exist in the dictionary or if |key|'s corresponding value // in the dictionary is not a string (i.e. the value is not of type // FPDF_OBJECT_STRING or FPDF_OBJECT_NAME), then an empty string would be copied // to |buffer| and the return value would be 2. On other errors, nothing would // be added to |buffer| and the return value would be 0. // // annot - handle to an annotation. // key - the key to the requested dictionary entry, encoded in UTF-8. // buffer - buffer for holding the value string, encoded in UTF-16LE. // buflen - length of the buffer in bytes. // // Returns the length of the string value in bytes. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFAnnot_GetStringValue(FPDF_ANNOTATION annot, FPDF_BYTESTRING key, FPDF_WCHAR* buffer, unsigned long buflen); // Experimental API. // Get the float value corresponding to |key| in |annot|'s dictionary. Writes // value to |value| and returns True if |key| exists in the dictionary and // |key|'s corresponding value is a number (FPDF_OBJECT_NUMBER), False // otherwise. // // annot - handle to an annotation. // key - the key to the requested dictionary entry, encoded in UTF-8. // value - receives the value, must not be NULL. // // Returns True if value found, False otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_GetNumberValue(FPDF_ANNOTATION annot, FPDF_BYTESTRING key, float* value); // Experimental API. // Set the AP (appearance string) in |annot|'s dictionary for a given // |appearanceMode|. // // annot - handle to an annotation. // appearanceMode - the appearance mode (normal, rollover or down) for which // to get the AP. // value - the string value to be set, encoded in UTF-16LE. If // nullptr is passed, the AP is cleared for that mode. If the // mode is Normal, APs for all modes are cleared. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetAP(FPDF_ANNOTATION annot, FPDF_ANNOT_APPEARANCEMODE appearanceMode, FPDF_WIDESTRING value); // Experimental API. // Get the AP (appearance string) from |annot|'s dictionary for a given // |appearanceMode|. // |buffer| is only modified if |buflen| is large enough to hold the whole AP // string. If |buflen| is smaller, the total size of the AP is still returned, // but nothing is copied. // If there is no appearance stream for |annot| in |appearanceMode|, an empty // string is written to |buf| and 2 is returned. // On other errors, nothing is written to |buffer| and 0 is returned. // // annot - handle to an annotation. // appearanceMode - the appearance mode (normal, rollover or down) for which // to get the AP. // buffer - buffer for holding the value string, encoded in UTF-16LE. // buflen - length of the buffer in bytes. // // Returns the length of the string value in bytes. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFAnnot_GetAP(FPDF_ANNOTATION annot, FPDF_ANNOT_APPEARANCEMODE appearanceMode, FPDF_WCHAR* buffer, unsigned long buflen); // Experimental API. // Get the annotation corresponding to |key| in |annot|'s dictionary. Common // keys for linking annotations include "IRT" and "Popup". Must call // FPDFPage_CloseAnnot() when the annotation returned by this function is no // longer needed. // // annot - handle to an annotation. // key - the key to the requested dictionary entry, encoded in UTF-8. // // Returns a handle to the linked annotation object, or NULL on failure. FPDF_EXPORT FPDF_ANNOTATION FPDF_CALLCONV FPDFAnnot_GetLinkedAnnot(FPDF_ANNOTATION annot, FPDF_BYTESTRING key); // Experimental API. // Get the annotation flags of |annot|. // // annot - handle to an annotation. // // Returns the annotation flags. FPDF_EXPORT int FPDF_CALLCONV FPDFAnnot_GetFlags(FPDF_ANNOTATION annot); // Experimental API. // Set the |annot|'s flags to be of the value |flags|. // // annot - handle to an annotation. // flags - the flag values to be set. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetFlags(FPDF_ANNOTATION annot, int flags); // Experimental API. // Get the annotation flags of |annot|. // // hHandle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment(). // annot - handle to an interactive form annotation. // // Returns the annotation flags specific to interactive forms. FPDF_EXPORT int FPDF_CALLCONV FPDFAnnot_GetFormFieldFlags(FPDF_FORMHANDLE handle, FPDF_ANNOTATION annot); // Experimental API. // Sets the form field flags for an interactive form annotation. // // handle - the handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment(). // annot - handle to an interactive form annotation. // flags - the form field flags to be set. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetFormFieldFlags(FPDF_FORMHANDLE handle, FPDF_ANNOTATION annot, int flags); // Experimental API. // Retrieves an interactive form annotation whose rectangle contains a given // point on a page. Must call FPDFPage_CloseAnnot() when the annotation returned // is no longer needed. // // // hHandle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment(). // page - handle to the page, returned by FPDF_LoadPage function. // point - position in PDF "user space". // // Returns the interactive form annotation whose rectangle contains the given // coordinates on the page. If there is no such annotation, return NULL. FPDF_EXPORT FPDF_ANNOTATION FPDF_CALLCONV FPDFAnnot_GetFormFieldAtPoint(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, const FS_POINTF* point); // Experimental API. // Gets the name of |annot|, which is an interactive form annotation. // |buffer| is only modified if |buflen| is longer than the length of contents. // In case of error, nothing will be added to |buffer| and the return value will // be 0. Note that return value of empty string is 2 for "\0\0". // // hHandle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment(). // annot - handle to an interactive form annotation. // buffer - buffer for holding the name string, encoded in UTF-16LE. // buflen - length of the buffer in bytes. // // Returns the length of the string value in bytes. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFAnnot_GetFormFieldName(FPDF_FORMHANDLE hHandle, FPDF_ANNOTATION annot, FPDF_WCHAR* buffer, unsigned long buflen); // Experimental API. // Gets the alternate name of |annot|, which is an interactive form annotation. // |buffer| is only modified if |buflen| is longer than the length of contents. // In case of error, nothing will be added to |buffer| and the return value will // be 0. Note that return value of empty string is 2 for "\0\0". // // hHandle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment(). // annot - handle to an interactive form annotation. // buffer - buffer for holding the alternate name string, encoded in // UTF-16LE. // buflen - length of the buffer in bytes. // // Returns the length of the string value in bytes. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFAnnot_GetFormFieldAlternateName(FPDF_FORMHANDLE hHandle, FPDF_ANNOTATION annot, FPDF_WCHAR* buffer, unsigned long buflen); // Experimental API. // Gets the form field type of |annot|, which is an interactive form annotation. // // hHandle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment(). // annot - handle to an interactive form annotation. // // Returns the type of the form field (one of the FPDF_FORMFIELD_* values) on // success. Returns -1 on error. // See field types in fpdf_formfill.h. FPDF_EXPORT int FPDF_CALLCONV FPDFAnnot_GetFormFieldType(FPDF_FORMHANDLE hHandle, FPDF_ANNOTATION annot); // Experimental API. // Gets the value of |annot|, which is an interactive form annotation. // |buffer| is only modified if |buflen| is longer than the length of contents. // In case of error, nothing will be added to |buffer| and the return value will // be 0. Note that return value of empty string is 2 for "\0\0". // // hHandle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment(). // annot - handle to an interactive form annotation. // buffer - buffer for holding the value string, encoded in UTF-16LE. // buflen - length of the buffer in bytes. // // Returns the length of the string value in bytes. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFAnnot_GetFormFieldValue(FPDF_FORMHANDLE hHandle, FPDF_ANNOTATION annot, FPDF_WCHAR* buffer, unsigned long buflen); // Experimental API. // Get the number of options in the |annot|'s "Opt" dictionary. Intended for // use with listbox and combobox widget annotations. // // hHandle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment. // annot - handle to an annotation. // // Returns the number of options in "Opt" dictionary on success. Return value // will be -1 if annotation does not have an "Opt" dictionary or other error. FPDF_EXPORT int FPDF_CALLCONV FPDFAnnot_GetOptionCount(FPDF_FORMHANDLE hHandle, FPDF_ANNOTATION annot); // Experimental API. // Get the string value for the label of the option at |index| in |annot|'s // "Opt" dictionary. Intended for use with listbox and combobox widget // annotations. |buffer| is only modified if |buflen| is longer than the length // of contents. If index is out of range or in case of other error, nothing // will be added to |buffer| and the return value will be 0. Note that // return value of empty string is 2 for "\0\0". // // hHandle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment. // annot - handle to an annotation. // index - numeric index of the option in the "Opt" array // buffer - buffer for holding the value string, encoded in UTF-16LE. // buflen - length of the buffer in bytes. // // Returns the length of the string value in bytes. // If |annot| does not have an "Opt" array, |index| is out of range or if any // other error occurs, returns 0. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFAnnot_GetOptionLabel(FPDF_FORMHANDLE hHandle, FPDF_ANNOTATION annot, int index, FPDF_WCHAR* buffer, unsigned long buflen); // Experimental API. // Determine whether or not the option at |index| in |annot|'s "Opt" dictionary // is selected. Intended for use with listbox and combobox widget annotations. // // handle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment. // annot - handle to an annotation. // index - numeric index of the option in the "Opt" array. // // Returns true if the option at |index| in |annot|'s "Opt" dictionary is // selected, false otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_IsOptionSelected(FPDF_FORMHANDLE handle, FPDF_ANNOTATION annot, int index); // Experimental API. // Get the float value of the font size for an |annot| with variable text. // If 0, the font is to be auto-sized: its size is computed as a function of // the height of the annotation rectangle. // // hHandle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment. // annot - handle to an annotation. // value - Required. Float which will be set to font size on success. // // Returns true if the font size was set in |value|, false on error or if // |value| not provided. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_GetFontSize(FPDF_FORMHANDLE hHandle, FPDF_ANNOTATION annot, float* value); // Experimental API. // Set the text color of an annotation. // // handle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment. // annot - handle to an annotation. // R - the red component for the text color. // G - the green component for the text color. // B - the blue component for the text color. // // Returns true if successful. // // Currently supported subtypes: freetext. // The range for the color components is 0 to 255. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetFontColor(FPDF_FORMHANDLE handle, FPDF_ANNOTATION annot, unsigned int R, unsigned int G, unsigned int B); // Experimental API. // Get the RGB value of the font color for an |annot| with variable text. // // hHandle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment. // annot - handle to an annotation. // R, G, B - buffer to hold the RGB value of the color. Ranges from 0 to 255. // // Returns true if the font color was set, false on error or if the font // color was not provided. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_GetFontColor(FPDF_FORMHANDLE hHandle, FPDF_ANNOTATION annot, unsigned int* R, unsigned int* G, unsigned int* B); // Experimental API. // Determine if |annot| is a form widget that is checked. Intended for use with // checkbox and radio button widgets. // // hHandle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment. // annot - handle to an annotation. // // Returns true if |annot| is a form widget and is checked, false otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_IsChecked(FPDF_FORMHANDLE hHandle, FPDF_ANNOTATION annot); // Experimental API. // Set the list of focusable annotation subtypes. Annotations of subtype // FPDF_ANNOT_WIDGET are by default focusable. New subtypes set using this API // will override the existing subtypes. // // hHandle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment. // subtypes - list of annotation subtype which can be tabbed over. // count - total number of annotation subtype in list. // Returns true if list of annotation subtype is set successfully, false // otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetFocusableSubtypes(FPDF_FORMHANDLE hHandle, const FPDF_ANNOTATION_SUBTYPE* subtypes, size_t count); // Experimental API. // Get the count of focusable annotation subtypes as set by host // for a |hHandle|. // // hHandle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment. // Returns the count of focusable annotation subtypes or -1 on error. // Note : Annotations of type FPDF_ANNOT_WIDGET are by default focusable. FPDF_EXPORT int FPDF_CALLCONV FPDFAnnot_GetFocusableSubtypesCount(FPDF_FORMHANDLE hHandle); // Experimental API. // Get the list of focusable annotation subtype as set by host. // // hHandle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment. // subtypes - receives the list of annotation subtype which can be tabbed // over. Caller must have allocated |subtypes| more than or // equal to the count obtained from // FPDFAnnot_GetFocusableSubtypesCount() API. // count - size of |subtypes|. // Returns true on success and set list of annotation subtype to |subtypes|, // false otherwise. // Note : Annotations of type FPDF_ANNOT_WIDGET are by default focusable. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_GetFocusableSubtypes(FPDF_FORMHANDLE hHandle, FPDF_ANNOTATION_SUBTYPE* subtypes, size_t count); // Experimental API. // Gets FPDF_LINK object for |annot|. Intended to use for link annotations. // // annot - handle to an annotation. // // Returns FPDF_LINK from the FPDF_ANNOTATION and NULL on failure, // if the input annot is NULL or input annot's subtype is not link. FPDF_EXPORT FPDF_LINK FPDF_CALLCONV FPDFAnnot_GetLink(FPDF_ANNOTATION annot); // Experimental API. // Gets the count of annotations in the |annot|'s control group. // A group of interactive form annotations is collectively called a form // control group. Here, |annot|, an interactive form annotation, should be // either a radio button or a checkbox. // // hHandle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment. // annot - handle to an annotation. // // Returns number of controls in its control group or -1 on error. FPDF_EXPORT int FPDF_CALLCONV FPDFAnnot_GetFormControlCount(FPDF_FORMHANDLE hHandle, FPDF_ANNOTATION annot); // Experimental API. // Gets the index of |annot| in |annot|'s control group. // A group of interactive form annotations is collectively called a form // control group. Here, |annot|, an interactive form annotation, should be // either a radio button or a checkbox. // // hHandle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment. // annot - handle to an annotation. // // Returns index of a given |annot| in its control group or -1 on error. FPDF_EXPORT int FPDF_CALLCONV FPDFAnnot_GetFormControlIndex(FPDF_FORMHANDLE hHandle, FPDF_ANNOTATION annot); // Experimental API. // Gets the export value of |annot| which is an interactive form annotation. // Intended for use with radio button and checkbox widget annotations. // |buffer| is only modified if |buflen| is longer than the length of contents. // In case of error, nothing will be added to |buffer| and the return value // will be 0. Note that return value of empty string is 2 for "\0\0". // // hHandle - handle to the form fill module, returned by // FPDFDOC_InitFormFillEnvironment(). // annot - handle to an interactive form annotation. // buffer - buffer for holding the value string, encoded in UTF-16LE. // buflen - length of the buffer in bytes. // // Returns the length of the string value in bytes. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFAnnot_GetFormFieldExportValue(FPDF_FORMHANDLE hHandle, FPDF_ANNOTATION annot, FPDF_WCHAR* buffer, unsigned long buflen); // Experimental API. // Add a URI action to |annot|, overwriting the existing action, if any. // // annot - handle to a link annotation. // uri - the URI to be set, encoded in 7-bit ASCII. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetURI(FPDF_ANNOTATION annot, const char* uri); // Experimental API. // Get the attachment from |annot|. // // annot - handle to a file annotation. // // Returns the handle to the attachment object, or NULL on failure. FPDF_EXPORT FPDF_ATTACHMENT FPDF_CALLCONV FPDFAnnot_GetFileAttachment(FPDF_ANNOTATION annot); // Experimental API. // Add an embedded file with |name| to |annot|. // // annot - handle to a file annotation. // name - name of the new attachment. // // Returns a handle to the new attachment object, or NULL on failure. FPDF_EXPORT FPDF_ATTACHMENT FPDF_CALLCONV FPDFAnnot_AddFileAttachment(FPDF_ANNOTATION annot, FPDF_WIDESTRING name); #ifdef __cplusplus } // extern "C" #endif // __cplusplus #endif // PUBLIC_FPDF_ANNOT_H_ ================================================ FILE: external/pdfium/windows-x64/include/fpdf_attachment.h ================================================ // Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef PUBLIC_FPDF_ATTACHMENT_H_ #define PUBLIC_FPDF_ATTACHMENT_H_ // NOLINTNEXTLINE(build/include) #include "fpdfview.h" #ifdef __cplusplus extern "C" { #endif // __cplusplus // Experimental API. // Get the number of embedded files in |document|. // // document - handle to a document. // // Returns the number of embedded files in |document|. FPDF_EXPORT int FPDF_CALLCONV FPDFDoc_GetAttachmentCount(FPDF_DOCUMENT document); // Experimental API. // Add an embedded file with |name| in |document|. If |name| is empty, or if // |name| is the name of a existing embedded file in |document|, or if // |document|'s embedded file name tree is too deep (i.e. |document| has too // many embedded files already), then a new attachment will not be added. // // document - handle to a document. // name - name of the new attachment. // // Returns a handle to the new attachment object, or NULL on failure. FPDF_EXPORT FPDF_ATTACHMENT FPDF_CALLCONV FPDFDoc_AddAttachment(FPDF_DOCUMENT document, FPDF_WIDESTRING name); // Experimental API. // Get the embedded attachment at |index| in |document|. Note that the returned // attachment handle is only valid while |document| is open. // // document - handle to a document. // index - the index of the requested embedded file. // // Returns the handle to the attachment object, or NULL on failure. FPDF_EXPORT FPDF_ATTACHMENT FPDF_CALLCONV FPDFDoc_GetAttachment(FPDF_DOCUMENT document, int index); // Experimental API. // Delete the embedded attachment at |index| in |document|. Note that this does // not remove the attachment data from the PDF file; it simply removes the // file's entry in the embedded files name tree so that it does not appear in // the attachment list. This behavior may change in the future. // // document - handle to a document. // index - the index of the embedded file to be deleted. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFDoc_DeleteAttachment(FPDF_DOCUMENT document, int index); // Experimental API. // Get the name of the |attachment| file. |buffer| is only modified if |buflen| // is longer than the length of the file name. On errors, |buffer| is unmodified // and the returned length is 0. // // attachment - handle to an attachment. // buffer - buffer for holding the file name, encoded in UTF-16LE. // buflen - length of the buffer in bytes. // // Returns the length of the file name in bytes. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFAttachment_GetName(FPDF_ATTACHMENT attachment, FPDF_WCHAR* buffer, unsigned long buflen); // Experimental API. // Check if the params dictionary of |attachment| has |key| as a key. // // attachment - handle to an attachment. // key - the key to look for, encoded in UTF-8. // // Returns true if |key| exists. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAttachment_HasKey(FPDF_ATTACHMENT attachment, FPDF_BYTESTRING key); // Experimental API. // Get the type of the value corresponding to |key| in the params dictionary of // the embedded |attachment|. // // attachment - handle to an attachment. // key - the key to look for, encoded in UTF-8. // // Returns the type of the dictionary value. FPDF_EXPORT FPDF_OBJECT_TYPE FPDF_CALLCONV FPDFAttachment_GetValueType(FPDF_ATTACHMENT attachment, FPDF_BYTESTRING key); // Experimental API. // Set the string value corresponding to |key| in the params dictionary of the // embedded file |attachment|, overwriting the existing value if any. The value // type should be FPDF_OBJECT_STRING after this function call succeeds. // // attachment - handle to an attachment. // key - the key to the dictionary entry, encoded in UTF-8. // value - the string value to be set, encoded in UTF-16LE. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAttachment_SetStringValue(FPDF_ATTACHMENT attachment, FPDF_BYTESTRING key, FPDF_WIDESTRING value); // Experimental API. // Get the string value corresponding to |key| in the params dictionary of the // embedded file |attachment|. |buffer| is only modified if |buflen| is longer // than the length of the string value. Note that if |key| does not exist in the // dictionary or if |key|'s corresponding value in the dictionary is not a // string (i.e. the value is not of type FPDF_OBJECT_STRING or // FPDF_OBJECT_NAME), then an empty string would be copied to |buffer| and the // return value would be 2. On other errors, nothing would be added to |buffer| // and the return value would be 0. // // attachment - handle to an attachment. // key - the key to the requested string value, encoded in UTF-8. // buffer - buffer for holding the string value encoded in UTF-16LE. // buflen - length of the buffer in bytes. // // Returns the length of the dictionary value string in bytes. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFAttachment_GetStringValue(FPDF_ATTACHMENT attachment, FPDF_BYTESTRING key, FPDF_WCHAR* buffer, unsigned long buflen); // Experimental API. // Set the file data of |attachment|, overwriting the existing file data if any. // The creation date and checksum will be updated, while all other dictionary // entries will be deleted. Note that only contents with |len| smaller than // INT_MAX is supported. // // attachment - handle to an attachment. // contents - buffer holding the file data to write to |attachment|. // len - length of file data in bytes. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAttachment_SetFile(FPDF_ATTACHMENT attachment, FPDF_DOCUMENT document, const void* contents, unsigned long len); // Experimental API. // Get the file data of |attachment|. // When the attachment file data is readable, true is returned, and |out_buflen| // is updated to indicate the file data size. |buffer| is only modified if // |buflen| is non-null and long enough to contain the entire file data. Callers // must check both the return value and the input |buflen| is no less than the // returned |out_buflen| before using the data. // // Otherwise, when the attachment file data is unreadable or when |out_buflen| // is null, false is returned and |buffer| and |out_buflen| remain unmodified. // // attachment - handle to an attachment. // buffer - buffer for holding the file data from |attachment|. // buflen - length of the buffer in bytes. // out_buflen - pointer to the variable that will receive the minimum buffer // size to contain the file data of |attachment|. // // Returns true on success, false otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAttachment_GetFile(FPDF_ATTACHMENT attachment, void* buffer, unsigned long buflen, unsigned long* out_buflen); // Experimental API. // Get the MIME type (Subtype) of the embedded file |attachment|. |buffer| is // only modified if |buflen| is longer than the length of the MIME type string. // If the Subtype is not found or if there is no file stream, an empty string // would be copied to |buffer| and the return value would be 2. On other errors, // nothing would be added to |buffer| and the return value would be 0. // // attachment - handle to an attachment. // buffer - buffer for holding the MIME type string encoded in UTF-16LE. // buflen - length of the buffer in bytes. // // Returns the length of the MIME type string in bytes. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFAttachment_GetSubtype(FPDF_ATTACHMENT attachment, FPDF_WCHAR* buffer, unsigned long buflen); #ifdef __cplusplus } // extern "C" #endif // __cplusplus #endif // PUBLIC_FPDF_ATTACHMENT_H_ ================================================ FILE: external/pdfium/windows-x64/include/fpdf_catalog.h ================================================ // Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef PUBLIC_FPDF_CATALOG_H_ #define PUBLIC_FPDF_CATALOG_H_ // NOLINTNEXTLINE(build/include) #include "fpdfview.h" #ifdef __cplusplus extern "C" { #endif // __cplusplus // Experimental API. // // Determine if |document| represents a tagged PDF. // // For the definition of tagged PDF, See (see 10.7 "Tagged PDF" in PDF // Reference 1.7). // // document - handle to a document. // // Returns |true| iff |document| is a tagged PDF. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFCatalog_IsTagged(FPDF_DOCUMENT document); // Experimental API. // Gets the language of |document| from the catalog's /Lang entry. // // document - handle to a document. // buffer - a buffer for the language string. May be NULL. // buflen - the length of the buffer, in bytes. May be 0. // // Returns the number of bytes in the language string, including the // trailing NUL character. The number of bytes is returned regardless of the // |buffer| and |buflen| parameters. // // Regardless of the platform, the |buffer| is always in UTF-16LE // encoding. The string is terminated by a UTF16 NUL character. If // |buflen| is less than the required length, or |buffer| is NULL, // |buffer| will not be modified. // // If |document| has no /Lang entry, an empty string is written to |buffer| and // 2 is returned. On error, nothing is written to |buffer| and 0 is returned. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFCatalog_GetLanguage(FPDF_DOCUMENT document, FPDF_WCHAR* buffer, unsigned long buflen); // Experimental API. // Sets the language of |document| to |language|. // // document - handle to a document. // language - the language to set to. // // Returns TRUE on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFCatalog_SetLanguage(FPDF_DOCUMENT document, FPDF_WIDESTRING language); #ifdef __cplusplus } // extern "C" #endif // __cplusplus #endif // PUBLIC_FPDF_CATALOG_H_ ================================================ FILE: external/pdfium/windows-x64/include/fpdf_dataavail.h ================================================ // Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #ifndef PUBLIC_FPDF_DATAAVAIL_H_ #define PUBLIC_FPDF_DATAAVAIL_H_ #include // NOLINTNEXTLINE(build/include) #include "fpdfview.h" #define PDF_LINEARIZATION_UNKNOWN -1 #define PDF_NOT_LINEARIZED 0 #define PDF_LINEARIZED 1 #define PDF_DATA_ERROR -1 #define PDF_DATA_NOTAVAIL 0 #define PDF_DATA_AVAIL 1 #define PDF_FORM_ERROR -1 #define PDF_FORM_NOTAVAIL 0 #define PDF_FORM_AVAIL 1 #define PDF_FORM_NOTEXIST 2 #ifdef __cplusplus extern "C" { #endif // __cplusplus // Interface for checking whether sections of the file are available. typedef struct _FX_FILEAVAIL { // Version number of the interface. Must be 1. int version; // Reports if the specified data section is currently available. A section is // available if all bytes in the section are available. // // Interface Version: 1 // Implementation Required: Yes // // pThis - pointer to the interface structure. // offset - the offset of the data section in the file. // size - the size of the data section. // // Returns true if the specified data section at |offset| of |size| // is available. FPDF_BOOL (*IsDataAvail)(struct _FX_FILEAVAIL* pThis, size_t offset, size_t size); } FX_FILEAVAIL; // Create a document availability provider. // // file_avail - pointer to file availability interface. // file - pointer to a file access interface. // // Returns a handle to the document availability provider, or NULL on error. // // FPDFAvail_Destroy() must be called when done with the availability provider. FPDF_EXPORT FPDF_AVAIL FPDF_CALLCONV FPDFAvail_Create(FX_FILEAVAIL* file_avail, FPDF_FILEACCESS* file); // Destroy the |avail| document availability provider. // // avail - handle to document availability provider to be destroyed. FPDF_EXPORT void FPDF_CALLCONV FPDFAvail_Destroy(FPDF_AVAIL avail); // Download hints interface. Used to receive hints for further downloading. typedef struct _FX_DOWNLOADHINTS { // Version number of the interface. Must be 1. int version; // Add a section to be downloaded. // // Interface Version: 1 // Implementation Required: Yes // // pThis - pointer to the interface structure. // offset - the offset of the hint reported to be downloaded. // size - the size of the hint reported to be downloaded. // // The |offset| and |size| of the section may not be unique. Part of the // section might be already available. The download manager must deal with // overlapping sections. void (*AddSegment)(struct _FX_DOWNLOADHINTS* pThis, size_t offset, size_t size); } FX_DOWNLOADHINTS; // Checks if the document is ready for loading, if not, gets download hints. // // avail - handle to document availability provider. // hints - pointer to a download hints interface. // // Returns one of: // PDF_DATA_ERROR: A common error is returned. Data availability unknown. // PDF_DATA_NOTAVAIL: Data not yet available. // PDF_DATA_AVAIL: Data available. // // Applications should call this function whenever new data arrives, and process // all the generated download hints, if any, until the function returns // |PDF_DATA_ERROR| or |PDF_DATA_AVAIL|. // if hints is nullptr, the function just check current document availability. // // Once all data is available, call FPDFAvail_GetDocument() to get a document // handle. FPDF_EXPORT int FPDF_CALLCONV FPDFAvail_IsDocAvail(FPDF_AVAIL avail, FX_DOWNLOADHINTS* hints); // Get document from the availability provider. // // avail - handle to document availability provider. // password - password for decrypting the PDF file. Optional. // // Returns a handle to the document. // // When FPDFAvail_IsDocAvail() returns TRUE, call FPDFAvail_GetDocument() to // retrieve the document handle. // See the comments for FPDF_LoadDocument() regarding the encoding for // |password|. FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV FPDFAvail_GetDocument(FPDF_AVAIL avail, FPDF_BYTESTRING password); // Get the page number for the first available page in a linearized PDF. // // doc - document handle. // // Returns the zero-based index for the first available page. // // For most linearized PDFs, the first available page will be the first page, // however, some PDFs might make another page the first available page. // For non-linearized PDFs, this function will always return zero. FPDF_EXPORT int FPDF_CALLCONV FPDFAvail_GetFirstPageNum(FPDF_DOCUMENT doc); // Check if |page_index| is ready for loading, if not, get the // |FX_DOWNLOADHINTS|. // // avail - handle to document availability provider. // page_index - index number of the page. Zero for the first page. // hints - pointer to a download hints interface. Populated if // |page_index| is not available. // // Returns one of: // PDF_DATA_ERROR: A common error is returned. Data availability unknown. // PDF_DATA_NOTAVAIL: Data not yet available. // PDF_DATA_AVAIL: Data available. // // This function can be called only after FPDFAvail_GetDocument() is called. // Applications should call this function whenever new data arrives and process // all the generated download |hints|, if any, until this function returns // |PDF_DATA_ERROR| or |PDF_DATA_AVAIL|. Applications can then perform page // loading. // if hints is nullptr, the function just check current availability of // specified page. FPDF_EXPORT int FPDF_CALLCONV FPDFAvail_IsPageAvail(FPDF_AVAIL avail, int page_index, FX_DOWNLOADHINTS* hints); // Check if form data is ready for initialization, if not, get the // |FX_DOWNLOADHINTS|. // // avail - handle to document availability provider. // hints - pointer to a download hints interface. Populated if form is not // ready for initialization. // // Returns one of: // PDF_FORM_ERROR: A common eror, in general incorrect parameters. // PDF_FORM_NOTAVAIL: Data not available. // PDF_FORM_AVAIL: Data available. // PDF_FORM_NOTEXIST: No form data. // // This function can be called only after FPDFAvail_GetDocument() is called. // The application should call this function whenever new data arrives and // process all the generated download |hints|, if any, until the function // |PDF_FORM_ERROR|, |PDF_FORM_AVAIL| or |PDF_FORM_NOTEXIST|. // if hints is nullptr, the function just check current form availability. // // Applications can then perform page loading. It is recommend to call // FPDFDOC_InitFormFillEnvironment() when |PDF_FORM_AVAIL| is returned. FPDF_EXPORT int FPDF_CALLCONV FPDFAvail_IsFormAvail(FPDF_AVAIL avail, FX_DOWNLOADHINTS* hints); // Check whether a document is a linearized PDF. // // avail - handle to document availability provider. // // Returns one of: // PDF_LINEARIZED // PDF_NOT_LINEARIZED // PDF_LINEARIZATION_UNKNOWN // // FPDFAvail_IsLinearized() will return |PDF_LINEARIZED| or |PDF_NOT_LINEARIZED| // when we have 1k of data. If the files size less than 1k, it returns // |PDF_LINEARIZATION_UNKNOWN| as there is insufficient information to determine // if the PDF is linearlized. FPDF_EXPORT int FPDF_CALLCONV FPDFAvail_IsLinearized(FPDF_AVAIL avail); #ifdef __cplusplus } // extern "C" #endif // __cplusplus #endif // PUBLIC_FPDF_DATAAVAIL_H_ ================================================ FILE: external/pdfium/windows-x64/include/fpdf_doc.h ================================================ // Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #ifndef PUBLIC_FPDF_DOC_H_ #define PUBLIC_FPDF_DOC_H_ // NOLINTNEXTLINE(build/include) #include "fpdfview.h" #ifdef __cplusplus extern "C" { #endif // __cplusplus // Unsupported action type. #define PDFACTION_UNSUPPORTED 0 // Go to a destination within current document. #define PDFACTION_GOTO 1 // Go to a destination within another document. #define PDFACTION_REMOTEGOTO 2 // URI, including web pages and other Internet resources. #define PDFACTION_URI 3 // Launch an application or open a file. #define PDFACTION_LAUNCH 4 // Go to a destination in an embedded file. #define PDFACTION_EMBEDDEDGOTO 5 // View destination fit types. See pdfmark reference v9, page 48. #define PDFDEST_VIEW_UNKNOWN_MODE 0 #define PDFDEST_VIEW_XYZ 1 #define PDFDEST_VIEW_FIT 2 #define PDFDEST_VIEW_FITH 3 #define PDFDEST_VIEW_FITV 4 #define PDFDEST_VIEW_FITR 5 #define PDFDEST_VIEW_FITB 6 #define PDFDEST_VIEW_FITBH 7 #define PDFDEST_VIEW_FITBV 8 // The file identifier entry type. See section 14.4 "File Identifiers" of the // ISO 32000-1:2008 spec. typedef enum { FILEIDTYPE_PERMANENT = 0, FILEIDTYPE_CHANGING = 1 } FPDF_FILEIDTYPE; // Get the first child of |bookmark|, or the first top-level bookmark item. // // document - handle to the document. // bookmark - handle to the current bookmark. Pass NULL for the first top // level item. // // Returns a handle to the first child of |bookmark| or the first top-level // bookmark item. NULL if no child or top-level bookmark found. // Note that another name for the bookmarks is the document outline, as // described in ISO 32000-1:2008, section 12.3.3. FPDF_EXPORT FPDF_BOOKMARK FPDF_CALLCONV FPDFBookmark_GetFirstChild(FPDF_DOCUMENT document, FPDF_BOOKMARK bookmark); // Get the next sibling of |bookmark|. // // document - handle to the document. // bookmark - handle to the current bookmark. // // Returns a handle to the next sibling of |bookmark|, or NULL if this is the // last bookmark at this level. // // Note that the caller is responsible for handling circular bookmark // references, as may arise from malformed documents. FPDF_EXPORT FPDF_BOOKMARK FPDF_CALLCONV FPDFBookmark_GetNextSibling(FPDF_DOCUMENT document, FPDF_BOOKMARK bookmark); // Get the title of |bookmark|. // // bookmark - handle to the bookmark. // buffer - buffer for the title. May be NULL. // buflen - the length of the buffer in bytes. May be 0. // // Returns the number of bytes in the title, including the terminating NUL // character. The number of bytes is returned regardless of the |buffer| and // |buflen| parameters. // // Regardless of the platform, the |buffer| is always in UTF-16LE encoding. The // string is terminated by a UTF16 NUL character. If |buflen| is less than the // required length, or |buffer| is NULL, |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFBookmark_GetTitle(FPDF_BOOKMARK bookmark, void* buffer, unsigned long buflen); // Experimental API. // Get the number of chlidren of |bookmark|. // // bookmark - handle to the bookmark. // // Returns a signed integer that represents the number of sub-items the given // bookmark has. If the value is positive, child items shall be shown by default // (open state). If the value is negative, child items shall be hidden by // default (closed state). Please refer to PDF 32000-1:2008, Table 153. // Returns 0 if the bookmark has no children or is invalid. FPDF_EXPORT int FPDF_CALLCONV FPDFBookmark_GetCount(FPDF_BOOKMARK bookmark); // Find the bookmark with |title| in |document|. // // document - handle to the document. // title - the UTF-16LE encoded Unicode title for which to search. // // Returns the handle to the bookmark, or NULL if |title| can't be found. // // FPDFBookmark_Find() will always return the first bookmark found even if // multiple bookmarks have the same |title|. FPDF_EXPORT FPDF_BOOKMARK FPDF_CALLCONV FPDFBookmark_Find(FPDF_DOCUMENT document, FPDF_WIDESTRING title); // Get the destination associated with |bookmark|. // // document - handle to the document. // bookmark - handle to the bookmark. // // Returns the handle to the destination data, or NULL if no destination is // associated with |bookmark|. FPDF_EXPORT FPDF_DEST FPDF_CALLCONV FPDFBookmark_GetDest(FPDF_DOCUMENT document, FPDF_BOOKMARK bookmark); // Get the action associated with |bookmark|. // // bookmark - handle to the bookmark. // // Returns the handle to the action data, or NULL if no action is associated // with |bookmark|. // If this function returns a valid handle, it is valid as long as |bookmark| is // valid. // If this function returns NULL, FPDFBookmark_GetDest() should be called to get // the |bookmark| destination data. FPDF_EXPORT FPDF_ACTION FPDF_CALLCONV FPDFBookmark_GetAction(FPDF_BOOKMARK bookmark); // Get the type of |action|. // // action - handle to the action. // // Returns one of: // PDFACTION_UNSUPPORTED // PDFACTION_GOTO // PDFACTION_REMOTEGOTO // PDFACTION_URI // PDFACTION_LAUNCH FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFAction_GetType(FPDF_ACTION action); // Get the destination of |action|. // // document - handle to the document. // action - handle to the action. |action| must be a |PDFACTION_GOTO| or // |PDFACTION_REMOTEGOTO|. // // Returns a handle to the destination data, or NULL on error, typically // because the arguments were bad or the action was of the wrong type. // // In the case of |PDFACTION_REMOTEGOTO|, you must first call // FPDFAction_GetFilePath(), then load the document at that path, then pass // the document handle from that document as |document| to FPDFAction_GetDest(). FPDF_EXPORT FPDF_DEST FPDF_CALLCONV FPDFAction_GetDest(FPDF_DOCUMENT document, FPDF_ACTION action); // Get the file path of |action|. // // action - handle to the action. |action| must be a |PDFACTION_LAUNCH| or // |PDFACTION_REMOTEGOTO|. // buffer - a buffer for output the path string. May be NULL. // buflen - the length of the buffer, in bytes. May be 0. // // Returns the number of bytes in the file path, including the trailing NUL // character, or 0 on error, typically because the arguments were bad or the // action was of the wrong type. // // Regardless of the platform, the |buffer| is always in UTF-8 encoding. // If |buflen| is less than the returned length, or |buffer| is NULL, |buffer| // will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFAction_GetFilePath(FPDF_ACTION action, void* buffer, unsigned long buflen); // Get the URI path of |action|. // // document - handle to the document. // action - handle to the action. Must be a |PDFACTION_URI|. // buffer - a buffer for the path string. May be NULL. // buflen - the length of the buffer, in bytes. May be 0. // // Returns the number of bytes in the URI path, including the trailing NUL // character, or 0 on error, typically because the arguments were bad or the // action was of the wrong type. // // The |buffer| may contain badly encoded data. The caller should validate the // output. e.g. Check to see if it is UTF-8. // // If |buflen| is less than the returned length, or |buffer| is NULL, |buffer| // will not be modified. // // Historically, the documentation for this API claimed |buffer| is always // encoded in 7-bit ASCII, but did not actually enforce it. // https://pdfium.googlesource.com/pdfium.git/+/d609e84cee2e14a18333247485af91df48a40592 // added that enforcement, but that did not work well for real world PDFs that // used UTF-8. As of this writing, this API reverted back to its original // behavior prior to commit d609e84cee. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFAction_GetURIPath(FPDF_DOCUMENT document, FPDF_ACTION action, void* buffer, unsigned long buflen); // Get the page index of |dest|. // // document - handle to the document. // dest - handle to the destination. // // Returns the 0-based page index containing |dest|. Returns -1 on error. FPDF_EXPORT int FPDF_CALLCONV FPDFDest_GetDestPageIndex(FPDF_DOCUMENT document, FPDF_DEST dest); // Experimental API. // Get the view (fit type) specified by |dest|. // // dest - handle to the destination. // pNumParams - receives the number of view parameters, which is at most 4. // pParams - buffer to write the view parameters. Must be at least 4 // FS_FLOATs long. // Returns one of the PDFDEST_VIEW_* constants, PDFDEST_VIEW_UNKNOWN_MODE if // |dest| does not specify a view. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFDest_GetView(FPDF_DEST dest, unsigned long* pNumParams, FS_FLOAT* pParams); // Get the (x, y, zoom) location of |dest| in the destination page, if the // destination is in [page /XYZ x y zoom] syntax. // // dest - handle to the destination. // hasXVal - out parameter; true if the x value is not null // hasYVal - out parameter; true if the y value is not null // hasZoomVal - out parameter; true if the zoom value is not null // x - out parameter; the x coordinate, in page coordinates. // y - out parameter; the y coordinate, in page coordinates. // zoom - out parameter; the zoom value. // Returns TRUE on successfully reading the /XYZ value. // // Note the [x, y, zoom] values are only set if the corresponding hasXVal, // hasYVal or hasZoomVal flags are true. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFDest_GetLocationInPage(FPDF_DEST dest, FPDF_BOOL* hasXVal, FPDF_BOOL* hasYVal, FPDF_BOOL* hasZoomVal, FS_FLOAT* x, FS_FLOAT* y, FS_FLOAT* zoom); // Find a link at point (|x|,|y|) on |page|. // // page - handle to the document page. // x - the x coordinate, in the page coordinate system. // y - the y coordinate, in the page coordinate system. // // Returns a handle to the link, or NULL if no link found at the given point. // // You can convert coordinates from screen coordinates to page coordinates using // FPDF_DeviceToPage(). FPDF_EXPORT FPDF_LINK FPDF_CALLCONV FPDFLink_GetLinkAtPoint(FPDF_PAGE page, double x, double y); // Find the Z-order of link at point (|x|,|y|) on |page|. // // page - handle to the document page. // x - the x coordinate, in the page coordinate system. // y - the y coordinate, in the page coordinate system. // // Returns the Z-order of the link, or -1 if no link found at the given point. // Larger Z-order numbers are closer to the front. // // You can convert coordinates from screen coordinates to page coordinates using // FPDF_DeviceToPage(). FPDF_EXPORT int FPDF_CALLCONV FPDFLink_GetLinkZOrderAtPoint(FPDF_PAGE page, double x, double y); // Get destination info for |link|. // // document - handle to the document. // link - handle to the link. // // Returns a handle to the destination, or NULL if there is no destination // associated with the link. In this case, you should call FPDFLink_GetAction() // to retrieve the action associated with |link|. FPDF_EXPORT FPDF_DEST FPDF_CALLCONV FPDFLink_GetDest(FPDF_DOCUMENT document, FPDF_LINK link); // Get action info for |link|. // // link - handle to the link. // // Returns a handle to the action associated to |link|, or NULL if no action. // If this function returns a valid handle, it is valid as long as |link| is // valid. FPDF_EXPORT FPDF_ACTION FPDF_CALLCONV FPDFLink_GetAction(FPDF_LINK link); // Enumerates all the link annotations in |page|. // // page - handle to the page. // start_pos - the start position, should initially be 0 and is updated with // the next start position on return. // link_annot - the link handle for |startPos|. // // Returns TRUE on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFLink_Enumerate(FPDF_PAGE page, int* start_pos, FPDF_LINK* link_annot); // Experimental API. // Gets FPDF_ANNOTATION object for |link_annot|. // // page - handle to the page in which FPDF_LINK object is present. // link_annot - handle to link annotation. // // Returns FPDF_ANNOTATION from the FPDF_LINK and NULL on failure, // if the input link annot or page is NULL. FPDF_EXPORT FPDF_ANNOTATION FPDF_CALLCONV FPDFLink_GetAnnot(FPDF_PAGE page, FPDF_LINK link_annot); // Get the rectangle for |link_annot|. // // link_annot - handle to the link annotation. // rect - the annotation rectangle. // // Returns true on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFLink_GetAnnotRect(FPDF_LINK link_annot, FS_RECTF* rect); // Get the count of quadrilateral points to the |link_annot|. // // link_annot - handle to the link annotation. // // Returns the count of quadrilateral points. FPDF_EXPORT int FPDF_CALLCONV FPDFLink_CountQuadPoints(FPDF_LINK link_annot); // Get the quadrilateral points for the specified |quad_index| in |link_annot|. // // link_annot - handle to the link annotation. // quad_index - the specified quad point index. // quad_points - receives the quadrilateral points. // // Returns true on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFLink_GetQuadPoints(FPDF_LINK link_annot, int quad_index, FS_QUADPOINTSF* quad_points); // Experimental API // Gets an additional-action from |page|. // // page - handle to the page, as returned by FPDF_LoadPage(). // aa_type - the type of the page object's addtional-action, defined // in public/fpdf_formfill.h // // Returns the handle to the action data, or NULL if there is no // additional-action of type |aa_type|. // If this function returns a valid handle, it is valid as long as |page| is // valid. FPDF_EXPORT FPDF_ACTION FPDF_CALLCONV FPDF_GetPageAAction(FPDF_PAGE page, int aa_type); // Experimental API. // Get the file identifer defined in the trailer of |document|. // // document - handle to the document. // id_type - the file identifier type to retrieve. // buffer - a buffer for the file identifier. May be NULL. // buflen - the length of the buffer, in bytes. May be 0. // // Returns the number of bytes in the file identifier, including the NUL // terminator. // // The |buffer| is always a byte string. The |buffer| is followed by a NUL // terminator. If |buflen| is less than the returned length, or |buffer| is // NULL, |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetFileIdentifier(FPDF_DOCUMENT document, FPDF_FILEIDTYPE id_type, void* buffer, unsigned long buflen); // Get meta-data |tag| content from |document|. // // document - handle to the document. // tag - the tag to retrieve. The tag can be one of: // Title, Author, Subject, Keywords, Creator, Producer, // CreationDate, or ModDate. // For detailed explanations of these tags and their respective // values, please refer to PDF Reference 1.6, section 10.2.1, // 'Document Information Dictionary'. // buffer - a buffer for the tag. May be NULL. // buflen - the length of the buffer, in bytes. May be 0. // // Returns the number of bytes in the tag, including trailing zeros. // // The |buffer| is always encoded in UTF-16LE. The |buffer| is followed by two // bytes of zeros indicating the end of the string. If |buflen| is less than // the returned length, or |buffer| is NULL, |buffer| will not be modified. // // For linearized files, FPDFAvail_IsFormAvail must be called before this, and // it must have returned PDF_FORM_AVAIL or PDF_FORM_NOTEXIST. Before that, there // is no guarantee the metadata has been loaded. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetMetaText(FPDF_DOCUMENT document, FPDF_BYTESTRING tag, void* buffer, unsigned long buflen); // Get the page label for |page_index| from |document|. // // document - handle to the document. // page_index - the 0-based index of the page. // buffer - a buffer for the page label. May be NULL. // buflen - the length of the buffer, in bytes. May be 0. // // Returns the number of bytes in the page label, including trailing zeros. // // The |buffer| is always encoded in UTF-16LE. The |buffer| is followed by two // bytes of zeros indicating the end of the string. If |buflen| is less than // the returned length, or |buffer| is NULL, |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetPageLabel(FPDF_DOCUMENT document, int page_index, void* buffer, unsigned long buflen); #ifdef __cplusplus } // extern "C" #endif // __cplusplus #endif // PUBLIC_FPDF_DOC_H_ ================================================ FILE: external/pdfium/windows-x64/include/fpdf_edit.h ================================================ // Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #ifndef PUBLIC_FPDF_EDIT_H_ #define PUBLIC_FPDF_EDIT_H_ #include // NOLINTNEXTLINE(build/include_directory) #include "fpdfview.h" #define FPDF_ARGB(a, r, g, b) \ ((uint32_t)(((uint32_t)(b)&0xff) | (((uint32_t)(g)&0xff) << 8) | \ (((uint32_t)(r)&0xff) << 16) | (((uint32_t)(a)&0xff) << 24))) #define FPDF_GetBValue(argb) ((uint8_t)(argb)) #define FPDF_GetGValue(argb) ((uint8_t)(((uint16_t)(argb)) >> 8)) #define FPDF_GetRValue(argb) ((uint8_t)((argb) >> 16)) #define FPDF_GetAValue(argb) ((uint8_t)((argb) >> 24)) // Refer to PDF Reference version 1.7 table 4.12 for all color space families. #define FPDF_COLORSPACE_UNKNOWN 0 #define FPDF_COLORSPACE_DEVICEGRAY 1 #define FPDF_COLORSPACE_DEVICERGB 2 #define FPDF_COLORSPACE_DEVICECMYK 3 #define FPDF_COLORSPACE_CALGRAY 4 #define FPDF_COLORSPACE_CALRGB 5 #define FPDF_COLORSPACE_LAB 6 #define FPDF_COLORSPACE_ICCBASED 7 #define FPDF_COLORSPACE_SEPARATION 8 #define FPDF_COLORSPACE_DEVICEN 9 #define FPDF_COLORSPACE_INDEXED 10 #define FPDF_COLORSPACE_PATTERN 11 // The page object constants. #define FPDF_PAGEOBJ_UNKNOWN 0 #define FPDF_PAGEOBJ_TEXT 1 #define FPDF_PAGEOBJ_PATH 2 #define FPDF_PAGEOBJ_IMAGE 3 #define FPDF_PAGEOBJ_SHADING 4 #define FPDF_PAGEOBJ_FORM 5 // The path segment constants. #define FPDF_SEGMENT_UNKNOWN -1 #define FPDF_SEGMENT_LINETO 0 #define FPDF_SEGMENT_BEZIERTO 1 #define FPDF_SEGMENT_MOVETO 2 #define FPDF_FILLMODE_NONE 0 #define FPDF_FILLMODE_ALTERNATE 1 #define FPDF_FILLMODE_WINDING 2 #define FPDF_FONT_TYPE1 1 #define FPDF_FONT_TRUETYPE 2 #define FPDF_LINECAP_BUTT 0 #define FPDF_LINECAP_ROUND 1 #define FPDF_LINECAP_PROJECTING_SQUARE 2 #define FPDF_LINEJOIN_MITER 0 #define FPDF_LINEJOIN_ROUND 1 #define FPDF_LINEJOIN_BEVEL 2 // See FPDF_SetPrintMode() for descriptions. #define FPDF_PRINTMODE_EMF 0 #define FPDF_PRINTMODE_TEXTONLY 1 #define FPDF_PRINTMODE_POSTSCRIPT2 2 #define FPDF_PRINTMODE_POSTSCRIPT3 3 #define FPDF_PRINTMODE_POSTSCRIPT2_PASSTHROUGH 4 #define FPDF_PRINTMODE_POSTSCRIPT3_PASSTHROUGH 5 #define FPDF_PRINTMODE_EMF_IMAGE_MASKS 6 #define FPDF_PRINTMODE_POSTSCRIPT3_TYPE42 7 #define FPDF_PRINTMODE_POSTSCRIPT3_TYPE42_PASSTHROUGH 8 typedef struct FPDF_IMAGEOBJ_METADATA { // The image width in pixels. unsigned int width; // The image height in pixels. unsigned int height; // The image's horizontal pixel-per-inch. float horizontal_dpi; // The image's vertical pixel-per-inch. float vertical_dpi; // The number of bits used to represent each pixel. unsigned int bits_per_pixel; // The image's colorspace. See above for the list of FPDF_COLORSPACE_*. int colorspace; // The image's marked content ID. Useful for pairing with associated alt-text. // A value of -1 indicates no ID. int marked_content_id; } FPDF_IMAGEOBJ_METADATA; #ifdef __cplusplus extern "C" { #endif // __cplusplus // Create a new PDF document. // // Returns a handle to a new document, or NULL on failure. FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV FPDF_CreateNewDocument(); // Create a new PDF page. // // document - handle to document. // page_index - suggested 0-based index of the page to create. If it is larger // than document's current last index(L), the created page index // is the next available index -- L+1. // width - the page width in points. // height - the page height in points. // // Returns the handle to the new page or NULL on failure. // // The page should be closed with FPDF_ClosePage() when finished as // with any other page in the document. FPDF_EXPORT FPDF_PAGE FPDF_CALLCONV FPDFPage_New(FPDF_DOCUMENT document, int page_index, double width, double height); // Delete the page at |page_index|. // // document - handle to document. // page_index - the index of the page to delete. FPDF_EXPORT void FPDF_CALLCONV FPDFPage_Delete(FPDF_DOCUMENT document, int page_index); // Experimental API. // Move the given pages to a new index position. // // page_indices - the ordered list of pages to move. No duplicates allowed. // page_indices_len - the number of elements in |page_indices| // dest_page_index - the new index position to which the pages in // |page_indices| are moved. // // Returns TRUE on success. If it returns FALSE, the document may be left in an // indeterminate state. // // Example: The PDF document starts out with pages [A, B, C, D], with indices // [0, 1, 2, 3]. // // > Move(doc, [3, 2], 2, 1); // returns true // > // The document has pages [A, D, C, B]. // > // > Move(doc, [0, 4, 3], 3, 1); // returns false // > // Returned false because index 4 is out of range. // > // > Move(doc, [0, 3, 1], 3, 2); // returns false // > // Returned false because index 2 is out of range for 3 page indices. // > // > Move(doc, [2, 2], 2, 0); // returns false // > // Returned false because [2, 2] contains duplicates. // FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_MovePages(FPDF_DOCUMENT document, const int* page_indices, unsigned long page_indices_len, int dest_page_index); // Get the rotation of |page|. // // page - handle to a page // // Returns one of the following indicating the page rotation: // 0 - No rotation. // 1 - Rotated 90 degrees clockwise. // 2 - Rotated 180 degrees clockwise. // 3 - Rotated 270 degrees clockwise. FPDF_EXPORT int FPDF_CALLCONV FPDFPage_GetRotation(FPDF_PAGE page); // Set rotation for |page|. // // page - handle to a page. // rotate - the rotation value, one of: // 0 - No rotation. // 1 - Rotated 90 degrees clockwise. // 2 - Rotated 180 degrees clockwise. // 3 - Rotated 270 degrees clockwise. FPDF_EXPORT void FPDF_CALLCONV FPDFPage_SetRotation(FPDF_PAGE page, int rotate); // Insert |page_object| into |page|. // // page - handle to a page // page_object - handle to a page object. The |page_object| will be // automatically freed. FPDF_EXPORT void FPDF_CALLCONV FPDFPage_InsertObject(FPDF_PAGE page, FPDF_PAGEOBJECT page_object); // Insert |page_object| into |page| at the specified |index|. // // page - handle to a page // page_object - handle to a page object as previously obtained by // FPDFPageObj_CreateNew{Path|Rect}() or // FPDFPageObj_New{Text|Image}Obj(). Ownership of the object // is transferred back to PDFium. // index - the index position to insert the object at. If index equals // the current object count, the object will be appended to the // end. If index is greater than the object count, the function // will fail and return false. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_InsertObjectAtIndex(FPDF_PAGE page, FPDF_PAGEOBJECT page_object, size_t index); // Experimental API. // Remove |page_object| from |page|. // // page - handle to a page // page_object - handle to a page object to be removed. // // Returns TRUE on success. // // Ownership is transferred to the caller. Call FPDFPageObj_Destroy() to free // it. // Note that when removing a |page_object| of type FPDF_PAGEOBJ_TEXT, all // FPDF_TEXTPAGE handles for |page| are no longer valid. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_RemoveObject(FPDF_PAGE page, FPDF_PAGEOBJECT page_object); // Get number of page objects inside |page|. // // page - handle to a page. // // Returns the number of objects in |page|. FPDF_EXPORT int FPDF_CALLCONV FPDFPage_CountObjects(FPDF_PAGE page); // Get object in |page| at |index|. // // page - handle to a page. // index - the index of a page object. // // Returns the handle to the page object, or NULL on failed. FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV FPDFPage_GetObject(FPDF_PAGE page, int index); // Checks if |page| contains transparency. // // page - handle to a page. // // Returns TRUE if |page| contains transparency. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_HasTransparency(FPDF_PAGE page); // Generate the content of |page|. // // page - handle to a page. // // Returns TRUE on success. // // Before you save the page to a file, or reload the page, you must call // |FPDFPage_GenerateContent| or any changes to |page| will be lost. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_GenerateContent(FPDF_PAGE page); // Destroy |page_object| by releasing its resources. |page_object| must have // been created by FPDFPageObj_CreateNew{Path|Rect}() or // FPDFPageObj_New{Text|Image}Obj(). This function must be called on // newly-created objects if they are not added to a page through // FPDFPage_InsertObject() or to an annotation through FPDFAnnot_AppendObject(). // // page_object - handle to a page object. FPDF_EXPORT void FPDF_CALLCONV FPDFPageObj_Destroy(FPDF_PAGEOBJECT page_object); // Checks if |page_object| contains transparency. // // page_object - handle to a page object. // // Returns TRUE if |page_object| contains transparency. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_HasTransparency(FPDF_PAGEOBJECT page_object); // Get type of |page_object|. // // page_object - handle to a page object. // // Returns one of the FPDF_PAGEOBJ_* values on success, FPDF_PAGEOBJ_UNKNOWN on // error. FPDF_EXPORT int FPDF_CALLCONV FPDFPageObj_GetType(FPDF_PAGEOBJECT page_object); // Experimental API. // Gets active state for |page_object| within page. // // page_object - handle to a page object. // active - pointer to variable that will receive if the page object is // active. This is a required parameter. Not filled if FALSE // is returned. // // For page objects where |active| is filled with FALSE, the |page_object| is // treated as if it wasn't in the document even though it is still held // internally. // // Returns TRUE if the operation succeeded, FALSE if it failed. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_GetIsActive(FPDF_PAGEOBJECT page_object, FPDF_BOOL* active); // Experimental API. // Sets if |page_object| is active within page. // // page_object - handle to a page object. // active - a boolean specifying if the object is active. // // Returns TRUE on success. // // Page objects all start in the active state by default, and remain in that // state unless this function is called. // // When |active| is false, this makes the |page_object| be treated as if it // wasn't in the document even though it is still held internally. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_SetIsActive(FPDF_PAGEOBJECT page_object, FPDF_BOOL active); // Transform |page_object| by the given matrix. // // page_object - handle to a page object. // a - matrix value. // b - matrix value. // c - matrix value. // d - matrix value. // e - matrix value. // f - matrix value. // // The matrix is composed as: // |a c e| // |b d f| // and can be used to scale, rotate, shear and translate the |page_object|. FPDF_EXPORT void FPDF_CALLCONV FPDFPageObj_Transform(FPDF_PAGEOBJECT page_object, double a, double b, double c, double d, double e, double f); // Experimental API. // Transform |page_object| by the given matrix. // // page_object - handle to a page object. // matrix - the transform matrix. // // Returns TRUE on success. // // This can be used to scale, rotate, shear and translate the |page_object|. // It is an improved version of FPDFPageObj_Transform() that does not do // unnecessary double to float conversions, and only uses 1 parameter for the // matrix. It also returns whether the operation succeeded or not. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_TransformF(FPDF_PAGEOBJECT page_object, const FS_MATRIX* matrix); // Experimental API. // Get the transform matrix of a page object. // // page_object - handle to a page object. // matrix - pointer to struct to receive the matrix value. // // The matrix is composed as: // |a c e| // |b d f| // and used to scale, rotate, shear and translate the page object. // // For page objects outside form objects, the matrix values are relative to the // page that contains it. // For page objects inside form objects, the matrix values are relative to the // form that contains it. // // Returns TRUE on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_GetMatrix(FPDF_PAGEOBJECT page_object, FS_MATRIX* matrix); // Experimental API. // Set the transform matrix of a page object. // // page_object - handle to a page object. // matrix - pointer to struct with the matrix value. // // The matrix is composed as: // |a c e| // |b d f| // and can be used to scale, rotate, shear and translate the page object. // // Returns TRUE on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_SetMatrix(FPDF_PAGEOBJECT page_object, const FS_MATRIX* matrix); // Transform all annotations in |page|. // // page - handle to a page. // a - matrix value. // b - matrix value. // c - matrix value. // d - matrix value. // e - matrix value. // f - matrix value. // // The matrix is composed as: // |a c e| // |b d f| // and can be used to scale, rotate, shear and translate the |page| annotations. FPDF_EXPORT void FPDF_CALLCONV FPDFPage_TransformAnnots(FPDF_PAGE page, double a, double b, double c, double d, double e, double f); // Create a new image object. // // document - handle to a document. // // Returns a handle to a new image object. FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV FPDFPageObj_NewImageObj(FPDF_DOCUMENT document); // Experimental API. // Get the marked content ID for the object. // // page_object - handle to a page object. // // Returns the page object's marked content ID, or -1 on error. FPDF_EXPORT int FPDF_CALLCONV FPDFPageObj_GetMarkedContentID(FPDF_PAGEOBJECT page_object); // Experimental API. // Get number of content marks in |page_object|. // // page_object - handle to a page object. // // Returns the number of content marks in |page_object|, or -1 in case of // failure. FPDF_EXPORT int FPDF_CALLCONV FPDFPageObj_CountMarks(FPDF_PAGEOBJECT page_object); // Experimental API. // Get content mark in |page_object| at |index|. // // page_object - handle to a page object. // index - the index of a page object. // // Returns the handle to the content mark, or NULL on failure. The handle is // still owned by the library, and it should not be freed directly. It becomes // invalid if the page object is destroyed, either directly or indirectly by // unloading the page. FPDF_EXPORT FPDF_PAGEOBJECTMARK FPDF_CALLCONV FPDFPageObj_GetMark(FPDF_PAGEOBJECT page_object, unsigned long index); // Experimental API. // Add a new content mark to a |page_object|. // // page_object - handle to a page object. // name - the name (tag) of the mark. // // Returns the handle to the content mark, or NULL on failure. The handle is // still owned by the library, and it should not be freed directly. It becomes // invalid if the page object is destroyed, either directly or indirectly by // unloading the page. FPDF_EXPORT FPDF_PAGEOBJECTMARK FPDF_CALLCONV FPDFPageObj_AddMark(FPDF_PAGEOBJECT page_object, FPDF_BYTESTRING name); // Experimental API. // Removes a content |mark| from a |page_object|. // The mark handle will be invalid after the removal. // // page_object - handle to a page object. // mark - handle to a content mark in that object to remove. // // Returns TRUE if the operation succeeded, FALSE if it failed. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_RemoveMark(FPDF_PAGEOBJECT page_object, FPDF_PAGEOBJECTMARK mark); // Experimental API. // Get the name of a content mark. // // mark - handle to a content mark. // buffer - buffer for holding the returned name in UTF-16LE. This is only // modified if |buflen| is large enough to store the name. // Optional, pass null to just retrieve the size of the buffer // needed. // buflen - length of the buffer in bytes. // out_buflen - pointer to variable that will receive the minimum buffer size // in bytes to contain the name. This is a required parameter. // Not filled if FALSE is returned. // // Returns TRUE if the operation succeeded, FALSE if it failed. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObjMark_GetName(FPDF_PAGEOBJECTMARK mark, FPDF_WCHAR* buffer, unsigned long buflen, unsigned long* out_buflen); // Experimental API. // Get the number of key/value pair parameters in |mark|. // // mark - handle to a content mark. // // Returns the number of key/value pair parameters |mark|, or -1 in case of // failure. FPDF_EXPORT int FPDF_CALLCONV FPDFPageObjMark_CountParams(FPDF_PAGEOBJECTMARK mark); // Experimental API. // Get the key of a property in a content mark. // // mark - handle to a content mark. // index - index of the property. // buffer - buffer for holding the returned key in UTF-16LE. This is only // modified if |buflen| is large enough to store the key. // Optional, pass null to just retrieve the size of the buffer // needed. // buflen - length of the buffer in bytes. // out_buflen - pointer to variable that will receive the minimum buffer size // in bytes to contain the name. This is a required parameter. // Not filled if FALSE is returned. // // Returns TRUE if the operation was successful, FALSE otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObjMark_GetParamKey(FPDF_PAGEOBJECTMARK mark, unsigned long index, FPDF_WCHAR* buffer, unsigned long buflen, unsigned long* out_buflen); // Experimental API. // Get the type of the value of a property in a content mark by key. // // mark - handle to a content mark. // key - string key of the property. // // Returns the type of the value, or FPDF_OBJECT_UNKNOWN in case of failure. FPDF_EXPORT FPDF_OBJECT_TYPE FPDF_CALLCONV FPDFPageObjMark_GetParamValueType(FPDF_PAGEOBJECTMARK mark, FPDF_BYTESTRING key); // Experimental API. // Get the value of a number property in a content mark by key as int. // FPDFPageObjMark_GetParamValueType() should have returned FPDF_OBJECT_NUMBER // for this property. // // mark - handle to a content mark. // key - string key of the property. // out_value - pointer to variable that will receive the value. Not filled if // false is returned. // // Returns TRUE if the key maps to a number value, FALSE otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObjMark_GetParamIntValue(FPDF_PAGEOBJECTMARK mark, FPDF_BYTESTRING key, int* out_value); // Experimental API. // Get the value of a number property in a content mark by key as float. // FPDFPageObjMark_GetParamValueType() should have returned FPDF_OBJECT_NUMBER // for this property. // // mark - handle to a content mark. // key - string key of the property. // out_value - pointer to variable that will receive the value. Not filled if // false is returned. // // Returns TRUE if the key maps to a number value, FALSE otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObjMark_GetParamFloatValue(FPDF_PAGEOBJECTMARK mark, FPDF_BYTESTRING key, float* out_value); // Experimental API. // Get the value of a string property in a content mark by key. // // mark - handle to a content mark. // key - string key of the property. // buffer - buffer for holding the returned value in UTF-16LE. This is // only modified if |buflen| is large enough to store the value. // Optional, pass null to just retrieve the size of the buffer // needed. // buflen - length of the buffer in bytes. // out_buflen - pointer to variable that will receive the minimum buffer size // in bytes to contain the name. This is a required parameter. // Not filled if FALSE is returned. // // Returns TRUE if the key maps to a string/blob value, FALSE otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObjMark_GetParamStringValue(FPDF_PAGEOBJECTMARK mark, FPDF_BYTESTRING key, FPDF_WCHAR* buffer, unsigned long buflen, unsigned long* out_buflen); // Experimental API. // Get the value of a blob property in a content mark by key. // // mark - handle to a content mark. // key - string key of the property. // buffer - buffer for holding the returned value. This is only modified // if |buflen| is large enough to store the value. // Optional, pass null to just retrieve the size of the buffer // needed. // buflen - length of the buffer in bytes. // out_buflen - pointer to variable that will receive the minimum buffer size // in bytes to contain the name. This is a required parameter. // Not filled if FALSE is returned. // // Returns TRUE if the key maps to a string/blob value, FALSE otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObjMark_GetParamBlobValue(FPDF_PAGEOBJECTMARK mark, FPDF_BYTESTRING key, unsigned char* buffer, unsigned long buflen, unsigned long* out_buflen); // Experimental API. // Set the value of an int property in a content mark by key. If a parameter // with key |key| exists, its value is set to |value|. Otherwise, it is added as // a new parameter. // // document - handle to the document. // page_object - handle to the page object with the mark. // mark - handle to a content mark. // key - string key of the property. // value - int value to set. // // Returns TRUE if the operation succeeded, FALSE otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObjMark_SetIntParam(FPDF_DOCUMENT document, FPDF_PAGEOBJECT page_object, FPDF_PAGEOBJECTMARK mark, FPDF_BYTESTRING key, int value); // Experimental API. // Set the value of a float property in a content mark by key. If a parameter // with key |key| exists, its value is set to |value|. Otherwise, it is added as // a new parameter. // // document - handle to the document. // page_object - handle to the page object with the mark. // mark - handle to a content mark. // key - string key of the property. // value - float value to set. // // Returns TRUE if the operation succeeded, FALSE otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObjMark_SetFloatParam(FPDF_DOCUMENT document, FPDF_PAGEOBJECT page_object, FPDF_PAGEOBJECTMARK mark, FPDF_BYTESTRING key, float value); // Experimental API. // Set the value of a string property in a content mark by key. If a parameter // with key |key| exists, its value is set to |value|. Otherwise, it is added as // a new parameter. // // document - handle to the document. // page_object - handle to the page object with the mark. // mark - handle to a content mark. // key - string key of the property. // value - string value to set. // // Returns TRUE if the operation succeeded, FALSE otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObjMark_SetStringParam(FPDF_DOCUMENT document, FPDF_PAGEOBJECT page_object, FPDF_PAGEOBJECTMARK mark, FPDF_BYTESTRING key, FPDF_BYTESTRING value); // Experimental API. // Set the value of a blob property in a content mark by key. If a parameter // with key |key| exists, its value is set to |value|. Otherwise, it is added as // a new parameter. // // document - handle to the document. // page_object - handle to the page object with the mark. // mark - handle to a content mark. // key - string key of the property. // value - pointer to blob value to set. // value_len - size in bytes of |value|. // // Returns TRUE if the operation succeeded, FALSE otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObjMark_SetBlobParam(FPDF_DOCUMENT document, FPDF_PAGEOBJECT page_object, FPDF_PAGEOBJECTMARK mark, FPDF_BYTESTRING key, const unsigned char* value, unsigned long value_len); // Experimental API. // Removes a property from a content mark by key. // // page_object - handle to the page object with the mark. // mark - handle to a content mark. // key - string key of the property. // // Returns TRUE if the operation succeeded, FALSE otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObjMark_RemoveParam(FPDF_PAGEOBJECT page_object, FPDF_PAGEOBJECTMARK mark, FPDF_BYTESTRING key); // Load an image from a JPEG image file and then set it into |image_object|. // // pages - pointer to the start of all loaded pages, may be NULL. // count - number of |pages|, may be 0. // image_object - handle to an image object. // file_access - file access handler which specifies the JPEG image file. // // Returns TRUE on success. // // The image object might already have an associated image, which is shared and // cached by the loaded pages. In that case, we need to clear the cached image // for all the loaded pages. Pass |pages| and page count (|count|) to this API // to clear the image cache. If the image is not previously shared, or NULL is a // valid |pages| value. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFImageObj_LoadJpegFile(FPDF_PAGE* pages, int count, FPDF_PAGEOBJECT image_object, FPDF_FILEACCESS* file_access); // Load an image from a JPEG image file and then set it into |image_object|. // // pages - pointer to the start of all loaded pages, may be NULL. // count - number of |pages|, may be 0. // image_object - handle to an image object. // file_access - file access handler which specifies the JPEG image file. // // Returns TRUE on success. // // The image object might already have an associated image, which is shared and // cached by the loaded pages. In that case, we need to clear the cached image // for all the loaded pages. Pass |pages| and page count (|count|) to this API // to clear the image cache. If the image is not previously shared, or NULL is a // valid |pages| value. This function loads the JPEG image inline, so the image // content is copied to the file. This allows |file_access| and its associated // data to be deleted after this function returns. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFImageObj_LoadJpegFileInline(FPDF_PAGE* pages, int count, FPDF_PAGEOBJECT image_object, FPDF_FILEACCESS* file_access); // TODO(thestig): Start deprecating this once FPDFPageObj_SetMatrix() is stable. // // Set the transform matrix of |image_object|. // // image_object - handle to an image object. // a - matrix value. // b - matrix value. // c - matrix value. // d - matrix value. // e - matrix value. // f - matrix value. // // The matrix is composed as: // |a c e| // |b d f| // and can be used to scale, rotate, shear and translate the |image_object|. // // Returns TRUE on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFImageObj_SetMatrix(FPDF_PAGEOBJECT image_object, double a, double b, double c, double d, double e, double f); // Set |bitmap| to |image_object|. // // pages - pointer to the start of all loaded pages, may be NULL. // count - number of |pages|, may be 0. // image_object - handle to an image object. // bitmap - handle of the bitmap. // // Returns TRUE on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFImageObj_SetBitmap(FPDF_PAGE* pages, int count, FPDF_PAGEOBJECT image_object, FPDF_BITMAP bitmap); // Get a bitmap rasterization of |image_object|. FPDFImageObj_GetBitmap() only // operates on |image_object| and does not take the associated image mask into // account. It also ignores the matrix for |image_object|. // The returned bitmap will be owned by the caller, and FPDFBitmap_Destroy() // must be called on the returned bitmap when it is no longer needed. // // image_object - handle to an image object. // // Returns the bitmap. FPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV FPDFImageObj_GetBitmap(FPDF_PAGEOBJECT image_object); // Experimental API. // Get a bitmap rasterization of |image_object| that takes the image mask and // image matrix into account. To render correctly, the caller must provide the // |document| associated with |image_object|. If there is a |page| associated // with |image_object|, the caller should provide that as well. // The returned bitmap will be owned by the caller, and FPDFBitmap_Destroy() // must be called on the returned bitmap when it is no longer needed. // // document - handle to a document associated with |image_object|. // page - handle to an optional page associated with |image_object|. // image_object - handle to an image object. // // Returns the bitmap or NULL on failure. FPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV FPDFImageObj_GetRenderedBitmap(FPDF_DOCUMENT document, FPDF_PAGE page, FPDF_PAGEOBJECT image_object); // Get the decoded image data of |image_object|. The decoded data is the // uncompressed image data, i.e. the raw image data after having all filters // applied. |buffer| is only modified if |buflen| is longer than the length of // the decoded image data. // // image_object - handle to an image object. // buffer - buffer for holding the decoded image data. // buflen - length of the buffer in bytes. // // Returns the length of the decoded image data. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFImageObj_GetImageDataDecoded(FPDF_PAGEOBJECT image_object, void* buffer, unsigned long buflen); // Get the raw image data of |image_object|. The raw data is the image data as // stored in the PDF without applying any filters. |buffer| is only modified if // |buflen| is longer than the length of the raw image data. // // image_object - handle to an image object. // buffer - buffer for holding the raw image data. // buflen - length of the buffer in bytes. // // Returns the length of the raw image data. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFImageObj_GetImageDataRaw(FPDF_PAGEOBJECT image_object, void* buffer, unsigned long buflen); // Get the number of filters (i.e. decoders) of the image in |image_object|. // // image_object - handle to an image object. // // Returns the number of |image_object|'s filters. FPDF_EXPORT int FPDF_CALLCONV FPDFImageObj_GetImageFilterCount(FPDF_PAGEOBJECT image_object); // Get the filter at |index| of |image_object|'s list of filters. Note that the // filters need to be applied in order, i.e. the first filter should be applied // first, then the second, etc. |buffer| is only modified if |buflen| is longer // than the length of the filter string. // // image_object - handle to an image object. // index - the index of the filter requested. // buffer - buffer for holding filter string, encoded in UTF-8. // buflen - length of the buffer. // // Returns the length of the filter string. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFImageObj_GetImageFilter(FPDF_PAGEOBJECT image_object, int index, void* buffer, unsigned long buflen); // Get the image metadata of |image_object|, including dimension, DPI, bits per // pixel, and colorspace. If the |image_object| is not an image object or if it // does not have an image, then the return value will be false. Otherwise, // failure to retrieve any specific parameter would result in its value being 0. // // image_object - handle to an image object. // page - handle to the page that |image_object| is on. Required for // retrieving the image's bits per pixel and colorspace. // metadata - receives the image metadata; must not be NULL. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFImageObj_GetImageMetadata(FPDF_PAGEOBJECT image_object, FPDF_PAGE page, FPDF_IMAGEOBJ_METADATA* metadata); // Experimental API. // Get the image size in pixels. Faster method to get only image size. // // image_object - handle to an image object. // width - receives the image width in pixels; must not be NULL. // height - receives the image height in pixels; must not be NULL. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFImageObj_GetImagePixelSize(FPDF_PAGEOBJECT image_object, unsigned int* width, unsigned int* height); // Experimental API. // Get ICC profile decoded data of |image_object|. If the |image_object| is not // an image object or if it does not have an image, then the return value will // be false. It also returns false if the |image_object| has no ICC profile. // |buffer| is only modified if ICC profile exists and |buflen| is longer than // the length of the ICC profile decoded data. // // image_object - handle to an image object; must not be NULL. // page - handle to the page containing |image_object|; must not be // NULL. Required for retrieving the image's colorspace. // buffer - Buffer to receive ICC profile data; may be NULL if querying // required size via |out_buflen|. // buflen - Length of the buffer in bytes. Ignored if |buffer| is NULL. // out_buflen - Pointer to receive the ICC profile data size in bytes; must // not be NULL. Will be set if this API returns true. // // Returns true if |out_buflen| is not null and an ICC profile exists for the // given |image_object|. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFImageObj_GetIccProfileDataDecoded(FPDF_PAGEOBJECT image_object, FPDF_PAGE page, uint8_t* buffer, size_t buflen, size_t* out_buflen); // Create a new path object at an initial position. // // x - initial horizontal position. // y - initial vertical position. // // Returns a handle to a new path object. FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV FPDFPageObj_CreateNewPath(float x, float y); // Create a closed path consisting of a rectangle. // // x - horizontal position for the left boundary of the rectangle. // y - vertical position for the bottom boundary of the rectangle. // w - width of the rectangle. // h - height of the rectangle. // // Returns a handle to the new path object. FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV FPDFPageObj_CreateNewRect(float x, float y, float w, float h); // Get the bounding box of |page_object|. // // page_object - handle to a page object. // left - pointer where the left coordinate will be stored // bottom - pointer where the bottom coordinate will be stored // right - pointer where the right coordinate will be stored // top - pointer where the top coordinate will be stored // // On success, returns TRUE and fills in the 4 coordinates. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_GetBounds(FPDF_PAGEOBJECT page_object, float* left, float* bottom, float* right, float* top); // Experimental API. // Get the quad points that bounds |page_object|. // // page_object - handle to a page object. // quad_points - pointer where the quadrilateral points will be stored. // // On success, returns TRUE and fills in |quad_points|. // // Similar to FPDFPageObj_GetBounds(), this returns the bounds of a page // object. When the object is rotated by a non-multiple of 90 degrees, this API // returns a tighter bound that cannot be represented with just the 4 sides of // a rectangle. // // Currently only works the following |page_object| types: FPDF_PAGEOBJ_TEXT and // FPDF_PAGEOBJ_IMAGE. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_GetRotatedBounds(FPDF_PAGEOBJECT page_object, FS_QUADPOINTSF* quad_points); // Set the blend mode of |page_object|. // // page_object - handle to a page object. // blend_mode - string containing the blend mode. // // Blend mode can be one of following: Color, ColorBurn, ColorDodge, Darken, // Difference, Exclusion, HardLight, Hue, Lighten, Luminosity, Multiply, Normal, // Overlay, Saturation, Screen, SoftLight FPDF_EXPORT void FPDF_CALLCONV FPDFPageObj_SetBlendMode(FPDF_PAGEOBJECT page_object, FPDF_BYTESTRING blend_mode); // Set the stroke RGBA of a page object. Range of values: 0 - 255. // // page_object - the handle to the page object. // R - the red component for the object's stroke color. // G - the green component for the object's stroke color. // B - the blue component for the object's stroke color. // A - the stroke alpha for the object. // // Returns TRUE on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_SetStrokeColor(FPDF_PAGEOBJECT page_object, unsigned int R, unsigned int G, unsigned int B, unsigned int A); // Get the stroke RGBA of a page object. Range of values: 0 - 255. // // page_object - the handle to the page object. // R - the red component of the path stroke color. // G - the green component of the object's stroke color. // B - the blue component of the object's stroke color. // A - the stroke alpha of the object. // // Returns TRUE on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_GetStrokeColor(FPDF_PAGEOBJECT page_object, unsigned int* R, unsigned int* G, unsigned int* B, unsigned int* A); // Set the stroke width of a page object. // // path - the handle to the page object. // width - the width of the stroke. // // Returns TRUE on success FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_SetStrokeWidth(FPDF_PAGEOBJECT page_object, float width); // Get the stroke width of a page object. // // path - the handle to the page object. // width - the width of the stroke. // // Returns TRUE on success FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_GetStrokeWidth(FPDF_PAGEOBJECT page_object, float* width); // Get the line join of |page_object|. // // page_object - handle to a page object. // // Returns the line join, or -1 on failure. // Line join can be one of following: FPDF_LINEJOIN_MITER, FPDF_LINEJOIN_ROUND, // FPDF_LINEJOIN_BEVEL FPDF_EXPORT int FPDF_CALLCONV FPDFPageObj_GetLineJoin(FPDF_PAGEOBJECT page_object); // Set the line join of |page_object|. // // page_object - handle to a page object. // line_join - line join // // Line join can be one of following: FPDF_LINEJOIN_MITER, FPDF_LINEJOIN_ROUND, // FPDF_LINEJOIN_BEVEL FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_SetLineJoin(FPDF_PAGEOBJECT page_object, int line_join); // Get the line cap of |page_object|. // // page_object - handle to a page object. // // Returns the line cap, or -1 on failure. // Line cap can be one of following: FPDF_LINECAP_BUTT, FPDF_LINECAP_ROUND, // FPDF_LINECAP_PROJECTING_SQUARE FPDF_EXPORT int FPDF_CALLCONV FPDFPageObj_GetLineCap(FPDF_PAGEOBJECT page_object); // Set the line cap of |page_object|. // // page_object - handle to a page object. // line_cap - line cap // // Line cap can be one of following: FPDF_LINECAP_BUTT, FPDF_LINECAP_ROUND, // FPDF_LINECAP_PROJECTING_SQUARE FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_SetLineCap(FPDF_PAGEOBJECT page_object, int line_cap); // Set the fill RGBA of a page object. Range of values: 0 - 255. // // page_object - the handle to the page object. // R - the red component for the object's fill color. // G - the green component for the object's fill color. // B - the blue component for the object's fill color. // A - the fill alpha for the object. // // Returns TRUE on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_SetFillColor(FPDF_PAGEOBJECT page_object, unsigned int R, unsigned int G, unsigned int B, unsigned int A); // Get the fill RGBA of a page object. Range of values: 0 - 255. // // page_object - the handle to the page object. // R - the red component of the object's fill color. // G - the green component of the object's fill color. // B - the blue component of the object's fill color. // A - the fill alpha of the object. // // Returns TRUE on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_GetFillColor(FPDF_PAGEOBJECT page_object, unsigned int* R, unsigned int* G, unsigned int* B, unsigned int* A); // Experimental API. // Get the line dash |phase| of |page_object|. // // page_object - handle to a page object. // phase - pointer where the dashing phase will be stored. // // Returns TRUE on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_GetDashPhase(FPDF_PAGEOBJECT page_object, float* phase); // Experimental API. // Set the line dash phase of |page_object|. // // page_object - handle to a page object. // phase - line dash phase. // // Returns TRUE on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_SetDashPhase(FPDF_PAGEOBJECT page_object, float phase); // Experimental API. // Get the line dash array of |page_object|. // // page_object - handle to a page object. // // Returns the line dash array size or -1 on failure. FPDF_EXPORT int FPDF_CALLCONV FPDFPageObj_GetDashCount(FPDF_PAGEOBJECT page_object); // Experimental API. // Get the line dash array of |page_object|. // // page_object - handle to a page object. // dash_array - pointer where the dashing array will be stored. // dash_count - number of elements in |dash_array|. // // Returns TRUE on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_GetDashArray(FPDF_PAGEOBJECT page_object, float* dash_array, size_t dash_count); // Experimental API. // Set the line dash array of |page_object|. // // page_object - handle to a page object. // dash_array - the dash array. // dash_count - number of elements in |dash_array|. // phase - the line dash phase. // // Returns TRUE on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_SetDashArray(FPDF_PAGEOBJECT page_object, const float* dash_array, size_t dash_count, float phase); // Get number of segments inside |path|. // // path - handle to a path. // // A segment is a command, created by e.g. FPDFPath_MoveTo(), // FPDFPath_LineTo() or FPDFPath_BezierTo(). // // Returns the number of objects in |path| or -1 on failure. FPDF_EXPORT int FPDF_CALLCONV FPDFPath_CountSegments(FPDF_PAGEOBJECT path); // Get segment in |path| at |index|. // // path - handle to a path. // index - the index of a segment. // // Returns the handle to the segment, or NULL on faiure. FPDF_EXPORT FPDF_PATHSEGMENT FPDF_CALLCONV FPDFPath_GetPathSegment(FPDF_PAGEOBJECT path, int index); // Get coordinates of |segment|. // // segment - handle to a segment. // x - the horizontal position of the segment. // y - the vertical position of the segment. // // Returns TRUE on success, otherwise |x| and |y| is not set. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPathSegment_GetPoint(FPDF_PATHSEGMENT segment, float* x, float* y); // Get type of |segment|. // // segment - handle to a segment. // // Returns one of the FPDF_SEGMENT_* values on success, // FPDF_SEGMENT_UNKNOWN on error. FPDF_EXPORT int FPDF_CALLCONV FPDFPathSegment_GetType(FPDF_PATHSEGMENT segment); // Gets if the |segment| closes the current subpath of a given path. // // segment - handle to a segment. // // Returns close flag for non-NULL segment, FALSE otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPathSegment_GetClose(FPDF_PATHSEGMENT segment); // Move a path's current point. // // path - the handle to the path object. // x - the horizontal position of the new current point. // y - the vertical position of the new current point. // // Note that no line will be created between the previous current point and the // new one. // // Returns TRUE on success FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_MoveTo(FPDF_PAGEOBJECT path, float x, float y); // Add a line between the current point and a new point in the path. // // path - the handle to the path object. // x - the horizontal position of the new point. // y - the vertical position of the new point. // // The path's current point is changed to (x, y). // // Returns TRUE on success FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_LineTo(FPDF_PAGEOBJECT path, float x, float y); // Add a cubic Bezier curve to the given path, starting at the current point. // // path - the handle to the path object. // x1 - the horizontal position of the first Bezier control point. // y1 - the vertical position of the first Bezier control point. // x2 - the horizontal position of the second Bezier control point. // y2 - the vertical position of the second Bezier control point. // x3 - the horizontal position of the ending point of the Bezier curve. // y3 - the vertical position of the ending point of the Bezier curve. // // Returns TRUE on success FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_BezierTo(FPDF_PAGEOBJECT path, float x1, float y1, float x2, float y2, float x3, float y3); // Close the current subpath of a given path. // // path - the handle to the path object. // // This will add a line between the current point and the initial point of the // subpath, thus terminating the current subpath. // // Returns TRUE on success FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_Close(FPDF_PAGEOBJECT path); // Set the drawing mode of a path. // // path - the handle to the path object. // fillmode - the filling mode to be set: one of the FPDF_FILLMODE_* flags. // stroke - a boolean specifying if the path should be stroked or not. // // Returns TRUE on success FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_SetDrawMode(FPDF_PAGEOBJECT path, int fillmode, FPDF_BOOL stroke); // Get the drawing mode of a path. // // path - the handle to the path object. // fillmode - the filling mode of the path: one of the FPDF_FILLMODE_* flags. // stroke - a boolean specifying if the path is stroked or not. // // Returns TRUE on success FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_GetDrawMode(FPDF_PAGEOBJECT path, int* fillmode, FPDF_BOOL* stroke); // Create a new text object using one of the standard PDF fonts. // // document - handle to the document. // font - string containing the font name, without spaces. // font_size - the font size for the new text object. // // Returns a handle to a new text object, or NULL on failure FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV FPDFPageObj_NewTextObj(FPDF_DOCUMENT document, FPDF_BYTESTRING font, float font_size); // Set the text for a text object. If it had text, it will be replaced. // // text_object - handle to the text object. // text - the UTF-16LE encoded string containing the text to be added. // // Returns TRUE on success FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFText_SetText(FPDF_PAGEOBJECT text_object, FPDF_WIDESTRING text); // Experimental API. // Set the text using charcodes for a text object. If it had text, it will be // replaced. // // text_object - handle to the text object. // charcodes - pointer to an array of charcodes to be added. // count - number of elements in |charcodes|. // // Returns TRUE on success FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFText_SetCharcodes(FPDF_PAGEOBJECT text_object, const uint32_t* charcodes, size_t count); // Returns a font object loaded from a stream of data. The font is loaded // into the document. Various font data structures, such as the ToUnicode data, // are auto-generated based on the inputs. // // document - handle to the document. // data - the stream of font data, which will be copied by the font object. // size - the size of the font data, in bytes. // font_type - FPDF_FONT_TYPE1 or FPDF_FONT_TRUETYPE depending on the font type. // cid - a boolean specifying if the font is a CID font or not. // // The loaded font can be closed using FPDFFont_Close(). // // Returns NULL on failure FPDF_EXPORT FPDF_FONT FPDF_CALLCONV FPDFText_LoadFont(FPDF_DOCUMENT document, const uint8_t* data, uint32_t size, int font_type, FPDF_BOOL cid); // Experimental API. // Loads one of the standard 14 fonts per PDF spec 1.7 page 416. The preferred // way of using font style is using a dash to separate the name from the style, // for example 'Helvetica-BoldItalic'. // // document - handle to the document. // font - string containing the font name, without spaces. // // The loaded font can be closed using FPDFFont_Close(). // // Returns NULL on failure. FPDF_EXPORT FPDF_FONT FPDF_CALLCONV FPDFText_LoadStandardFont(FPDF_DOCUMENT document, FPDF_BYTESTRING font); // Experimental API. // Returns a font object loaded from a stream of data for a type 2 CID font. The // font is loaded into the document. Unlike FPDFText_LoadFont(), the ToUnicode // data and the CIDToGIDMap data are caller provided, instead of auto-generated. // // document - handle to the document. // font_data - the stream of font data, which will be copied by // the font object. // font_data_size - the size of the font data, in bytes. // to_unicode_cmap - the ToUnicode data. // cid_to_gid_map_data - the stream of CIDToGIDMap data. // cid_to_gid_map_data_size - the size of the CIDToGIDMap data, in bytes. // // The loaded font can be closed using FPDFFont_Close(). // // Returns NULL on failure. FPDF_EXPORT FPDF_FONT FPDF_CALLCONV FPDFText_LoadCidType2Font(FPDF_DOCUMENT document, const uint8_t* font_data, uint32_t font_data_size, FPDF_BYTESTRING to_unicode_cmap, const uint8_t* cid_to_gid_map_data, uint32_t cid_to_gid_map_data_size); // Get the font size of a text object. // // text - handle to a text. // size - pointer to the font size of the text object, measured in points // (about 1/72 inch) // // Returns TRUE on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFTextObj_GetFontSize(FPDF_PAGEOBJECT text, float* size); // Close a loaded PDF font. // // font - Handle to the loaded font. FPDF_EXPORT void FPDF_CALLCONV FPDFFont_Close(FPDF_FONT font); // Create a new text object using a loaded font. // // document - handle to the document. // font - handle to the font object. // font_size - the font size for the new text object. // // Returns a handle to a new text object, or NULL on failure FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV FPDFPageObj_CreateTextObj(FPDF_DOCUMENT document, FPDF_FONT font, float font_size); // Get the text rendering mode of a text object. // // text - the handle to the text object. // // Returns one of the known FPDF_TEXT_RENDERMODE enum values on success, // FPDF_TEXTRENDERMODE_UNKNOWN on error. FPDF_EXPORT FPDF_TEXT_RENDERMODE FPDF_CALLCONV FPDFTextObj_GetTextRenderMode(FPDF_PAGEOBJECT text); // Experimental API. // Set the text rendering mode of a text object. // // text - the handle to the text object. // render_mode - the FPDF_TEXT_RENDERMODE enum value to be set (cannot set to // FPDF_TEXTRENDERMODE_UNKNOWN). // // Returns TRUE on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFTextObj_SetTextRenderMode(FPDF_PAGEOBJECT text, FPDF_TEXT_RENDERMODE render_mode); // Get the text of a text object. // // text_object - the handle to the text object. // text_page - the handle to the text page. // buffer - the address of a buffer that receives the text. // length - the size, in bytes, of |buffer|. // // Returns the number of bytes in the text (including the trailing NUL // character) on success, 0 on error. // // Regardless of the platform, the |buffer| is always in UTF-16LE encoding. // If |length| is less than the returned length, or |buffer| is NULL, |buffer| // will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFTextObj_GetText(FPDF_PAGEOBJECT text_object, FPDF_TEXTPAGE text_page, FPDF_WCHAR* buffer, unsigned long length); // Experimental API. // Get a bitmap rasterization of |text_object|. To render correctly, the caller // must provide the |document| associated with |text_object|. If there is a // |page| associated with |text_object|, the caller should provide that as well. // The returned bitmap will be owned by the caller, and FPDFBitmap_Destroy() // must be called on the returned bitmap when it is no longer needed. // // document - handle to a document associated with |text_object|. // page - handle to an optional page associated with |text_object|. // text_object - handle to a text object. // scale - the scaling factor, which must be greater than 0. // // Returns the bitmap or NULL on failure. FPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV FPDFTextObj_GetRenderedBitmap(FPDF_DOCUMENT document, FPDF_PAGE page, FPDF_PAGEOBJECT text_object, float scale); // Experimental API. // Get the font of a text object. // // text - the handle to the text object. // // Returns a handle to the font object held by |text| which retains ownership. FPDF_EXPORT FPDF_FONT FPDF_CALLCONV FPDFTextObj_GetFont(FPDF_PAGEOBJECT text); // Experimental API. // Get the base name of a font. // // font - the handle to the font object. // buffer - the address of a buffer that receives the base font name. // length - the size, in bytes, of |buffer|. // // Returns the number of bytes in the base name (including the trailing NUL // character) on success, 0 on error. The base name is typically the font's // PostScript name. See descriptions of "BaseFont" in ISO 32000-1:2008 spec. // // Regardless of the platform, the |buffer| is always in UTF-8 encoding. // If |length| is less than the returned length, or |buffer| is NULL, |buffer| // will not be modified. FPDF_EXPORT size_t FPDF_CALLCONV FPDFFont_GetBaseFontName(FPDF_FONT font, char* buffer, size_t length); // Experimental API. // Get the family name of a font. // // font - the handle to the font object. // buffer - the address of a buffer that receives the font name. // length - the size, in bytes, of |buffer|. // // Returns the number of bytes in the family name (including the trailing NUL // character) on success, 0 on error. // // Regardless of the platform, the |buffer| is always in UTF-8 encoding. // If |length| is less than the returned length, or |buffer| is NULL, |buffer| // will not be modified. FPDF_EXPORT size_t FPDF_CALLCONV FPDFFont_GetFamilyName(FPDF_FONT font, char* buffer, size_t length); // Experimental API. // Get the decoded data from the |font| object. // // font - The handle to the font object. (Required) // buffer - The address of a buffer that receives the font data. // buflen - Length of the buffer. // out_buflen - Pointer to variable that will receive the minimum buffer size // to contain the font data. Not filled if the return value is // FALSE. (Required) // // Returns TRUE on success. In which case, |out_buflen| will be filled, and // |buffer| will be filled if it is large enough. Returns FALSE if any of the // required parameters are null. // // The decoded data is the uncompressed font data. i.e. the raw font data after // having all stream filters applied, when the data is embedded. // // If the font is not embedded, then this API will instead return the data for // the substitution font it is using. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFFont_GetFontData(FPDF_FONT font, uint8_t* buffer, size_t buflen, size_t* out_buflen); // Experimental API. // Get whether |font| is embedded or not. // // font - the handle to the font object. // // Returns 1 if the font is embedded, 0 if it not, and -1 on failure. FPDF_EXPORT int FPDF_CALLCONV FPDFFont_GetIsEmbedded(FPDF_FONT font); // Experimental API. // Get the descriptor flags of a font. // // font - the handle to the font object. // // Returns the bit flags specifying various characteristics of the font as // defined in ISO 32000-1:2008, table 123, -1 on failure. FPDF_EXPORT int FPDF_CALLCONV FPDFFont_GetFlags(FPDF_FONT font); // Experimental API. // Get the font weight of a font. // // font - the handle to the font object. // // Returns the font weight, -1 on failure. // Typical values are 400 (normal) and 700 (bold). FPDF_EXPORT int FPDF_CALLCONV FPDFFont_GetWeight(FPDF_FONT font); // Experimental API. // Get the italic angle of a font. // // font - the handle to the font object. // angle - pointer where the italic angle will be stored // // The italic angle of a |font| is defined as degrees counterclockwise // from vertical. For a font that slopes to the right, this will be negative. // // Returns TRUE on success; |angle| unmodified on failure. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFFont_GetItalicAngle(FPDF_FONT font, int* angle); // Experimental API. // Get ascent distance of a font. // // font - the handle to the font object. // font_size - the size of the |font|. // ascent - pointer where the font ascent will be stored // // Ascent is the maximum distance in points above the baseline reached by the // glyphs of the |font|. One point is 1/72 inch (around 0.3528 mm). // // Returns TRUE on success; |ascent| unmodified on failure. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFFont_GetAscent(FPDF_FONT font, float font_size, float* ascent); // Experimental API. // Get descent distance of a font. // // font - the handle to the font object. // font_size - the size of the |font|. // descent - pointer where the font descent will be stored // // Descent is the maximum distance in points below the baseline reached by the // glyphs of the |font|. One point is 1/72 inch (around 0.3528 mm). // // Returns TRUE on success; |descent| unmodified on failure. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFFont_GetDescent(FPDF_FONT font, float font_size, float* descent); // Experimental API. // Get the width of a glyph in a font. // // font - the handle to the font object. // glyph - the glyph. // font_size - the size of the font. // width - pointer where the glyph width will be stored // // Glyph width is the distance from the end of the prior glyph to the next // glyph. This will be the vertical distance for vertical writing. // // Returns TRUE on success; |width| unmodified on failure. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFFont_GetGlyphWidth(FPDF_FONT font, uint32_t glyph, float font_size, float* width); // Experimental API. // Get the glyphpath describing how to draw a font glyph. // // font - the handle to the font object. // glyph - the glyph being drawn. // font_size - the size of the font. // // Returns the handle to the segment, or NULL on faiure. FPDF_EXPORT FPDF_GLYPHPATH FPDF_CALLCONV FPDFFont_GetGlyphPath(FPDF_FONT font, uint32_t glyph, float font_size); // Experimental API. // Get number of segments inside glyphpath. // // glyphpath - handle to a glyph path. // // Returns the number of objects in |glyphpath| or -1 on failure. FPDF_EXPORT int FPDF_CALLCONV FPDFGlyphPath_CountGlyphSegments(FPDF_GLYPHPATH glyphpath); // Experimental API. // Get segment in glyphpath at index. // // glyphpath - handle to a glyph path. // index - the index of a segment. // // Returns the handle to the segment, or NULL on faiure. FPDF_EXPORT FPDF_PATHSEGMENT FPDF_CALLCONV FPDFGlyphPath_GetGlyphPathSegment(FPDF_GLYPHPATH glyphpath, int index); // Get number of page objects inside |form_object|. // // form_object - handle to a form object. // // Returns the number of objects in |form_object| on success, -1 on error. FPDF_EXPORT int FPDF_CALLCONV FPDFFormObj_CountObjects(FPDF_PAGEOBJECT form_object); // Get page object in |form_object| at |index|. // // form_object - handle to a form object. // index - the 0-based index of a page object. // // Returns the handle to the page object, or NULL on error. FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV FPDFFormObj_GetObject(FPDF_PAGEOBJECT form_object, unsigned long index); // Experimental API. // // Remove |page_object| from |form_object|. // // form_object - handle to a form object. // page_object - handle to a page object to be removed from the form. // // Returns TRUE on success. // // Ownership of the removed |page_object| is transferred to the caller. // Call FPDFPageObj_Destroy() on the removed page_object to free it. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFFormObj_RemoveObject(FPDF_PAGEOBJECT form_object, FPDF_PAGEOBJECT page_object); #ifdef __cplusplus } // extern "C" #endif // __cplusplus #endif // PUBLIC_FPDF_EDIT_H_ ================================================ FILE: external/pdfium/windows-x64/include/fpdf_ext.h ================================================ // Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #ifndef PUBLIC_FPDF_EXT_H_ #define PUBLIC_FPDF_EXT_H_ #include // NOLINTNEXTLINE(build/include) #include "fpdfview.h" #ifdef __cplusplus extern "C" { #endif // __cplusplus // Unsupported XFA form. #define FPDF_UNSP_DOC_XFAFORM 1 // Unsupported portable collection. #define FPDF_UNSP_DOC_PORTABLECOLLECTION 2 // Unsupported attachment. #define FPDF_UNSP_DOC_ATTACHMENT 3 // Unsupported security. #define FPDF_UNSP_DOC_SECURITY 4 // Unsupported shared review. #define FPDF_UNSP_DOC_SHAREDREVIEW 5 // Unsupported shared form, acrobat. #define FPDF_UNSP_DOC_SHAREDFORM_ACROBAT 6 // Unsupported shared form, filesystem. #define FPDF_UNSP_DOC_SHAREDFORM_FILESYSTEM 7 // Unsupported shared form, email. #define FPDF_UNSP_DOC_SHAREDFORM_EMAIL 8 // Unsupported 3D annotation. #define FPDF_UNSP_ANNOT_3DANNOT 11 // Unsupported movie annotation. #define FPDF_UNSP_ANNOT_MOVIE 12 // Unsupported sound annotation. #define FPDF_UNSP_ANNOT_SOUND 13 // Unsupported screen media annotation. #define FPDF_UNSP_ANNOT_SCREEN_MEDIA 14 // Unsupported screen rich media annotation. #define FPDF_UNSP_ANNOT_SCREEN_RICHMEDIA 15 // Unsupported attachment annotation. #define FPDF_UNSP_ANNOT_ATTACHMENT 16 // Unsupported signature annotation. #define FPDF_UNSP_ANNOT_SIG 17 // Interface for unsupported feature notifications. typedef struct _UNSUPPORT_INFO { // Version number of the interface. Must be 1. int version; // Unsupported object notification function. // Interface Version: 1 // Implementation Required: Yes // // pThis - pointer to the interface structure. // nType - the type of unsupported object. One of the |FPDF_UNSP_*| entries. void (*FSDK_UnSupport_Handler)(struct _UNSUPPORT_INFO* pThis, int nType); } UNSUPPORT_INFO; // Setup an unsupported object handler. // // unsp_info - Pointer to an UNSUPPORT_INFO structure. // // Returns TRUE on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FSDK_SetUnSpObjProcessHandler(UNSUPPORT_INFO* unsp_info); // Set replacement function for calls to time(). // // This API is intended to be used only for testing, thus may cause PDFium to // behave poorly in production environments. // // func - Function pointer to alternate implementation of time(), or // NULL to restore to actual time() call itself. FPDF_EXPORT void FPDF_CALLCONV FSDK_SetTimeFunction(time_t (*func)()); // Set replacement function for calls to localtime(). // // This API is intended to be used only for testing, thus may cause PDFium to // behave poorly in production environments. // // func - Function pointer to alternate implementation of localtime(), or // NULL to restore to actual localtime() call itself. FPDF_EXPORT void FPDF_CALLCONV FSDK_SetLocaltimeFunction(struct tm* (*func)(const time_t*)); // Unknown page mode. #define PAGEMODE_UNKNOWN -1 // Document outline, and thumbnails hidden. #define PAGEMODE_USENONE 0 // Document outline visible. #define PAGEMODE_USEOUTLINES 1 // Thumbnail images visible. #define PAGEMODE_USETHUMBS 2 // Full-screen mode, no menu bar, window controls, or other decorations visible. #define PAGEMODE_FULLSCREEN 3 // Optional content group panel visible. #define PAGEMODE_USEOC 4 // Attachments panel visible. #define PAGEMODE_USEATTACHMENTS 5 // Get the document's PageMode. // // doc - Handle to document. // // Returns one of the |PAGEMODE_*| flags defined above. // // The page mode defines how the document should be initially displayed. FPDF_EXPORT int FPDF_CALLCONV FPDFDoc_GetPageMode(FPDF_DOCUMENT document); #ifdef __cplusplus } // extern "C" #endif // __cplusplus #endif // PUBLIC_FPDF_EXT_H_ ================================================ FILE: external/pdfium/windows-x64/include/fpdf_flatten.h ================================================ // Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #ifndef PUBLIC_FPDF_FLATTEN_H_ #define PUBLIC_FPDF_FLATTEN_H_ // NOLINTNEXTLINE(build/include) #include "fpdfview.h" // Flatten operation failed. #define FLATTEN_FAIL 0 // Flatten operation succeed. #define FLATTEN_SUCCESS 1 // Nothing to be flattened. #define FLATTEN_NOTHINGTODO 2 // Flatten for normal display. #define FLAT_NORMALDISPLAY 0 // Flatten for print. #define FLAT_PRINT 1 #ifdef __cplusplus extern "C" { #endif // __cplusplus // Flatten annotations and form fields into the page contents. // // page - handle to the page. // nFlag - One of the |FLAT_*| values denoting the page usage. // // Returns one of the |FLATTEN_*| values. // // Currently, all failures return |FLATTEN_FAIL| with no indication of the // cause. FPDF_EXPORT int FPDF_CALLCONV FPDFPage_Flatten(FPDF_PAGE page, int nFlag); #ifdef __cplusplus } // extern "C" #endif // __cplusplus #endif // PUBLIC_FPDF_FLATTEN_H_ ================================================ FILE: external/pdfium/windows-x64/include/fpdf_formfill.h ================================================ // Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #ifndef PUBLIC_FPDF_FORMFILL_H_ #define PUBLIC_FPDF_FORMFILL_H_ // clang-format off // NOLINTNEXTLINE(build/include_directory) #include "fpdfview.h" // These values are return values for a public API, so should not be changed // other than the count when adding new values. #define FORMTYPE_NONE 0 // Document contains no forms #define FORMTYPE_ACRO_FORM 1 // Forms are specified using AcroForm spec #define FORMTYPE_XFA_FULL 2 // Forms are specified using entire XFA spec #define FORMTYPE_XFA_FOREGROUND 3 // Forms are specified using the XFAF subset // of XFA spec #define FORMTYPE_COUNT 4 // The number of form types #define JSPLATFORM_ALERT_BUTTON_OK 0 // OK button #define JSPLATFORM_ALERT_BUTTON_OKCANCEL 1 // OK & Cancel buttons #define JSPLATFORM_ALERT_BUTTON_YESNO 2 // Yes & No buttons #define JSPLATFORM_ALERT_BUTTON_YESNOCANCEL 3 // Yes, No & Cancel buttons #define JSPLATFORM_ALERT_BUTTON_DEFAULT JSPLATFORM_ALERT_BUTTON_OK #define JSPLATFORM_ALERT_ICON_ERROR 0 // Error #define JSPLATFORM_ALERT_ICON_WARNING 1 // Warning #define JSPLATFORM_ALERT_ICON_QUESTION 2 // Question #define JSPLATFORM_ALERT_ICON_STATUS 3 // Status #define JSPLATFORM_ALERT_ICON_ASTERISK 4 // Asterisk #define JSPLATFORM_ALERT_ICON_DEFAULT JSPLATFORM_ALERT_ICON_ERROR #define JSPLATFORM_ALERT_RETURN_OK 1 // OK #define JSPLATFORM_ALERT_RETURN_CANCEL 2 // Cancel #define JSPLATFORM_ALERT_RETURN_NO 3 // No #define JSPLATFORM_ALERT_RETURN_YES 4 // Yes #define JSPLATFORM_BEEP_ERROR 0 // Error #define JSPLATFORM_BEEP_WARNING 1 // Warning #define JSPLATFORM_BEEP_QUESTION 2 // Question #define JSPLATFORM_BEEP_STATUS 3 // Status #define JSPLATFORM_BEEP_DEFAULT 4 // Default // Exported Functions #ifdef __cplusplus extern "C" { #endif typedef struct _IPDF_JsPlatform { // Version number of the interface. Currently must be 2. int version; // Version 1. // Method: app_alert // Pop up a dialog to show warning or hint. // Interface Version: // 1 // Implementation Required: // yes // Parameters: // pThis - Pointer to the interface structure itself. // Msg - A string containing the message to be displayed. // Title - The title of the dialog. // Type - The type of button group, one of the // JSPLATFORM_ALERT_BUTTON_* values above. // nIcon - The type of the icon, one of the // JSPLATFORM_ALERT_ICON_* above. // Return Value: // Option selected by user in dialogue, one of the // JSPLATFORM_ALERT_RETURN_* values above. int (*app_alert)(struct _IPDF_JsPlatform* pThis, FPDF_WIDESTRING Msg, FPDF_WIDESTRING Title, int Type, int Icon); // Method: app_beep // Causes the system to play a sound. // Interface Version: // 1 // Implementation Required: // yes // Parameters: // pThis - Pointer to the interface structure itself // nType - The sound type, see JSPLATFORM_BEEP_TYPE_* // above. // Return Value: // None void (*app_beep)(struct _IPDF_JsPlatform* pThis, int nType); // Method: app_response // Displays a dialog box containing a question and an entry field for // the user to reply to the question. // Interface Version: // 1 // Implementation Required: // yes // Parameters: // pThis - Pointer to the interface structure itself // Question - The question to be posed to the user. // Title - The title of the dialog box. // Default - A default value for the answer to the question. If // not specified, no default value is presented. // cLabel - A short string to appear in front of and on the // same line as the edit text field. // bPassword - If true, indicates that the user's response should // be shown as asterisks (*) or bullets (?) to mask // the response, which might be sensitive information. // response - A string buffer allocated by PDFium, to receive the // user's response. // length - The length of the buffer in bytes. Currently, it is // always 2048. // Return Value: // Number of bytes the complete user input would actually require, not // including trailing zeros, regardless of the value of the length // parameter or the presence of the response buffer. // Comments: // No matter on what platform, the response buffer should be always // written using UTF-16LE encoding. If a response buffer is // present and the size of the user input exceeds the capacity of the // buffer as specified by the length parameter, only the // first "length" bytes of the user input are to be written to the // buffer. int (*app_response)(struct _IPDF_JsPlatform* pThis, FPDF_WIDESTRING Question, FPDF_WIDESTRING Title, FPDF_WIDESTRING Default, FPDF_WIDESTRING cLabel, FPDF_BOOL bPassword, void* response, int length); // Method: Doc_getFilePath // Get the file path of the current document. // Interface Version: // 1 // Implementation Required: // yes // Parameters: // pThis - Pointer to the interface structure itself // filePath - The string buffer to receive the file path. Can // be NULL. // length - The length of the buffer, number of bytes. Can // be 0. // Return Value: // Number of bytes the filePath consumes, including trailing zeros. // Comments: // The filePath should always be provided in the local encoding. // The return value always indicated number of bytes required for // the buffer, even when there is no buffer specified, or the buffer // size is less than required. In this case, the buffer will not // be modified. int (*Doc_getFilePath)(struct _IPDF_JsPlatform* pThis, void* filePath, int length); // Method: Doc_mail // Mails the data buffer as an attachment to all recipients, with or // without user interaction. // Interface Version: // 1 // Implementation Required: // yes // Parameters: // pThis - Pointer to the interface structure itself // mailData - Pointer to the data buffer to be sent. Can be NULL. // length - The size,in bytes, of the buffer pointed by // mailData parameter. Can be 0. // bUI - If true, the rest of the parameters are used in a // compose-new-message window that is displayed to the // user. If false, the cTo parameter is required and // all others are optional. // To - A semicolon-delimited list of recipients for the // message. // Subject - The subject of the message. The length limit is // 64 KB. // CC - A semicolon-delimited list of CC recipients for // the message. // BCC - A semicolon-delimited list of BCC recipients for // the message. // Msg - The content of the message. The length limit is // 64 KB. // Return Value: // None. // Comments: // If the parameter mailData is NULL or length is 0, the current // document will be mailed as an attachment to all recipients. void (*Doc_mail)(struct _IPDF_JsPlatform* pThis, void* mailData, int length, FPDF_BOOL bUI, FPDF_WIDESTRING To, FPDF_WIDESTRING Subject, FPDF_WIDESTRING CC, FPDF_WIDESTRING BCC, FPDF_WIDESTRING Msg); // Method: Doc_print // Prints all or a specific number of pages of the document. // Interface Version: // 1 // Implementation Required: // yes // Parameters: // pThis - Pointer to the interface structure itself. // bUI - If true, will cause a UI to be presented to the // user to obtain printing information and confirm // the action. // nStart - A 0-based index that defines the start of an // inclusive range of pages. // nEnd - A 0-based index that defines the end of an // inclusive page range. // bSilent - If true, suppresses the cancel dialog box while // the document is printing. The default is false. // bShrinkToFit - If true, the page is shrunk (if necessary) to // fit within the imageable area of the printed page. // bPrintAsImage - If true, print pages as an image. // bReverse - If true, print from nEnd to nStart. // bAnnotations - If true (the default), annotations are // printed. // Return Value: // None. void (*Doc_print)(struct _IPDF_JsPlatform* pThis, FPDF_BOOL bUI, int nStart, int nEnd, FPDF_BOOL bSilent, FPDF_BOOL bShrinkToFit, FPDF_BOOL bPrintAsImage, FPDF_BOOL bReverse, FPDF_BOOL bAnnotations); // Method: Doc_submitForm // Send the form data to a specified URL. // Interface Version: // 1 // Implementation Required: // yes // Parameters: // pThis - Pointer to the interface structure itself // formData - Pointer to the data buffer to be sent. // length - The size,in bytes, of the buffer pointed by // formData parameter. // URL - The URL to send to. // Return Value: // None. void (*Doc_submitForm)(struct _IPDF_JsPlatform* pThis, void* formData, int length, FPDF_WIDESTRING URL); // Method: Doc_gotoPage // Jump to a specified page. // Interface Version: // 1 // Implementation Required: // yes // Parameters: // pThis - Pointer to the interface structure itself // nPageNum - The specified page number, zero for the first page. // Return Value: // None. void (*Doc_gotoPage)(struct _IPDF_JsPlatform* pThis, int nPageNum); // Method: Field_browse // Show a file selection dialog, and return the selected file path. // Interface Version: // 1 // Implementation Required: // yes // Parameters: // pThis - Pointer to the interface structure itself. // filePath - Pointer to the data buffer to receive the file // path. Can be NULL. // length - The length of the buffer, in bytes. Can be 0. // Return Value: // Number of bytes the filePath consumes, including trailing zeros. // Comments: // The filePath should always be provided in local encoding. int (*Field_browse)(struct _IPDF_JsPlatform* pThis, void* filePath, int length); // Pointer for embedder-specific data. Unused by PDFium, and despite // its name, can be any data the embedder desires, though traditionally // a FPDF_FORMFILLINFO interface. void* m_pFormfillinfo; // Version 2. void* m_isolate; // Unused in v3, retain for compatibility. unsigned int m_v8EmbedderSlot; // Unused in v3, retain for compatibility. // Version 3. // Version 3 moves m_Isolate and m_v8EmbedderSlot to FPDF_LIBRARY_CONFIG. } IPDF_JSPLATFORM; // Flags for Cursor type #define FXCT_ARROW 0 #define FXCT_NESW 1 #define FXCT_NWSE 2 #define FXCT_VBEAM 3 #define FXCT_HBEAM 4 #define FXCT_HAND 5 // Function signature for the callback function passed to the FFI_SetTimer // method. // Parameters: // idEvent - Identifier of the timer. // Return value: // None. typedef void (*TimerCallback)(int idEvent); // Declares of a struct type to the local system time. typedef struct _FPDF_SYSTEMTIME { unsigned short wYear; // years since 1900 unsigned short wMonth; // months since January - [0,11] unsigned short wDayOfWeek; // days since Sunday - [0,6] unsigned short wDay; // day of the month - [1,31] unsigned short wHour; // hours since midnight - [0,23] unsigned short wMinute; // minutes after the hour - [0,59] unsigned short wSecond; // seconds after the minute - [0,59] unsigned short wMilliseconds; // milliseconds after the second - [0,999] } FPDF_SYSTEMTIME; #ifdef PDF_ENABLE_XFA // Pageview event flags #define FXFA_PAGEVIEWEVENT_POSTADDED 1 // After a new pageview is added. #define FXFA_PAGEVIEWEVENT_POSTREMOVED 3 // After a pageview is removed. // Definitions for Right Context Menu Features Of XFA Fields #define FXFA_MENU_COPY 1 #define FXFA_MENU_CUT 2 #define FXFA_MENU_SELECTALL 4 #define FXFA_MENU_UNDO 8 #define FXFA_MENU_REDO 16 #define FXFA_MENU_PASTE 32 // Definitions for File Type. #define FXFA_SAVEAS_XML 1 #define FXFA_SAVEAS_XDP 2 #endif // PDF_ENABLE_XFA typedef struct _FPDF_FORMFILLINFO { // Version number of the interface. // Version 1 contains stable interfaces. Version 2 has additional // experimental interfaces. // When PDFium is built without the XFA module, version can be 1 or 2. // With version 1, only stable interfaces are called. With version 2, // additional experimental interfaces are also called. // When PDFium is built with the XFA module, version must be 2. // All the XFA related interfaces are experimental. If PDFium is built with // the XFA module and version 1 then none of the XFA related interfaces // would be called. When PDFium is built with XFA module then the version // must be 2. int version; // Version 1. // Method: Release // Give the implementation a chance to release any resources after the // interface is no longer used. // Interface Version: // 1 // Implementation Required: // No // Comments: // Called by PDFium during the final cleanup process. // Parameters: // pThis - Pointer to the interface structure itself // Return Value: // None void (*Release)(struct _FPDF_FORMFILLINFO* pThis); // Method: FFI_Invalidate // Invalidate the client area within the specified rectangle. // Interface Version: // 1 // Implementation Required: // yes // Parameters: // pThis - Pointer to the interface structure itself. // page - Handle to the page. Returned by FPDF_LoadPage(). // left - Left position of the client area in PDF page // coordinates. // top - Top position of the client area in PDF page // coordinates. // right - Right position of the client area in PDF page // coordinates. // bottom - Bottom position of the client area in PDF page // coordinates. // Return Value: // None. // Comments: // All positions are measured in PDF "user space". // Implementation should call FPDF_RenderPageBitmap() for repainting // the specified page area. void (*FFI_Invalidate)(struct _FPDF_FORMFILLINFO* pThis, FPDF_PAGE page, double left, double top, double right, double bottom); // Method: FFI_OutputSelectedRect // When the user selects text in form fields with the mouse, this // callback function will be invoked with the selected areas. // Interface Version: // 1 // Implementation Required: // No // Parameters: // pThis - Pointer to the interface structure itself. // page - Handle to the page. Returned by FPDF_LoadPage()/ // left - Left position of the client area in PDF page // coordinates. // top - Top position of the client area in PDF page // coordinates. // right - Right position of the client area in PDF page // coordinates. // bottom - Bottom position of the client area in PDF page // coordinates. // Return Value: // None. // Comments: // This callback function is useful for implementing special text // selection effects. An implementation should first record the // returned rectangles, then draw them one by one during the next // painting period. Lastly, it should remove all the recorded // rectangles when finished painting. void (*FFI_OutputSelectedRect)(struct _FPDF_FORMFILLINFO* pThis, FPDF_PAGE page, double left, double top, double right, double bottom); // Method: FFI_SetCursor // Set the Cursor shape. // Interface Version: // 1 // Implementation Required: // yes // Parameters: // pThis - Pointer to the interface structure itself. // nCursorType - Cursor type, see Flags for Cursor type for details. // Return value: // None. void (*FFI_SetCursor)(struct _FPDF_FORMFILLINFO* pThis, int nCursorType); // Method: FFI_SetTimer // This method installs a system timer. An interval value is specified, // and every time that interval elapses, the system must call into the // callback function with the timer ID as returned by this function. // Interface Version: // 1 // Implementation Required: // yes // Parameters: // pThis - Pointer to the interface structure itself. // uElapse - Specifies the time-out value, in milliseconds. // lpTimerFunc - A pointer to the callback function-TimerCallback. // Return value: // The timer identifier of the new timer if the function is successful. // An application passes this value to the FFI_KillTimer method to kill // the timer. Nonzero if it is successful; otherwise, it is zero. int (*FFI_SetTimer)(struct _FPDF_FORMFILLINFO* pThis, int uElapse, TimerCallback lpTimerFunc); // Method: FFI_KillTimer // This method uninstalls a system timer, as set by an earlier call to // FFI_SetTimer. // Interface Version: // 1 // Implementation Required: // yes // Parameters: // pThis - Pointer to the interface structure itself. // nTimerID - The timer ID returned by FFI_SetTimer function. // Return value: // None. void (*FFI_KillTimer)(struct _FPDF_FORMFILLINFO* pThis, int nTimerID); // Method: FFI_GetLocalTime // This method receives the current local time on the system. // Interface Version: // 1 // Implementation Required: // yes // Parameters: // pThis - Pointer to the interface structure itself. // Return value: // The local time. See FPDF_SYSTEMTIME above for details. // Note: Unused. FPDF_SYSTEMTIME (*FFI_GetLocalTime)(struct _FPDF_FORMFILLINFO* pThis); // Method: FFI_OnChange // This method will be invoked to notify the implementation when the // value of any FormField on the document had been changed. // Interface Version: // 1 // Implementation Required: // no // Parameters: // pThis - Pointer to the interface structure itself. // Return value: // None. void (*FFI_OnChange)(struct _FPDF_FORMFILLINFO* pThis); // Method: FFI_GetPage // This method receives the page handle associated with a specified // page index. // Interface Version: // 1 // Implementation Required: // yes // Parameters: // pThis - Pointer to the interface structure itself. // document - Handle to document. Returned by FPDF_LoadDocument(). // nPageIndex - Index number of the page. 0 for the first page. // Return value: // Handle to the page, as previously returned to the implementation by // FPDF_LoadPage(). // Comments: // The implementation is expected to keep track of the page handles it // receives from PDFium, and their mappings to page numbers. In some // cases, the document-level JavaScript action may refer to a page // which hadn't been loaded yet. To successfully run the Javascript // action, the implementation needs to load the page. FPDF_PAGE (*FFI_GetPage)(struct _FPDF_FORMFILLINFO* pThis, FPDF_DOCUMENT document, int nPageIndex); // Method: FFI_GetCurrentPage // This method receives the handle to the current page. // Interface Version: // 1 // Implementation Required: // Yes when V8 support is present, otherwise unused. // Parameters: // pThis - Pointer to the interface structure itself. // document - Handle to document. Returned by FPDF_LoadDocument(). // Return value: // Handle to the page. Returned by FPDF_LoadPage(). // Comments: // PDFium doesn't keep keep track of the "current page" (e.g. the one // that is most visible on screen), so it must ask the embedder for // this information. FPDF_PAGE (*FFI_GetCurrentPage)(struct _FPDF_FORMFILLINFO* pThis, FPDF_DOCUMENT document); // Method: FFI_GetRotation // This method receives currently rotation of the page view. // Interface Version: // 1 // Implementation Required: // yes // Parameters: // pThis - Pointer to the interface structure itself. // page - Handle to page, as returned by FPDF_LoadPage(). // Return value: // A number to indicate the page rotation in 90 degree increments // in a clockwise direction: // 0 - 0 degrees // 1 - 90 degrees // 2 - 180 degrees // 3 - 270 degrees // Note: Unused. int (*FFI_GetRotation)(struct _FPDF_FORMFILLINFO* pThis, FPDF_PAGE page); // Method: FFI_ExecuteNamedAction // This method will execute a named action. // Interface Version: // 1 // Implementation Required: // yes // Parameters: // pThis - Pointer to the interface structure itself. // namedAction - A byte string which indicates the named action, // terminated by 0. // Return value: // None. // Comments: // See ISO 32000-1:2008, section 12.6.4.11 for descriptions of the // standard named actions, but note that a document may supply any // name of its choosing. void (*FFI_ExecuteNamedAction)(struct _FPDF_FORMFILLINFO* pThis, FPDF_BYTESTRING namedAction); // Method: FFI_SetTextFieldFocus // Called when a text field is getting or losing focus. // Interface Version: // 1 // Implementation Required: // no // Parameters: // pThis - Pointer to the interface structure itself. // value - The string value of the form field, in UTF-16LE // format. // valueLen - The length of the string value. This is the // number of characters, not bytes. // is_focus - True if the form field is getting focus, false // if the form field is losing focus. // Return value: // None. // Comments: // Only supports text fields and combobox fields. void (*FFI_SetTextFieldFocus)(struct _FPDF_FORMFILLINFO* pThis, FPDF_WIDESTRING value, FPDF_DWORD valueLen, FPDF_BOOL is_focus); // Method: FFI_DoURIAction // Ask the implementation to navigate to a uniform resource identifier. // Interface Version: // 1 // Implementation Required: // No // Parameters: // pThis - Pointer to the interface structure itself. // bsURI - A byte string which indicates the uniform // resource identifier, terminated by 0. // Return value: // None. // Comments: // If the embedder is version 2 or higher and have implementation for // FFI_DoURIActionWithKeyboardModifier, then // FFI_DoURIActionWithKeyboardModifier takes precedence over // FFI_DoURIAction. // See the URI actions description of <> // for more details. void (*FFI_DoURIAction)(struct _FPDF_FORMFILLINFO* pThis, FPDF_BYTESTRING bsURI); // Method: FFI_DoGoToAction // This action changes the view to a specified destination. // Interface Version: // 1 // Implementation Required: // No // Parameters: // pThis - Pointer to the interface structure itself. // nPageIndex - The index of the PDF page. // zoomMode - The zoom mode for viewing page. See below. // fPosArray - The float array which carries the position info. // sizeofArray - The size of float array. // PDFZoom values: // - XYZ = 1 // - FITPAGE = 2 // - FITHORZ = 3 // - FITVERT = 4 // - FITRECT = 5 // - FITBBOX = 6 // - FITBHORZ = 7 // - FITBVERT = 8 // Return value: // None. // Comments: // See the Destinations description of <> // in 8.2.1 for more details. void (*FFI_DoGoToAction)(struct _FPDF_FORMFILLINFO* pThis, int nPageIndex, int zoomMode, float* fPosArray, int sizeofArray); // Pointer to IPDF_JSPLATFORM interface. // Unused if PDFium is built without V8 support. Otherwise, if NULL, then // JavaScript will be prevented from executing while rendering the document. IPDF_JSPLATFORM* m_pJsPlatform; // Version 2 - Experimental. // Whether the XFA module is disabled when built with the XFA module. // Interface Version: // Ignored if |version| < 2. FPDF_BOOL xfa_disabled; // Method: FFI_DisplayCaret // This method will show the caret at specified position. // Interface Version: // Ignored if |version| < 2. // Implementation Required: // Required for XFA, otherwise set to NULL. // Parameters: // pThis - Pointer to the interface structure itself. // page - Handle to page. Returned by FPDF_LoadPage(). // left - Left position of the client area in PDF page // coordinates. // top - Top position of the client area in PDF page // coordinates. // right - Right position of the client area in PDF page // coordinates. // bottom - Bottom position of the client area in PDF page // coordinates. // Return value: // None. void (*FFI_DisplayCaret)(struct _FPDF_FORMFILLINFO* pThis, FPDF_PAGE page, FPDF_BOOL bVisible, double left, double top, double right, double bottom); // Method: FFI_GetCurrentPageIndex // This method will get the current page index. // Interface Version: // Ignored if |version| < 2. // Implementation Required: // Required for XFA, otherwise set to NULL. // Parameters: // pThis - Pointer to the interface structure itself. // document - Handle to document from FPDF_LoadDocument(). // Return value: // The index of current page. int (*FFI_GetCurrentPageIndex)(struct _FPDF_FORMFILLINFO* pThis, FPDF_DOCUMENT document); // Method: FFI_SetCurrentPage // This method will set the current page. // Interface Version: // Ignored if |version| < 2. // Implementation Required: // Required for XFA, otherwise set to NULL. // Parameters: // pThis - Pointer to the interface structure itself. // document - Handle to document from FPDF_LoadDocument(). // iCurPage - The index of the PDF page. // Return value: // None. void (*FFI_SetCurrentPage)(struct _FPDF_FORMFILLINFO* pThis, FPDF_DOCUMENT document, int iCurPage); // Method: FFI_GotoURL // This method will navigate to the specified URL. // Interface Version: // Ignored if |version| < 2. // Implementation Required: // Required for XFA, otherwise set to NULL. // Parameters: // pThis - Pointer to the interface structure itself. // document - Handle to document from FPDF_LoadDocument(). // wsURL - The string value of the URL, in UTF-16LE format. // Return value: // None. void (*FFI_GotoURL)(struct _FPDF_FORMFILLINFO* pThis, FPDF_DOCUMENT document, FPDF_WIDESTRING wsURL); // Method: FFI_GetPageViewRect // This method will get the current page view rectangle. // Interface Version: // Ignored if |version| < 2. // Implementation Required: // Required for XFA, otherwise set to NULL. // Parameters: // pThis - Pointer to the interface structure itself. // page - Handle to page. Returned by FPDF_LoadPage(). // left - The pointer to receive left position of the page // view area in PDF page coordinates. // top - The pointer to receive top position of the page // view area in PDF page coordinates. // right - The pointer to receive right position of the // page view area in PDF page coordinates. // bottom - The pointer to receive bottom position of the // page view area in PDF page coordinates. // Return value: // None. void (*FFI_GetPageViewRect)(struct _FPDF_FORMFILLINFO* pThis, FPDF_PAGE page, double* left, double* top, double* right, double* bottom); // Method: FFI_PageEvent // This method fires when pages have been added to or deleted from // the XFA document. // Interface Version: // Ignored if |version| < 2. // Implementation Required: // Required for XFA, otherwise set to NULL. // Parameters: // pThis - Pointer to the interface structure itself. // page_count - The number of pages to be added or deleted. // event_type - See FXFA_PAGEVIEWEVENT_* above. // Return value: // None. // Comments: // The pages to be added or deleted always start from the last page // of document. This means that if parameter page_count is 2 and // event type is FXFA_PAGEVIEWEVENT_POSTADDED, 2 new pages have been // appended to the tail of document; If page_count is 2 and // event type is FXFA_PAGEVIEWEVENT_POSTREMOVED, the last 2 pages // have been deleted. void (*FFI_PageEvent)(struct _FPDF_FORMFILLINFO* pThis, int page_count, FPDF_DWORD event_type); // Method: FFI_PopupMenu // This method will track the right context menu for XFA fields. // Interface Version: // Ignored if |version| < 2. // Implementation Required: // Required for XFA, otherwise set to NULL. // Parameters: // pThis - Pointer to the interface structure itself. // page - Handle to page. Returned by FPDF_LoadPage(). // hWidget - Always null, exists for compatibility. // menuFlag - The menu flags. Please refer to macro definition // of FXFA_MENU_XXX and this can be one or a // combination of these macros. // x - X position of the client area in PDF page // coordinates. // y - Y position of the client area in PDF page // coordinates. // Return value: // TRUE indicates success; otherwise false. FPDF_BOOL (*FFI_PopupMenu)(struct _FPDF_FORMFILLINFO* pThis, FPDF_PAGE page, FPDF_WIDGET hWidget, int menuFlag, float x, float y); // Method: FFI_OpenFile // This method will open the specified file with the specified mode. // Interface Version: // Ignored if |version| < 2. // Implementation Required: // Required for XFA, otherwise set to NULL. // Parameters: // pThis - Pointer to the interface structure itself. // fileFlag - The file flag. Please refer to macro definition // of FXFA_SAVEAS_XXX and use one of these macros. // wsURL - The string value of the file URL, in UTF-16LE // format. // mode - The mode for open file, e.g. "rb" or "wb". // Return value: // The handle to FPDF_FILEHANDLER. FPDF_FILEHANDLER* (*FFI_OpenFile)(struct _FPDF_FORMFILLINFO* pThis, int fileFlag, FPDF_WIDESTRING wsURL, const char* mode); // Method: FFI_EmailTo // This method will email the specified file stream to the specified // contact. // Interface Version: // Ignored if |version| < 2. // Implementation Required: // Required for XFA, otherwise set to NULL. // Parameters: // pThis - Pointer to the interface structure itself. // pFileHandler - Handle to the FPDF_FILEHANDLER. // pTo - A semicolon-delimited list of recipients for the // message,in UTF-16LE format. // pSubject - The subject of the message,in UTF-16LE format. // pCC - A semicolon-delimited list of CC recipients for // the message,in UTF-16LE format. // pBcc - A semicolon-delimited list of BCC recipients for // the message,in UTF-16LE format. // pMsg - Pointer to the data buffer to be sent.Can be // NULL,in UTF-16LE format. // Return value: // None. void (*FFI_EmailTo)(struct _FPDF_FORMFILLINFO* pThis, FPDF_FILEHANDLER* fileHandler, FPDF_WIDESTRING pTo, FPDF_WIDESTRING pSubject, FPDF_WIDESTRING pCC, FPDF_WIDESTRING pBcc, FPDF_WIDESTRING pMsg); // Method: FFI_UploadTo // This method will upload the specified file stream to the // specified URL. // Interface Version: // Ignored if |version| < 2. // Implementation Required: // Required for XFA, otherwise set to NULL. // Parameters: // pThis - Pointer to the interface structure itself. // pFileHandler - Handle to the FPDF_FILEHANDLER. // fileFlag - The file flag. Please refer to macro definition // of FXFA_SAVEAS_XXX and use one of these macros. // uploadTo - Pointer to the URL path, in UTF-16LE format. // Return value: // None. void (*FFI_UploadTo)(struct _FPDF_FORMFILLINFO* pThis, FPDF_FILEHANDLER* fileHandler, int fileFlag, FPDF_WIDESTRING uploadTo); // Method: FFI_GetPlatform // This method will get the current platform. // Interface Version: // Ignored if |version| < 2. // Implementation Required: // Required for XFA, otherwise set to NULL. // Parameters: // pThis - Pointer to the interface structure itself. // platform - Pointer to the data buffer to receive the // platform,in UTF-16LE format. Can be NULL. // length - The length of the buffer in bytes. Can be // 0 to query the required size. // Return value: // The length of the buffer, number of bytes. int (*FFI_GetPlatform)(struct _FPDF_FORMFILLINFO* pThis, void* platform, int length); // Method: FFI_GetLanguage // This method will get the current language. // Interface Version: // Ignored if |version| < 2. // Implementation Required: // Required for XFA, otherwise set to NULL. // Parameters: // pThis - Pointer to the interface structure itself. // language - Pointer to the data buffer to receive the // current language. Can be NULL. // length - The length of the buffer in bytes. Can be // 0 to query the required size. // Return value: // The length of the buffer, number of bytes. int (*FFI_GetLanguage)(struct _FPDF_FORMFILLINFO* pThis, void* language, int length); // Method: FFI_DownloadFromURL // This method will download the specified file from the URL. // Interface Version: // Ignored if |version| < 2. // Implementation Required: // Required for XFA, otherwise set to NULL. // Parameters: // pThis - Pointer to the interface structure itself. // URL - The string value of the file URL, in UTF-16LE // format. // Return value: // The handle to FPDF_FILEHANDLER. FPDF_FILEHANDLER* (*FFI_DownloadFromURL)(struct _FPDF_FORMFILLINFO* pThis, FPDF_WIDESTRING URL); // Method: FFI_PostRequestURL // This method will post the request to the server URL. // Interface Version: // Ignored if |version| < 2. // Implementation Required: // Required for XFA, otherwise set to NULL. // Parameters: // pThis - Pointer to the interface structure itself. // wsURL - The string value of the server URL, in UTF-16LE // format. // wsData - The post data,in UTF-16LE format. // wsContentType - The content type of the request data, in // UTF-16LE format. // wsEncode - The encode type, in UTF-16LE format. // wsHeader - The request header,in UTF-16LE format. // response - Pointer to the FPDF_BSTR to receive the response // data from the server, in UTF-16LE format. // Return value: // TRUE indicates success, otherwise FALSE. FPDF_BOOL (*FFI_PostRequestURL)(struct _FPDF_FORMFILLINFO* pThis, FPDF_WIDESTRING wsURL, FPDF_WIDESTRING wsData, FPDF_WIDESTRING wsContentType, FPDF_WIDESTRING wsEncode, FPDF_WIDESTRING wsHeader, FPDF_BSTR* response); // Method: FFI_PutRequestURL // This method will put the request to the server URL. // Interface Version: // Ignored if |version| < 2. // Implementation Required: // Required for XFA, otherwise set to NULL. // Parameters: // pThis - Pointer to the interface structure itself. // wsURL - The string value of the server URL, in UTF-16LE // format. // wsData - The put data, in UTF-16LE format. // wsEncode - The encode type, in UTR-16LE format. // Return value: // TRUE indicates success, otherwise FALSE. FPDF_BOOL (*FFI_PutRequestURL)(struct _FPDF_FORMFILLINFO* pThis, FPDF_WIDESTRING wsURL, FPDF_WIDESTRING wsData, FPDF_WIDESTRING wsEncode); // Method: FFI_OnFocusChange // Called when the focused annotation is updated. // Interface Version: // Ignored if |version| < 2. // Implementation Required: // No // Parameters: // param - Pointer to the interface structure itself. // annot - The focused annotation. // page_index - Index number of the page which contains the // focused annotation. 0 for the first page. // Return value: // None. // Comments: // This callback function is useful for implementing any view based // action such as scrolling the annotation rect into view. The // embedder should not copy and store the annot as its scope is // limited to this call only. void (*FFI_OnFocusChange)(struct _FPDF_FORMFILLINFO* param, FPDF_ANNOTATION annot, int page_index); // Method: FFI_DoURIActionWithKeyboardModifier // Ask the implementation to navigate to a uniform resource identifier // with the specified modifiers. // Interface Version: // Ignored if |version| < 2. // Implementation Required: // No // Parameters: // param - Pointer to the interface structure itself. // uri - A byte string which indicates the uniform // resource identifier, terminated by 0. // modifiers - Keyboard modifier that indicates which of // the virtual keys are down, if any. // Return value: // None. // Comments: // If the embedder who is version 2 and does not implement this API, // then a call will be redirected to FFI_DoURIAction. // See the URI actions description of <> // for more details. void(*FFI_DoURIActionWithKeyboardModifier)(struct _FPDF_FORMFILLINFO* param, FPDF_BYTESTRING uri, int modifiers); } FPDF_FORMFILLINFO; // Function: FPDFDOC_InitFormFillEnvironment // Initialize form fill environment. // Parameters: // document - Handle to document from FPDF_LoadDocument(). // formInfo - Pointer to a FPDF_FORMFILLINFO structure. // Return Value: // Handle to the form fill module, or NULL on failure. // Comments: // This function should be called before any form fill operation. // The FPDF_FORMFILLINFO passed in via |formInfo| must remain valid until // the returned FPDF_FORMHANDLE is closed. FPDF_EXPORT FPDF_FORMHANDLE FPDF_CALLCONV FPDFDOC_InitFormFillEnvironment(FPDF_DOCUMENT document, FPDF_FORMFILLINFO* formInfo); // Function: FPDFDOC_ExitFormFillEnvironment // Take ownership of |hHandle| and exit form fill environment. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // Return Value: // None. // Comments: // This function is a no-op when |hHandle| is null. FPDF_EXPORT void FPDF_CALLCONV FPDFDOC_ExitFormFillEnvironment(FPDF_FORMHANDLE hHandle); // Function: FORM_OnAfterLoadPage // This method is required for implementing all the form related // functions. Should be invoked after user successfully loaded a // PDF page, and FPDFDOC_InitFormFillEnvironment() has been invoked. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // Return Value: // None. FPDF_EXPORT void FPDF_CALLCONV FORM_OnAfterLoadPage(FPDF_PAGE page, FPDF_FORMHANDLE hHandle); // Function: FORM_OnBeforeClosePage // This method is required for implementing all the form related // functions. Should be invoked before user closes the PDF page. // Parameters: // page - Handle to the page, as returned by FPDF_LoadPage(). // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // Return Value: // None. FPDF_EXPORT void FPDF_CALLCONV FORM_OnBeforeClosePage(FPDF_PAGE page, FPDF_FORMHANDLE hHandle); // Function: FORM_DoDocumentJSAction // This method is required for performing document-level JavaScript // actions. It should be invoked after the PDF document has been loaded. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // Return Value: // None. // Comments: // If there is document-level JavaScript action embedded in the // document, this method will execute the JavaScript action. Otherwise, // the method will do nothing. FPDF_EXPORT void FPDF_CALLCONV FORM_DoDocumentJSAction(FPDF_FORMHANDLE hHandle); // Function: FORM_DoDocumentOpenAction // This method is required for performing open-action when the document // is opened. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // Return Value: // None. // Comments: // This method will do nothing if there are no open-actions embedded // in the document. FPDF_EXPORT void FPDF_CALLCONV FORM_DoDocumentOpenAction(FPDF_FORMHANDLE hHandle); // Additional actions type of document: // WC, before closing document, JavaScript action. // WS, before saving document, JavaScript action. // DS, after saving document, JavaScript action. // WP, before printing document, JavaScript action. // DP, after printing document, JavaScript action. #define FPDFDOC_AACTION_WC 0x10 #define FPDFDOC_AACTION_WS 0x11 #define FPDFDOC_AACTION_DS 0x12 #define FPDFDOC_AACTION_WP 0x13 #define FPDFDOC_AACTION_DP 0x14 // Function: FORM_DoDocumentAAction // This method is required for performing the document's // additional-action. // Parameters: // hHandle - Handle to the form fill module. Returned by // FPDFDOC_InitFormFillEnvironment. // aaType - The type of the additional-actions which defined // above. // Return Value: // None. // Comments: // This method will do nothing if there is no document // additional-action corresponding to the specified |aaType|. FPDF_EXPORT void FPDF_CALLCONV FORM_DoDocumentAAction(FPDF_FORMHANDLE hHandle, int aaType); // Additional-action types of page object: // OPEN (/O) -- An action to be performed when the page is opened // CLOSE (/C) -- An action to be performed when the page is closed #define FPDFPAGE_AACTION_OPEN 0 #define FPDFPAGE_AACTION_CLOSE 1 // Function: FORM_DoPageAAction // This method is required for performing the page object's // additional-action when opened or closed. // Parameters: // page - Handle to the page, as returned by FPDF_LoadPage(). // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // aaType - The type of the page object's additional-actions // which defined above. // Return Value: // None. // Comments: // This method will do nothing if no additional-action corresponding // to the specified |aaType| exists. FPDF_EXPORT void FPDF_CALLCONV FORM_DoPageAAction(FPDF_PAGE page, FPDF_FORMHANDLE hHandle, int aaType); // Function: FORM_OnMouseMove // Call this member function when the mouse cursor moves. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page, as returned by FPDF_LoadPage(). // modifier - Indicates whether various virtual keys are down. // page_x - Specifies the x-coordinate of the cursor in PDF user // space. // page_y - Specifies the y-coordinate of the cursor in PDF user // space. // Return Value: // True indicates success; otherwise false. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnMouseMove(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, int modifier, double page_x, double page_y); // Experimental API // Function: FORM_OnMouseWheel // Call this member function when the user scrolls the mouse wheel. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page, as returned by FPDF_LoadPage(). // modifier - Indicates whether various virtual keys are down. // page_coord - Specifies the coordinates of the cursor in PDF user // space. // delta_x - Specifies the amount of wheel movement on the x-axis, // in units of platform-agnostic wheel deltas. Negative // values mean left. // delta_y - Specifies the amount of wheel movement on the y-axis, // in units of platform-agnostic wheel deltas. Negative // values mean down. // Return Value: // True indicates success; otherwise false. // Comments: // For |delta_x| and |delta_y|, the caller must normalize // platform-specific wheel deltas. e.g. On Windows, a delta value of 240 // for a WM_MOUSEWHEEL event normalizes to 2, since Windows defines // WHEEL_DELTA as 120. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnMouseWheel( FPDF_FORMHANDLE hHandle, FPDF_PAGE page, int modifier, const FS_POINTF* page_coord, int delta_x, int delta_y); // Function: FORM_OnFocus // This function focuses the form annotation at a given point. If the // annotation at the point already has focus, nothing happens. If there // is no annotation at the point, removes form focus. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page, as returned by FPDF_LoadPage(). // modifier - Indicates whether various virtual keys are down. // page_x - Specifies the x-coordinate of the cursor in PDF user // space. // page_y - Specifies the y-coordinate of the cursor in PDF user // space. // Return Value: // True if there is an annotation at the given point and it has focus. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnFocus(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, int modifier, double page_x, double page_y); // Function: FORM_OnLButtonDown // Call this member function when the user presses the left // mouse button. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page, as returned by FPDF_LoadPage(). // modifier - Indicates whether various virtual keys are down. // page_x - Specifies the x-coordinate of the cursor in PDF user // space. // page_y - Specifies the y-coordinate of the cursor in PDF user // space. // Return Value: // True indicates success; otherwise false. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnLButtonDown(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, int modifier, double page_x, double page_y); // Function: FORM_OnRButtonDown // Same as above, execpt for the right mouse button. // Comments: // At the present time, has no effect except in XFA builds, but is // included for the sake of symmetry. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnRButtonDown(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, int modifier, double page_x, double page_y); // Function: FORM_OnLButtonUp // Call this member function when the user releases the left // mouse button. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page, as returned by FPDF_LoadPage(). // modifier - Indicates whether various virtual keys are down. // page_x - Specifies the x-coordinate of the cursor in device. // page_y - Specifies the y-coordinate of the cursor in device. // Return Value: // True indicates success; otherwise false. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnLButtonUp(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, int modifier, double page_x, double page_y); // Function: FORM_OnRButtonUp // Same as above, execpt for the right mouse button. // Comments: // At the present time, has no effect except in XFA builds, but is // included for the sake of symmetry. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnRButtonUp(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, int modifier, double page_x, double page_y); // Function: FORM_OnLButtonDoubleClick // Call this member function when the user double clicks the // left mouse button. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page, as returned by FPDF_LoadPage(). // modifier - Indicates whether various virtual keys are down. // page_x - Specifies the x-coordinate of the cursor in PDF user // space. // page_y - Specifies the y-coordinate of the cursor in PDF user // space. // Return Value: // True indicates success; otherwise false. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnLButtonDoubleClick(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, int modifier, double page_x, double page_y); // Function: FORM_OnKeyDown // Call this member function when a nonsystem key is pressed. // Parameters: // hHandle - Handle to the form fill module, aseturned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page, as returned by FPDF_LoadPage(). // nKeyCode - The virtual-key code of the given key (see // fpdf_fwlevent.h for virtual key codes). // modifier - Mask of key flags (see fpdf_fwlevent.h for key // flag values). // Return Value: // True indicates success; otherwise false. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnKeyDown(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, int nKeyCode, int modifier); // Function: FORM_OnKeyUp // Call this member function when a nonsystem key is released. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page, as returned by FPDF_LoadPage(). // nKeyCode - The virtual-key code of the given key (see // fpdf_fwlevent.h for virtual key codes). // modifier - Mask of key flags (see fpdf_fwlevent.h for key // flag values). // Return Value: // True indicates success; otherwise false. // Comments: // Currently unimplemented and always returns false. PDFium reserves this // API and may implement it in the future on an as-needed basis. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnKeyUp(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, int nKeyCode, int modifier); // Function: FORM_OnChar // Call this member function when a keystroke translates to a // nonsystem character. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page, as returned by FPDF_LoadPage(). // nChar - The character code value itself. // modifier - Mask of key flags (see fpdf_fwlevent.h for key // flag values). // Return Value: // True indicates success; otherwise false. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnChar(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, int nChar, int modifier); // Experimental API // Function: FORM_GetFocusedText // Call this function to obtain the text within the current focused // field, if any. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page, as returned by FPDF_LoadPage(). // buffer - Buffer for holding the form text, encoded in // UTF-16LE. If NULL, |buffer| is not modified. // buflen - Length of |buffer| in bytes. If |buflen| is less // than the length of the form text string, |buffer| is // not modified. // Return Value: // Length in bytes for the text in the focused field. FPDF_EXPORT unsigned long FPDF_CALLCONV FORM_GetFocusedText(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, void* buffer, unsigned long buflen); // Function: FORM_GetSelectedText // Call this function to obtain selected text within a form text // field or form combobox text field. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page, as returned by FPDF_LoadPage(). // buffer - Buffer for holding the selected text, encoded in // UTF-16LE. If NULL, |buffer| is not modified. // buflen - Length of |buffer| in bytes. If |buflen| is less // than the length of the selected text string, // |buffer| is not modified. // Return Value: // Length in bytes of selected text in form text field or form combobox // text field. FPDF_EXPORT unsigned long FPDF_CALLCONV FORM_GetSelectedText(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, void* buffer, unsigned long buflen); // Experimental API // Function: FORM_ReplaceAndKeepSelection // Call this function to replace the selected text in a form // text field or user-editable form combobox text field with another // text string (which can be empty or non-empty). If there is no // selected text, this function will append the replacement text after // the current caret position. After the insertion, the inserted text // will be selected. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page, as Returned by FPDF_LoadPage(). // wsText - The text to be inserted, in UTF-16LE format. // Return Value: // None. FPDF_EXPORT void FPDF_CALLCONV FORM_ReplaceAndKeepSelection(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, FPDF_WIDESTRING wsText); // Function: FORM_ReplaceSelection // Call this function to replace the selected text in a form // text field or user-editable form combobox text field with another // text string (which can be empty or non-empty). If there is no // selected text, this function will append the replacement text after // the current caret position. After the insertion, the selection range // will be set to empty. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page, as Returned by FPDF_LoadPage(). // wsText - The text to be inserted, in UTF-16LE format. // Return Value: // None. FPDF_EXPORT void FPDF_CALLCONV FORM_ReplaceSelection(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, FPDF_WIDESTRING wsText); // Experimental API // Function: FORM_SelectAllText // Call this function to select all the text within the currently focused // form text field or form combobox text field. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page, as returned by FPDF_LoadPage(). // Return Value: // Whether the operation succeeded or not. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_SelectAllText(FPDF_FORMHANDLE hHandle, FPDF_PAGE page); // Function: FORM_CanUndo // Find out if it is possible for the current focused widget in a given // form to perform an undo operation. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page, as returned by FPDF_LoadPage(). // Return Value: // True if it is possible to undo. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_CanUndo(FPDF_FORMHANDLE hHandle, FPDF_PAGE page); // Function: FORM_CanRedo // Find out if it is possible for the current focused widget in a given // form to perform a redo operation. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page, as returned by FPDF_LoadPage(). // Return Value: // True if it is possible to redo. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_CanRedo(FPDF_FORMHANDLE hHandle, FPDF_PAGE page); // Function: FORM_Undo // Make the current focused widget perform an undo operation. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page, as returned by FPDF_LoadPage(). // Return Value: // True if the undo operation succeeded. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_Undo(FPDF_FORMHANDLE hHandle, FPDF_PAGE page); // Function: FORM_Redo // Make the current focused widget perform a redo operation. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page, as returned by FPDF_LoadPage(). // Return Value: // True if the redo operation succeeded. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_Redo(FPDF_FORMHANDLE hHandle, FPDF_PAGE page); // Function: FORM_ForceToKillFocus. // Call this member function to force to kill the focus of the form // field which has focus. If it would kill the focus of a form field, // save the value of form field if was changed by theuser. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // Return Value: // True indicates success; otherwise false. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_ForceToKillFocus(FPDF_FORMHANDLE hHandle); // Experimental API. // Function: FORM_GetFocusedAnnot. // Call this member function to get the currently focused annotation. // Parameters: // handle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // page_index - Buffer to hold the index number of the page which // contains the focused annotation. 0 for the first page. // Can't be NULL. // annot - Buffer to hold the focused annotation. Can't be NULL. // Return Value: // On success, return true and write to the out parameters. Otherwise // return false and leave the out parameters unmodified. // Comments: // Not currently supported for XFA forms - will report no focused // annotation. // Must call FPDFPage_CloseAnnot() when the annotation returned in |annot| // by this function is no longer needed. // This will return true and set |page_index| to -1 and |annot| to NULL, // if there is no focused annotation. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_GetFocusedAnnot(FPDF_FORMHANDLE handle, int* page_index, FPDF_ANNOTATION* annot); // Experimental API. // Function: FORM_SetFocusedAnnot. // Call this member function to set the currently focused annotation. // Parameters: // handle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // annot - Handle to an annotation. // Return Value: // True indicates success; otherwise false. // Comments: // |annot| can't be NULL. To kill focus, use FORM_ForceToKillFocus() // instead. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_SetFocusedAnnot(FPDF_FORMHANDLE handle, FPDF_ANNOTATION annot); // Form Field Types // The names of the defines are stable, but the specific values associated with // them are not, so do not hardcode their values. #define FPDF_FORMFIELD_UNKNOWN 0 // Unknown. #define FPDF_FORMFIELD_PUSHBUTTON 1 // push button type. #define FPDF_FORMFIELD_CHECKBOX 2 // check box type. #define FPDF_FORMFIELD_RADIOBUTTON 3 // radio button type. #define FPDF_FORMFIELD_COMBOBOX 4 // combo box type. #define FPDF_FORMFIELD_LISTBOX 5 // list box type. #define FPDF_FORMFIELD_TEXTFIELD 6 // text field type. #define FPDF_FORMFIELD_SIGNATURE 7 // text field type. #ifdef PDF_ENABLE_XFA #define FPDF_FORMFIELD_XFA 8 // Generic XFA type. #define FPDF_FORMFIELD_XFA_CHECKBOX 9 // XFA check box type. #define FPDF_FORMFIELD_XFA_COMBOBOX 10 // XFA combo box type. #define FPDF_FORMFIELD_XFA_IMAGEFIELD 11 // XFA image field type. #define FPDF_FORMFIELD_XFA_LISTBOX 12 // XFA list box type. #define FPDF_FORMFIELD_XFA_PUSHBUTTON 13 // XFA push button type. #define FPDF_FORMFIELD_XFA_SIGNATURE 14 // XFA signture field type. #define FPDF_FORMFIELD_XFA_TEXTFIELD 15 // XFA text field type. #endif // PDF_ENABLE_XFA #ifdef PDF_ENABLE_XFA #define FPDF_FORMFIELD_COUNT 16 #else // PDF_ENABLE_XFA #define FPDF_FORMFIELD_COUNT 8 #endif // PDF_ENABLE_XFA #ifdef PDF_ENABLE_XFA #define IS_XFA_FORMFIELD(type) \ (((type) == FPDF_FORMFIELD_XFA) || \ ((type) == FPDF_FORMFIELD_XFA_CHECKBOX) || \ ((type) == FPDF_FORMFIELD_XFA_COMBOBOX) || \ ((type) == FPDF_FORMFIELD_XFA_IMAGEFIELD) || \ ((type) == FPDF_FORMFIELD_XFA_LISTBOX) || \ ((type) == FPDF_FORMFIELD_XFA_PUSHBUTTON) || \ ((type) == FPDF_FORMFIELD_XFA_SIGNATURE) || \ ((type) == FPDF_FORMFIELD_XFA_TEXTFIELD)) #endif // PDF_ENABLE_XFA // Function: FPDFPage_HasFormFieldAtPoint // Get the form field type by point. // Parameters: // hHandle - Handle to the form fill module. Returned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page. Returned by FPDF_LoadPage(). // page_x - X position in PDF "user space". // page_y - Y position in PDF "user space". // Return Value: // Return the type of the form field; -1 indicates no field. // See field types above. FPDF_EXPORT int FPDF_CALLCONV FPDFPage_HasFormFieldAtPoint(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, double page_x, double page_y); // Function: FPDFPage_FormFieldZOrderAtPoint // Get the form field z-order by point. // Parameters: // hHandle - Handle to the form fill module. Returned by // FPDFDOC_InitFormFillEnvironment(). // page - Handle to the page. Returned by FPDF_LoadPage(). // page_x - X position in PDF "user space". // page_y - Y position in PDF "user space". // Return Value: // Return the z-order of the form field; -1 indicates no field. // Higher numbers are closer to the front. FPDF_EXPORT int FPDF_CALLCONV FPDFPage_FormFieldZOrderAtPoint(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, double page_x, double page_y); // Function: FPDF_SetFormFieldHighlightColor // Set the highlight color of the specified (or all) form fields // in the document. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // doc - Handle to the document, as returned by // FPDF_LoadDocument(). // fieldType - A 32-bit integer indicating the type of a form // field (defined above). // color - The highlight color of the form field. Constructed by // 0xxxrrggbb. // Return Value: // None. // Comments: // When the parameter fieldType is set to FPDF_FORMFIELD_UNKNOWN, the // highlight color will be applied to all the form fields in the // document. // Please refresh the client window to show the highlight immediately // if necessary. FPDF_EXPORT void FPDF_CALLCONV FPDF_SetFormFieldHighlightColor(FPDF_FORMHANDLE hHandle, int fieldType, unsigned long color); // Function: FPDF_SetFormFieldHighlightAlpha // Set the transparency of the form field highlight color in the // document. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // doc - Handle to the document, as returaned by // FPDF_LoadDocument(). // alpha - The transparency of the form field highlight color, // between 0-255. // Return Value: // None. FPDF_EXPORT void FPDF_CALLCONV FPDF_SetFormFieldHighlightAlpha(FPDF_FORMHANDLE hHandle, unsigned char alpha); // Function: FPDF_RemoveFormFieldHighlight // Remove the form field highlight color in the document. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // Return Value: // None. // Comments: // Please refresh the client window to remove the highlight immediately // if necessary. FPDF_EXPORT void FPDF_CALLCONV FPDF_RemoveFormFieldHighlight(FPDF_FORMHANDLE hHandle); // Function: FPDF_FFLDraw // Render FormFields and popup window on a page to a device independent // bitmap. // Parameters: // hHandle - Handle to the form fill module, as returned by // FPDFDOC_InitFormFillEnvironment(). // bitmap - Handle to the device independent bitmap (as the // output buffer). Bitmap handles can be created by // FPDFBitmap_Create(). // page - Handle to the page, as returned by FPDF_LoadPage(). // start_x - Left pixel position of the display area in the // device coordinates. // start_y - Top pixel position of the display area in the device // coordinates. // size_x - Horizontal size (in pixels) for displaying the page. // size_y - Vertical size (in pixels) for displaying the page. // rotate - Page orientation: 0 (normal), 1 (rotated 90 degrees // clockwise), 2 (rotated 180 degrees), 3 (rotated 90 // degrees counter-clockwise). // flags - 0 for normal display, or combination of flags // defined above. // Return Value: // None. // Comments: // This function is designed to render annotations that are // user-interactive, which are widget annotations (for FormFields) and // popup annotations. // With the FPDF_ANNOT flag, this function will render a popup annotation // when users mouse-hover on a non-widget annotation. Regardless of // FPDF_ANNOT flag, this function will always render widget annotations // for FormFields. // In order to implement the FormFill functions, implementation should // call this function after rendering functions, such as // FPDF_RenderPageBitmap() or FPDF_RenderPageBitmap_Start(), have // finished rendering the page contents. FPDF_EXPORT void FPDF_CALLCONV FPDF_FFLDraw(FPDF_FORMHANDLE hHandle, FPDF_BITMAP bitmap, FPDF_PAGE page, int start_x, int start_y, int size_x, int size_y, int rotate, int flags); #if defined(PDF_USE_SKIA) FPDF_EXPORT void FPDF_CALLCONV FPDF_FFLDrawSkia(FPDF_FORMHANDLE hHandle, FPDF_SKIA_CANVAS canvas, FPDF_PAGE page, int start_x, int start_y, int size_x, int size_y, int rotate, int flags); #endif // Experimental API // Function: FPDF_GetFormType // Returns the type of form contained in the PDF document. // Parameters: // document - Handle to document. // Return Value: // Integer value representing one of the FORMTYPE_ values. // Comments: // If |document| is NULL, then the return value is FORMTYPE_NONE. FPDF_EXPORT int FPDF_CALLCONV FPDF_GetFormType(FPDF_DOCUMENT document); // Experimental API // Function: FORM_SetIndexSelected // Selects/deselects the value at the given |index| of the focused // annotation. // Parameters: // hHandle - Handle to the form fill module. Returned by // FPDFDOC_InitFormFillEnvironment. // page - Handle to the page. Returned by FPDF_LoadPage // index - 0-based index of value to be set as // selected/unselected // selected - true to select, false to deselect // Return Value: // TRUE if the operation succeeded. // FALSE if the operation failed or widget is not a supported type. // Comments: // Intended for use with listbox/combobox widget types. Comboboxes // have at most a single value selected at a time which cannot be // deselected. Deselect on a combobox is a no-op that returns false. // Default implementation is a no-op that will return false for // other types. // Not currently supported for XFA forms - will return false. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_SetIndexSelected(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, int index, FPDF_BOOL selected); // Experimental API // Function: FORM_IsIndexSelected // Returns whether or not the value at |index| of the focused // annotation is currently selected. // Parameters: // hHandle - Handle to the form fill module. Returned by // FPDFDOC_InitFormFillEnvironment. // page - Handle to the page. Returned by FPDF_LoadPage // index - 0-based Index of value to check // Return Value: // TRUE if value at |index| is currently selected. // FALSE if value at |index| is not selected or widget is not a // supported type. // Comments: // Intended for use with listbox/combobox widget types. Default // implementation is a no-op that will return false for other types. // Not currently supported for XFA forms - will return false. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_IsIndexSelected(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, int index); // Function: FPDF_LoadXFA // If the document consists of XFA fields, call this method to // attempt to load XFA fields. // Parameters: // document - Handle to document from FPDF_LoadDocument(). // Return Value: // TRUE upon success, otherwise FALSE. If XFA support is not built // into PDFium, performs no action and always returns FALSE. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_LoadXFA(FPDF_DOCUMENT document); #ifdef __cplusplus } #endif #endif // PUBLIC_FPDF_FORMFILL_H_ ================================================ FILE: external/pdfium/windows-x64/include/fpdf_fwlevent.h ================================================ // Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #ifndef PUBLIC_FPDF_FWLEVENT_H_ #define PUBLIC_FPDF_FWLEVENT_H_ // NOLINTNEXTLINE(build/include) #include "fpdfview.h" #ifdef __cplusplus extern "C" { #endif // __cplusplus // Key flags. typedef enum { FWL_EVENTFLAG_ShiftKey = 1 << 0, FWL_EVENTFLAG_ControlKey = 1 << 1, FWL_EVENTFLAG_AltKey = 1 << 2, FWL_EVENTFLAG_MetaKey = 1 << 3, FWL_EVENTFLAG_KeyPad = 1 << 4, FWL_EVENTFLAG_AutoRepeat = 1 << 5, FWL_EVENTFLAG_LeftButtonDown = 1 << 6, FWL_EVENTFLAG_MiddleButtonDown = 1 << 7, FWL_EVENTFLAG_RightButtonDown = 1 << 8, } FWL_EVENTFLAG; // Virtual keycodes. typedef enum { FWL_VKEY_Back = 0x08, FWL_VKEY_Tab = 0x09, FWL_VKEY_NewLine = 0x0A, FWL_VKEY_Clear = 0x0C, FWL_VKEY_Return = 0x0D, FWL_VKEY_Shift = 0x10, FWL_VKEY_Control = 0x11, FWL_VKEY_Menu = 0x12, FWL_VKEY_Pause = 0x13, FWL_VKEY_Capital = 0x14, FWL_VKEY_Kana = 0x15, FWL_VKEY_Hangul = 0x15, FWL_VKEY_Junja = 0x17, FWL_VKEY_Final = 0x18, FWL_VKEY_Hanja = 0x19, FWL_VKEY_Kanji = 0x19, FWL_VKEY_Escape = 0x1B, FWL_VKEY_Convert = 0x1C, FWL_VKEY_NonConvert = 0x1D, FWL_VKEY_Accept = 0x1E, FWL_VKEY_ModeChange = 0x1F, FWL_VKEY_Space = 0x20, FWL_VKEY_Prior = 0x21, FWL_VKEY_Next = 0x22, FWL_VKEY_End = 0x23, FWL_VKEY_Home = 0x24, FWL_VKEY_Left = 0x25, FWL_VKEY_Up = 0x26, FWL_VKEY_Right = 0x27, FWL_VKEY_Down = 0x28, FWL_VKEY_Select = 0x29, FWL_VKEY_Print = 0x2A, FWL_VKEY_Execute = 0x2B, FWL_VKEY_Snapshot = 0x2C, FWL_VKEY_Insert = 0x2D, FWL_VKEY_Delete = 0x2E, FWL_VKEY_Help = 0x2F, FWL_VKEY_0 = 0x30, FWL_VKEY_1 = 0x31, FWL_VKEY_2 = 0x32, FWL_VKEY_3 = 0x33, FWL_VKEY_4 = 0x34, FWL_VKEY_5 = 0x35, FWL_VKEY_6 = 0x36, FWL_VKEY_7 = 0x37, FWL_VKEY_8 = 0x38, FWL_VKEY_9 = 0x39, FWL_VKEY_A = 0x41, FWL_VKEY_B = 0x42, FWL_VKEY_C = 0x43, FWL_VKEY_D = 0x44, FWL_VKEY_E = 0x45, FWL_VKEY_F = 0x46, FWL_VKEY_G = 0x47, FWL_VKEY_H = 0x48, FWL_VKEY_I = 0x49, FWL_VKEY_J = 0x4A, FWL_VKEY_K = 0x4B, FWL_VKEY_L = 0x4C, FWL_VKEY_M = 0x4D, FWL_VKEY_N = 0x4E, FWL_VKEY_O = 0x4F, FWL_VKEY_P = 0x50, FWL_VKEY_Q = 0x51, FWL_VKEY_R = 0x52, FWL_VKEY_S = 0x53, FWL_VKEY_T = 0x54, FWL_VKEY_U = 0x55, FWL_VKEY_V = 0x56, FWL_VKEY_W = 0x57, FWL_VKEY_X = 0x58, FWL_VKEY_Y = 0x59, FWL_VKEY_Z = 0x5A, FWL_VKEY_LWin = 0x5B, FWL_VKEY_Command = 0x5B, FWL_VKEY_RWin = 0x5C, FWL_VKEY_Apps = 0x5D, FWL_VKEY_Sleep = 0x5F, FWL_VKEY_NumPad0 = 0x60, FWL_VKEY_NumPad1 = 0x61, FWL_VKEY_NumPad2 = 0x62, FWL_VKEY_NumPad3 = 0x63, FWL_VKEY_NumPad4 = 0x64, FWL_VKEY_NumPad5 = 0x65, FWL_VKEY_NumPad6 = 0x66, FWL_VKEY_NumPad7 = 0x67, FWL_VKEY_NumPad8 = 0x68, FWL_VKEY_NumPad9 = 0x69, FWL_VKEY_Multiply = 0x6A, FWL_VKEY_Add = 0x6B, FWL_VKEY_Separator = 0x6C, FWL_VKEY_Subtract = 0x6D, FWL_VKEY_Decimal = 0x6E, FWL_VKEY_Divide = 0x6F, FWL_VKEY_F1 = 0x70, FWL_VKEY_F2 = 0x71, FWL_VKEY_F3 = 0x72, FWL_VKEY_F4 = 0x73, FWL_VKEY_F5 = 0x74, FWL_VKEY_F6 = 0x75, FWL_VKEY_F7 = 0x76, FWL_VKEY_F8 = 0x77, FWL_VKEY_F9 = 0x78, FWL_VKEY_F10 = 0x79, FWL_VKEY_F11 = 0x7A, FWL_VKEY_F12 = 0x7B, FWL_VKEY_F13 = 0x7C, FWL_VKEY_F14 = 0x7D, FWL_VKEY_F15 = 0x7E, FWL_VKEY_F16 = 0x7F, FWL_VKEY_F17 = 0x80, FWL_VKEY_F18 = 0x81, FWL_VKEY_F19 = 0x82, FWL_VKEY_F20 = 0x83, FWL_VKEY_F21 = 0x84, FWL_VKEY_F22 = 0x85, FWL_VKEY_F23 = 0x86, FWL_VKEY_F24 = 0x87, FWL_VKEY_NunLock = 0x90, FWL_VKEY_Scroll = 0x91, FWL_VKEY_LShift = 0xA0, FWL_VKEY_RShift = 0xA1, FWL_VKEY_LControl = 0xA2, FWL_VKEY_RControl = 0xA3, FWL_VKEY_LMenu = 0xA4, FWL_VKEY_RMenu = 0xA5, FWL_VKEY_BROWSER_Back = 0xA6, FWL_VKEY_BROWSER_Forward = 0xA7, FWL_VKEY_BROWSER_Refresh = 0xA8, FWL_VKEY_BROWSER_Stop = 0xA9, FWL_VKEY_BROWSER_Search = 0xAA, FWL_VKEY_BROWSER_Favorites = 0xAB, FWL_VKEY_BROWSER_Home = 0xAC, FWL_VKEY_VOLUME_Mute = 0xAD, FWL_VKEY_VOLUME_Down = 0xAE, FWL_VKEY_VOLUME_Up = 0xAF, FWL_VKEY_MEDIA_NEXT_Track = 0xB0, FWL_VKEY_MEDIA_PREV_Track = 0xB1, FWL_VKEY_MEDIA_Stop = 0xB2, FWL_VKEY_MEDIA_PLAY_Pause = 0xB3, FWL_VKEY_MEDIA_LAUNCH_Mail = 0xB4, FWL_VKEY_MEDIA_LAUNCH_MEDIA_Select = 0xB5, FWL_VKEY_MEDIA_LAUNCH_APP1 = 0xB6, FWL_VKEY_MEDIA_LAUNCH_APP2 = 0xB7, FWL_VKEY_OEM_1 = 0xBA, FWL_VKEY_OEM_Plus = 0xBB, FWL_VKEY_OEM_Comma = 0xBC, FWL_VKEY_OEM_Minus = 0xBD, FWL_VKEY_OEM_Period = 0xBE, FWL_VKEY_OEM_2 = 0xBF, FWL_VKEY_OEM_3 = 0xC0, FWL_VKEY_OEM_4 = 0xDB, FWL_VKEY_OEM_5 = 0xDC, FWL_VKEY_OEM_6 = 0xDD, FWL_VKEY_OEM_7 = 0xDE, FWL_VKEY_OEM_8 = 0xDF, FWL_VKEY_OEM_102 = 0xE2, FWL_VKEY_ProcessKey = 0xE5, FWL_VKEY_Packet = 0xE7, FWL_VKEY_Attn = 0xF6, FWL_VKEY_Crsel = 0xF7, FWL_VKEY_Exsel = 0xF8, FWL_VKEY_Ereof = 0xF9, FWL_VKEY_Play = 0xFA, FWL_VKEY_Zoom = 0xFB, FWL_VKEY_NoName = 0xFC, FWL_VKEY_PA1 = 0xFD, FWL_VKEY_OEM_Clear = 0xFE, FWL_VKEY_Unknown = 0, } FWL_VKEYCODE; #ifdef __cplusplus } // extern "C" #endif // __cplusplus #endif // PUBLIC_FPDF_FWLEVENT_H_ ================================================ FILE: external/pdfium/windows-x64/include/fpdf_javascript.h ================================================ // Copyright 2019 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef PUBLIC_FPDF_JAVASCRIPT_H_ #define PUBLIC_FPDF_JAVASCRIPT_H_ // NOLINTNEXTLINE(build/include) #include "fpdfview.h" #ifdef __cplusplus extern "C" { #endif // __cplusplus // Experimental API. // Get the number of JavaScript actions in |document|. // // document - handle to a document. // // Returns the number of JavaScript actions in |document| or -1 on error. FPDF_EXPORT int FPDF_CALLCONV FPDFDoc_GetJavaScriptActionCount(FPDF_DOCUMENT document); // Experimental API. // Get the JavaScript action at |index| in |document|. // // document - handle to a document. // index - the index of the requested JavaScript action. // // Returns the handle to the JavaScript action, or NULL on failure. // Caller owns the returned handle and must close it with // FPDFDoc_CloseJavaScriptAction(). FPDF_EXPORT FPDF_JAVASCRIPT_ACTION FPDF_CALLCONV FPDFDoc_GetJavaScriptAction(FPDF_DOCUMENT document, int index); // Experimental API. // Close a loaded FPDF_JAVASCRIPT_ACTION object. // javascript - Handle to a JavaScript action. FPDF_EXPORT void FPDF_CALLCONV FPDFDoc_CloseJavaScriptAction(FPDF_JAVASCRIPT_ACTION javascript); // Experimental API. // Get the name from the |javascript| handle. |buffer| is only modified if // |buflen| is longer than the length of the name. On errors, |buffer| is // unmodified and the returned length is 0. // // javascript - handle to an JavaScript action. // buffer - buffer for holding the name, encoded in UTF-16LE. // buflen - length of the buffer in bytes. // // Returns the length of the JavaScript action name in bytes. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFJavaScriptAction_GetName(FPDF_JAVASCRIPT_ACTION javascript, FPDF_WCHAR* buffer, unsigned long buflen); // Experimental API. // Get the script from the |javascript| handle. |buffer| is only modified if // |buflen| is longer than the length of the script. On errors, |buffer| is // unmodified and the returned length is 0. // // javascript - handle to an JavaScript action. // buffer - buffer for holding the name, encoded in UTF-16LE. // buflen - length of the buffer in bytes. // // Returns the length of the JavaScript action name in bytes. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFJavaScriptAction_GetScript(FPDF_JAVASCRIPT_ACTION javascript, FPDF_WCHAR* buffer, unsigned long buflen); #ifdef __cplusplus } // extern "C" #endif // __cplusplus #endif // PUBLIC_FPDF_JAVASCRIPT_H_ ================================================ FILE: external/pdfium/windows-x64/include/fpdf_ppo.h ================================================ // Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #ifndef PUBLIC_FPDF_PPO_H_ #define PUBLIC_FPDF_PPO_H_ // NOLINTNEXTLINE(build/include) #include "fpdfview.h" #ifdef __cplusplus extern "C" { #endif // Experimental API. // Import pages to a FPDF_DOCUMENT. // // dest_doc - The destination document for the pages. // src_doc - The document to be imported. // page_indices - An array of page indices to be imported. The first page is // zero. If |page_indices| is NULL, all pages from |src_doc| // are imported. // length - The length of the |page_indices| array. // index - The page index at which to insert the first imported page // into |dest_doc|. The first page is zero. // // Returns TRUE on success. Returns FALSE if any pages in |page_indices| is // invalid. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_ImportPagesByIndex(FPDF_DOCUMENT dest_doc, FPDF_DOCUMENT src_doc, const int* page_indices, unsigned long length, int index); // Import pages to a FPDF_DOCUMENT. // // dest_doc - The destination document for the pages. // src_doc - The document to be imported. // pagerange - A page range string, Such as "1,3,5-7". The first page is one. // If |pagerange| is NULL, all pages from |src_doc| are imported. // index - The page index at which to insert the first imported page into // |dest_doc|. The first page is zero. // // Returns TRUE on success. Returns FALSE if any pages in |pagerange| is // invalid or if |pagerange| cannot be read. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_ImportPages(FPDF_DOCUMENT dest_doc, FPDF_DOCUMENT src_doc, FPDF_BYTESTRING pagerange, int index); // Experimental API. // Create a new document from |src_doc|. The pages of |src_doc| will be // combined to provide |num_pages_on_x_axis x num_pages_on_y_axis| pages per // |output_doc| page. // // src_doc - The document to be imported. // output_width - The output page width in PDF "user space" units. // output_height - The output page height in PDF "user space" units. // num_pages_on_x_axis - The number of pages on X Axis. // num_pages_on_y_axis - The number of pages on Y Axis. // // Return value: // A handle to the created document, or NULL on failure. // // Comments: // number of pages per page = num_pages_on_x_axis * num_pages_on_y_axis // FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV FPDF_ImportNPagesToOne(FPDF_DOCUMENT src_doc, float output_width, float output_height, size_t num_pages_on_x_axis, size_t num_pages_on_y_axis); // Experimental API. // Create a template to generate form xobjects from |src_doc|'s page at // |src_page_index|, for use in |dest_doc|. // // Returns a handle on success, or NULL on failure. Caller owns the newly // created object. FPDF_EXPORT FPDF_XOBJECT FPDF_CALLCONV FPDF_NewXObjectFromPage(FPDF_DOCUMENT dest_doc, FPDF_DOCUMENT src_doc, int src_page_index); // Experimental API. // Close an FPDF_XOBJECT handle created by FPDF_NewXObjectFromPage(). // FPDF_PAGEOBJECTs created from the FPDF_XOBJECT handle are not affected. FPDF_EXPORT void FPDF_CALLCONV FPDF_CloseXObject(FPDF_XOBJECT xobject); // Experimental API. // Create a new form object from an FPDF_XOBJECT object. // // Returns a new form object on success, or NULL on failure. Caller owns the // newly created object. FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV FPDF_NewFormObjectFromXObject(FPDF_XOBJECT xobject); // Copy the viewer preferences from |src_doc| into |dest_doc|. // // dest_doc - Document to write the viewer preferences into. // src_doc - Document to read the viewer preferences from. // // Returns TRUE on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_CopyViewerPreferences(FPDF_DOCUMENT dest_doc, FPDF_DOCUMENT src_doc); #ifdef __cplusplus } // extern "C" #endif // __cplusplus #endif // PUBLIC_FPDF_PPO_H_ ================================================ FILE: external/pdfium/windows-x64/include/fpdf_progressive.h ================================================ // Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #ifndef PUBLIC_FPDF_PROGRESSIVE_H_ #define PUBLIC_FPDF_PROGRESSIVE_H_ // clang-format off // NOLINTNEXTLINE(build/include) #include "fpdfview.h" // Flags for progressive process status. #define FPDF_RENDER_READY 0 #define FPDF_RENDER_TOBECONTINUED 1 #define FPDF_RENDER_DONE 2 #define FPDF_RENDER_FAILED 3 #ifdef __cplusplus extern "C" { #endif // IFPDF_RENDERINFO interface. typedef struct _IFSDK_PAUSE { // Version number of the interface. Currently must be 1. int version; // Method: NeedToPauseNow // Check if we need to pause a progressive process now. // Interface Version: // 1 // Implementation Required: // yes // Parameters: // pThis - Pointer to the interface structure itself // Return Value: // Non-zero for pause now, 0 for continue. FPDF_BOOL (*NeedToPauseNow)(struct _IFSDK_PAUSE* pThis); // A user defined data pointer, used by user's application. Can be NULL. void* user; } IFSDK_PAUSE; // Experimental API. // Function: FPDF_RenderPageBitmapWithColorScheme_Start // Start to render page contents to a device independent bitmap // progressively with a specified color scheme for the content. // Parameters: // bitmap - Handle to the device independent bitmap (as the // output buffer). Bitmap handle can be created by // FPDFBitmap_Create function. // page - Handle to the page as returned by FPDF_LoadPage // function. // start_x - Left pixel position of the display area in the // bitmap coordinate. // start_y - Top pixel position of the display area in the // bitmap coordinate. // size_x - Horizontal size (in pixels) for displaying the // page. // size_y - Vertical size (in pixels) for displaying the page. // rotate - Page orientation: 0 (normal), 1 (rotated 90 // degrees clockwise), 2 (rotated 180 degrees), // 3 (rotated 90 degrees counter-clockwise). // flags - 0 for normal display, or combination of flags // defined in fpdfview.h. With FPDF_ANNOT flag, it // renders all annotations that does not require // user-interaction, which are all annotations except // widget and popup annotations. // color_scheme - Color scheme to be used in rendering the |page|. // If null, this function will work similar to // FPDF_RenderPageBitmap_Start(). // pause - The IFSDK_PAUSE interface. A callback mechanism // allowing the page rendering process. // Return value: // Rendering Status. See flags for progressive process status for the // details. FPDF_EXPORT int FPDF_CALLCONV FPDF_RenderPageBitmapWithColorScheme_Start(FPDF_BITMAP bitmap, FPDF_PAGE page, int start_x, int start_y, int size_x, int size_y, int rotate, int flags, const FPDF_COLORSCHEME* color_scheme, IFSDK_PAUSE* pause); // Function: FPDF_RenderPageBitmap_Start // Start to render page contents to a device independent bitmap // progressively. // Parameters: // bitmap - Handle to the device independent bitmap (as the // output buffer). Bitmap handle can be created by // FPDFBitmap_Create(). // page - Handle to the page, as returned by FPDF_LoadPage(). // start_x - Left pixel position of the display area in the // bitmap coordinates. // start_y - Top pixel position of the display area in the bitmap // coordinates. // size_x - Horizontal size (in pixels) for displaying the page. // size_y - Vertical size (in pixels) for displaying the page. // rotate - Page orientation: 0 (normal), 1 (rotated 90 degrees // clockwise), 2 (rotated 180 degrees), 3 (rotated 90 // degrees counter-clockwise). // flags - 0 for normal display, or combination of flags // defined in fpdfview.h. With FPDF_ANNOT flag, it // renders all annotations that does not require // user-interaction, which are all annotations except // widget and popup annotations. // pause - The IFSDK_PAUSE interface.A callback mechanism // allowing the page rendering process // Return value: // Rendering Status. See flags for progressive process status for the // details. FPDF_EXPORT int FPDF_CALLCONV FPDF_RenderPageBitmap_Start(FPDF_BITMAP bitmap, FPDF_PAGE page, int start_x, int start_y, int size_x, int size_y, int rotate, int flags, IFSDK_PAUSE* pause); // Function: FPDF_RenderPage_Continue // Continue rendering a PDF page. // Parameters: // page - Handle to the page, as returned by FPDF_LoadPage(). // pause - The IFSDK_PAUSE interface (a callback mechanism // allowing the page rendering process to be paused // before it's finished). This can be NULL if you // don't want to pause. // Return value: // The rendering status. See flags for progressive process status for // the details. FPDF_EXPORT int FPDF_CALLCONV FPDF_RenderPage_Continue(FPDF_PAGE page, IFSDK_PAUSE* pause); // Function: FPDF_RenderPage_Close // Release the resource allocate during page rendering. Need to be // called after finishing rendering or // cancel the rendering. // Parameters: // page - Handle to the page, as returned by FPDF_LoadPage(). // Return value: // None. FPDF_EXPORT void FPDF_CALLCONV FPDF_RenderPage_Close(FPDF_PAGE page); #ifdef __cplusplus } #endif #endif // PUBLIC_FPDF_PROGRESSIVE_H_ ================================================ FILE: external/pdfium/windows-x64/include/fpdf_save.h ================================================ // Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #ifndef PUBLIC_FPDF_SAVE_H_ #define PUBLIC_FPDF_SAVE_H_ // clang-format off // NOLINTNEXTLINE(build/include) #include "fpdfview.h" #ifdef __cplusplus extern "C" { #endif // Structure for custom file write typedef struct FPDF_FILEWRITE_ { // // Version number of the interface. Currently must be 1. // int version; // Method: WriteBlock // Output a block of data in your custom way. // Interface Version: // 1 // Implementation Required: // Yes // Comments: // Called by function FPDF_SaveDocument // Parameters: // self - Pointer to the structure itself // data - Pointer to a buffer to output // size - The size of the buffer. // Return value: // Should be non-zero if successful, zero for error. int (*WriteBlock)(struct FPDF_FILEWRITE_* self, const void* data, unsigned long size); } FPDF_FILEWRITE; // Flags for FPDF_SaveAsCopy(). // FPDF_INCREMENTAL and FPDF_NO_INCREMENTAL cannot be used together. #define FPDF_INCREMENTAL (1 << 0) #define FPDF_NO_INCREMENTAL (1 << 1) // Deprecated. Use FPDF_REMOVE_SECURITY instead. // TODO(crbug.com/42270430): Remove FPDF_REMOVE_SECURITY_DEPRECATED. #define FPDF_REMOVE_SECURITY_DEPRECATED 3 #define FPDF_REMOVE_SECURITY (1 << 2) // Experimental. Subsets any embedded font files for new text objects added to // the document. #define FPDF_SUBSET_NEW_FONTS (1 << 3) // Function: FPDF_SaveAsCopy // Saves the copy of specified document in custom way. // Parameters: // document - Handle to document, as returned by // FPDF_LoadDocument() or FPDF_CreateNewDocument(). // file_write - A pointer to a custom file write structure. // flags - Flags above that affect how the PDF gets saved. // Pass in 0 when there are no flags. // Return value: // TRUE for succeed, FALSE for failed. // FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_SaveAsCopy(FPDF_DOCUMENT document, FPDF_FILEWRITE* file_write, FPDF_DWORD flags); // Function: FPDF_SaveWithVersion // Same as FPDF_SaveAsCopy(), except the file version of the // saved document can be specified by the caller. // Parameters: // document - Handle to document. // file_write - A pointer to a custom file write structure. // flags - The creating flags. // file_version - The PDF file version. File version: 14 for 1.4, // 15 for 1.5, ... // Return value: // TRUE if succeed, FALSE if failed. // FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_SaveWithVersion(FPDF_DOCUMENT document, FPDF_FILEWRITE* file_write, FPDF_DWORD flags, int file_version); #ifdef __cplusplus } #endif #endif // PUBLIC_FPDF_SAVE_H_ ================================================ FILE: external/pdfium/windows-x64/include/fpdf_searchex.h ================================================ // Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #ifndef PUBLIC_FPDF_SEARCHEX_H_ #define PUBLIC_FPDF_SEARCHEX_H_ // NOLINTNEXTLINE(build/include) #include "fpdfview.h" #ifdef __cplusplus extern "C" { #endif // __cplusplus // Get the character index in |text_page| internal character list. // // text_page - a text page information structure. // nTextIndex - index of the text returned from FPDFText_GetText(). // // Returns the index of the character in internal character list. -1 for error. FPDF_EXPORT int FPDF_CALLCONV FPDFText_GetCharIndexFromTextIndex(FPDF_TEXTPAGE text_page, int nTextIndex); // Get the text index in |text_page| internal character list. // // text_page - a text page information structure. // nCharIndex - index of the character in internal character list. // // Returns the index of the text returned from FPDFText_GetText(). -1 for error. FPDF_EXPORT int FPDF_CALLCONV FPDFText_GetTextIndexFromCharIndex(FPDF_TEXTPAGE text_page, int nCharIndex); #ifdef __cplusplus } // extern "C" #endif // __cplusplus #endif // PUBLIC_FPDF_SEARCHEX_H_ ================================================ FILE: external/pdfium/windows-x64/include/fpdf_signature.h ================================================ // Copyright 2020 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef PUBLIC_FPDF_SIGNATURE_H_ #define PUBLIC_FPDF_SIGNATURE_H_ // NOLINTNEXTLINE(build/include) #include "fpdfview.h" #ifdef __cplusplus extern "C" { #endif // __cplusplus // Experimental API. // Function: FPDF_GetSignatureCount // Get total number of signatures in the document. // Parameters: // document - Handle to document. Returned by FPDF_LoadDocument(). // Return value: // Total number of signatures in the document on success, -1 on error. FPDF_EXPORT int FPDF_CALLCONV FPDF_GetSignatureCount(FPDF_DOCUMENT document); // Experimental API. // Function: FPDF_GetSignatureObject // Get the Nth signature of the document. // Parameters: // document - Handle to document. Returned by FPDF_LoadDocument(). // index - Index into the array of signatures of the document. // Return value: // Returns the handle to the signature, or NULL on failure. The caller // does not take ownership of the returned FPDF_SIGNATURE. Instead, it // remains valid until FPDF_CloseDocument() is called for the document. FPDF_EXPORT FPDF_SIGNATURE FPDF_CALLCONV FPDF_GetSignatureObject(FPDF_DOCUMENT document, int index); // Experimental API. // Function: FPDFSignatureObj_GetContents // Get the contents of a signature object. // Parameters: // signature - Handle to the signature object. Returned by // FPDF_GetSignatureObject(). // buffer - The address of a buffer that receives the contents. // length - The size, in bytes, of |buffer|. // Return value: // Returns the number of bytes in the contents on success, 0 on error. // // For public-key signatures, |buffer| is either a DER-encoded PKCS#1 binary or // a DER-encoded PKCS#7 binary. If |length| is less than the returned length, or // |buffer| is NULL, |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFSignatureObj_GetContents(FPDF_SIGNATURE signature, void* buffer, unsigned long length); // Experimental API. // Function: FPDFSignatureObj_GetByteRange // Get the byte range of a signature object. // Parameters: // signature - Handle to the signature object. Returned by // FPDF_GetSignatureObject(). // buffer - The address of a buffer that receives the // byte range. // length - The size, in ints, of |buffer|. // Return value: // Returns the number of ints in the byte range on // success, 0 on error. // // |buffer| is an array of pairs of integers (starting byte offset, // length in bytes) that describes the exact byte range for the digest // calculation. If |length| is less than the returned length, or // |buffer| is NULL, |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFSignatureObj_GetByteRange(FPDF_SIGNATURE signature, int* buffer, unsigned long length); // Experimental API. // Function: FPDFSignatureObj_GetSubFilter // Get the encoding of the value of a signature object. // Parameters: // signature - Handle to the signature object. Returned by // FPDF_GetSignatureObject(). // buffer - The address of a buffer that receives the encoding. // length - The size, in bytes, of |buffer|. // Return value: // Returns the number of bytes in the encoding name (including the // trailing NUL character) on success, 0 on error. // // The |buffer| is always encoded in 7-bit ASCII. If |length| is less than the // returned length, or |buffer| is NULL, |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFSignatureObj_GetSubFilter(FPDF_SIGNATURE signature, char* buffer, unsigned long length); // Experimental API. // Function: FPDFSignatureObj_GetReason // Get the reason (comment) of the signature object. // Parameters: // signature - Handle to the signature object. Returned by // FPDF_GetSignatureObject(). // buffer - The address of a buffer that receives the reason. // length - The size, in bytes, of |buffer|. // Return value: // Returns the number of bytes in the reason on success, 0 on error. // // Regardless of the platform, the |buffer| is always in UTF-16LE encoding. The // string is terminated by a UTF16 NUL character. If |length| is less than the // returned length, or |buffer| is NULL, |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFSignatureObj_GetReason(FPDF_SIGNATURE signature, void* buffer, unsigned long length); // Experimental API. // Function: FPDFSignatureObj_GetTime // Get the time of signing of a signature object. // Parameters: // signature - Handle to the signature object. Returned by // FPDF_GetSignatureObject(). // buffer - The address of a buffer that receives the time. // length - The size, in bytes, of |buffer|. // Return value: // Returns the number of bytes in the encoding name (including the // trailing NUL character) on success, 0 on error. // // The |buffer| is always encoded in 7-bit ASCII. If |length| is less than the // returned length, or |buffer| is NULL, |buffer| will not be modified. // // The format of time is expected to be D:YYYYMMDDHHMMSS+XX'YY', i.e. it's // percision is seconds, with timezone information. This value should be used // only when the time of signing is not available in the (PKCS#7 binary) // signature. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFSignatureObj_GetTime(FPDF_SIGNATURE signature, char* buffer, unsigned long length); // Experimental API. // Function: FPDFSignatureObj_GetDocMDPPermission // Get the DocMDP permission of a signature object. // Parameters: // signature - Handle to the signature object. Returned by // FPDF_GetSignatureObject(). // Return value: // Returns the permission (1, 2 or 3) on success, 0 on error. FPDF_EXPORT unsigned int FPDF_CALLCONV FPDFSignatureObj_GetDocMDPPermission(FPDF_SIGNATURE signature); #ifdef __cplusplus } // extern "C" #endif // __cplusplus #endif // PUBLIC_FPDF_SIGNATURE_H_ ================================================ FILE: external/pdfium/windows-x64/include/fpdf_structtree.h ================================================ // Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #ifndef PUBLIC_FPDF_STRUCTTREE_H_ #define PUBLIC_FPDF_STRUCTTREE_H_ // clang-format off // NOLINTNEXTLINE(build/include) #include "fpdfview.h" #ifdef __cplusplus extern "C" { #endif // Function: FPDF_StructTree_GetForPage // Get the structure tree for a page. // Parameters: // page - Handle to the page, as returned by FPDF_LoadPage(). // Return value: // A handle to the structure tree or NULL on error. The caller owns the // returned handle and must use FPDF_StructTree_Close() to release it. // The handle should be released before |page| gets released. FPDF_EXPORT FPDF_STRUCTTREE FPDF_CALLCONV FPDF_StructTree_GetForPage(FPDF_PAGE page); // Function: FPDF_StructTree_Close // Release a resource allocated by FPDF_StructTree_GetForPage(). // Parameters: // struct_tree - Handle to the structure tree, as returned by // FPDF_StructTree_LoadPage(). // Return value: // None. FPDF_EXPORT void FPDF_CALLCONV FPDF_StructTree_Close(FPDF_STRUCTTREE struct_tree); // Function: FPDF_StructTree_CountChildren // Count the number of children for the structure tree. // Parameters: // struct_tree - Handle to the structure tree, as returned by // FPDF_StructTree_LoadPage(). // Return value: // The number of children, or -1 on error. FPDF_EXPORT int FPDF_CALLCONV FPDF_StructTree_CountChildren(FPDF_STRUCTTREE struct_tree); // Function: FPDF_StructTree_GetChildAtIndex // Get a child in the structure tree. // Parameters: // struct_tree - Handle to the structure tree, as returned by // FPDF_StructTree_LoadPage(). // index - The index for the child, 0-based. // Return value: // The child at the n-th index or NULL on error. The caller does not // own the handle. The handle remains valid as long as |struct_tree| // remains valid. // Comments: // The |index| must be less than the FPDF_StructTree_CountChildren() // return value. FPDF_EXPORT FPDF_STRUCTELEMENT FPDF_CALLCONV FPDF_StructTree_GetChildAtIndex(FPDF_STRUCTTREE struct_tree, int index); // Function: FPDF_StructElement_GetAltText // Get the alt text for a given element. // Parameters: // struct_element - Handle to the struct element. // buffer - A buffer for output the alt text. May be NULL. // buflen - The length of the buffer, in bytes. May be 0. // Return value: // The number of bytes in the alt text, including the terminating NUL // character. The number of bytes is returned regardless of the // |buffer| and |buflen| parameters. // Comments: // Regardless of the platform, the |buffer| is always in UTF-16LE // encoding. The string is terminated by a UTF16 NUL character. If // |buflen| is less than the required length, or |buffer| is NULL, // |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_StructElement_GetAltText(FPDF_STRUCTELEMENT struct_element, void* buffer, unsigned long buflen); // Experimental API. // Function: FPDF_StructElement_GetActualText // Get the actual text for a given element. // Parameters: // struct_element - Handle to the struct element. // buffer - A buffer for output the actual text. May be NULL. // buflen - The length of the buffer, in bytes. May be 0. // Return value: // The number of bytes in the actual text, including the terminating // NUL character. The number of bytes is returned regardless of the // |buffer| and |buflen| parameters. // Comments: // Regardless of the platform, the |buffer| is always in UTF-16LE // encoding. The string is terminated by a UTF16 NUL character. If // |buflen| is less than the required length, or |buffer| is NULL, // |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_StructElement_GetActualText(FPDF_STRUCTELEMENT struct_element, void* buffer, unsigned long buflen); // Experimental API. // Function: FPDF_StructElement_GetExpansion // Get the expansion of an abbreviation or acronym for a given element. // Parameters: // struct_element - Handle to the struct element. // buffer - A buffer for output the expansion text. May be // NULL. // buflen - The length of the buffer, in bytes. May be 0. // Return value: // The number of bytes in the expansion text, including the terminating // NUL character. The number of bytes is returned regardless of the // |buffer| and |buflen| parameters. // Comments: // Regardless of the platform, the |buffer| is always in UTF-16LE // encoding. The string is terminated by a UTF16 NUL character. If // |buflen| is less than the required length, or |buffer| is NULL, // |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_StructElement_GetExpansion(FPDF_STRUCTELEMENT struct_element, void* buffer, unsigned long buflen); // Function: FPDF_StructElement_GetID // Get the ID for a given element. // Parameters: // struct_element - Handle to the struct element. // buffer - A buffer for output the ID string. May be NULL. // buflen - The length of the buffer, in bytes. May be 0. // Return value: // The number of bytes in the ID string, including the terminating NUL // character. The number of bytes is returned regardless of the // |buffer| and |buflen| parameters. // Comments: // Regardless of the platform, the |buffer| is always in UTF-16LE // encoding. The string is terminated by a UTF16 NUL character. If // |buflen| is less than the required length, or |buffer| is NULL, // |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_StructElement_GetID(FPDF_STRUCTELEMENT struct_element, void* buffer, unsigned long buflen); // Experimental API. // Function: FPDF_StructElement_GetLang // Get the case-insensitive IETF BCP 47 language code for an element. // Parameters: // struct_element - Handle to the struct element. // buffer - A buffer for output the lang string. May be NULL. // buflen - The length of the buffer, in bytes. May be 0. // Return value: // The number of bytes in the ID string, including the terminating NUL // character. The number of bytes is returned regardless of the // |buffer| and |buflen| parameters. // Comments: // Regardless of the platform, the |buffer| is always in UTF-16LE // encoding. The string is terminated by a UTF16 NUL character. If // |buflen| is less than the required length, or |buffer| is NULL, // |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_StructElement_GetLang(FPDF_STRUCTELEMENT struct_element, void* buffer, unsigned long buflen); // Experimental API. // Function: FPDF_StructElement_GetStringAttribute // Get a struct element attribute of type "name" or "string". // Parameters: // struct_element - Handle to the struct element. // attr_name - The name of the attribute to retrieve. // buffer - A buffer for output. May be NULL. // buflen - The length of the buffer, in bytes. May be 0. // Return value: // The number of bytes in the attribute value, including the // terminating NUL character. The number of bytes is returned // regardless of the |buffer| and |buflen| parameters. // Comments: // Regardless of the platform, the |buffer| is always in UTF-16LE // encoding. The string is terminated by a UTF16 NUL character. If // |buflen| is less than the required length, or |buffer| is NULL, // |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_StructElement_GetStringAttribute(FPDF_STRUCTELEMENT struct_element, FPDF_BYTESTRING attr_name, void* buffer, unsigned long buflen); // Function: FPDF_StructElement_GetMarkedContentID // Get the marked content ID for a given element. // Parameters: // struct_element - Handle to the struct element. // Return value: // The marked content ID of the element. If no ID exists, returns // -1. // Comments: // FPDF_StructElement_GetMarkedContentIdAtIndex() may be able to // extract more marked content IDs out of |struct_element|. This API // may be deprecated in the future. FPDF_EXPORT int FPDF_CALLCONV FPDF_StructElement_GetMarkedContentID(FPDF_STRUCTELEMENT struct_element); // Function: FPDF_StructElement_GetType // Get the type (/S) for a given element. // Parameters: // struct_element - Handle to the struct element. // buffer - A buffer for output. May be NULL. // buflen - The length of the buffer, in bytes. May be 0. // Return value: // The number of bytes in the type, including the terminating NUL // character. The number of bytes is returned regardless of the // |buffer| and |buflen| parameters. // Comments: // Regardless of the platform, the |buffer| is always in UTF-16LE // encoding. The string is terminated by a UTF16 NUL character. If // |buflen| is less than the required length, or |buffer| is NULL, // |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_StructElement_GetType(FPDF_STRUCTELEMENT struct_element, void* buffer, unsigned long buflen); // Experimental API. // Function: FPDF_StructElement_GetObjType // Get the object type (/Type) for a given element. // Parameters: // struct_element - Handle to the struct element. // buffer - A buffer for output. May be NULL. // buflen - The length of the buffer, in bytes. May be 0. // Return value: // The number of bytes in the object type, including the terminating // NUL character. The number of bytes is returned regardless of the // |buffer| and |buflen| parameters. // Comments: // Regardless of the platform, the |buffer| is always in UTF-16LE // encoding. The string is terminated by a UTF16 NUL character. If // |buflen| is less than the required length, or |buffer| is NULL, // |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_StructElement_GetObjType(FPDF_STRUCTELEMENT struct_element, void* buffer, unsigned long buflen); // Function: FPDF_StructElement_GetTitle // Get the title (/T) for a given element. // Parameters: // struct_element - Handle to the struct element. // buffer - A buffer for output. May be NULL. // buflen - The length of the buffer, in bytes. May be 0. // Return value: // The number of bytes in the title, including the terminating NUL // character. The number of bytes is returned regardless of the // |buffer| and |buflen| parameters. // Comments: // Regardless of the platform, the |buffer| is always in UTF-16LE // encoding. The string is terminated by a UTF16 NUL character. If // |buflen| is less than the required length, or |buffer| is NULL, // |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_StructElement_GetTitle(FPDF_STRUCTELEMENT struct_element, void* buffer, unsigned long buflen); // Function: FPDF_StructElement_CountChildren // Count the number of children for the structure element. // Parameters: // struct_element - Handle to the struct element. // Return value: // The number of children, or -1 on error. FPDF_EXPORT int FPDF_CALLCONV FPDF_StructElement_CountChildren(FPDF_STRUCTELEMENT struct_element); // Function: FPDF_StructElement_GetChildAtIndex // Get a child in the structure element. // Parameters: // struct_element - Handle to the struct element. // index - The index for the child, 0-based. // Return value: // The child at the n-th index or NULL on error. // Comments: // If the child exists but is not an element, then this function will // return NULL. This will also return NULL for out of bounds indices. // The |index| must be less than the FPDF_StructElement_CountChildren() // return value. FPDF_EXPORT FPDF_STRUCTELEMENT FPDF_CALLCONV FPDF_StructElement_GetChildAtIndex(FPDF_STRUCTELEMENT struct_element, int index); // Experimental API. // Function: FPDF_StructElement_GetChildMarkedContentID // Get the child's content id // Parameters: // struct_element - Handle to the struct element. // index - The index for the child, 0-based. // Return value: // The marked content ID of the child. If no ID exists, returns -1. // Comments: // If the child exists but is not a stream or object, then this // function will return -1. This will also return -1 for out of bounds // indices. Compared to FPDF_StructElement_GetMarkedContentIdAtIndex, // it is scoped to the current page. // The |index| must be less than the FPDF_StructElement_CountChildren() // return value. FPDF_EXPORT int FPDF_CALLCONV FPDF_StructElement_GetChildMarkedContentID(FPDF_STRUCTELEMENT struct_element, int index); // Experimental API. // Function: FPDF_StructElement_GetParent // Get the parent of the structure element. // Parameters: // struct_element - Handle to the struct element. // Return value: // The parent structure element or NULL on error. // Comments: // If structure element is StructTreeRoot, then this function will // return NULL. FPDF_EXPORT FPDF_STRUCTELEMENT FPDF_CALLCONV FPDF_StructElement_GetParent(FPDF_STRUCTELEMENT struct_element); // Function: FPDF_StructElement_GetAttributeCount // Count the number of attributes for the structure element. // Parameters: // struct_element - Handle to the struct element. // Return value: // The number of attributes, or -1 on error. FPDF_EXPORT int FPDF_CALLCONV FPDF_StructElement_GetAttributeCount(FPDF_STRUCTELEMENT struct_element); // Experimental API. // Function: FPDF_StructElement_GetAttributeAtIndex // Get an attribute object in the structure element. // Parameters: // struct_element - Handle to the struct element. // index - The index for the attribute object, 0-based. // Return value: // The attribute object at the n-th index or NULL on error. // Comments: // If the attribute object exists but is not a dict, then this // function will return NULL. This will also return NULL for out of // bounds indices. The caller does not own the handle. The handle // remains valid as long as |struct_element| remains valid. // The |index| must be less than the // FPDF_StructElement_GetAttributeCount() return value. FPDF_EXPORT FPDF_STRUCTELEMENT_ATTR FPDF_CALLCONV FPDF_StructElement_GetAttributeAtIndex(FPDF_STRUCTELEMENT struct_element, int index); // Experimental API. // Function: FPDF_StructElement_Attr_GetCount // Count the number of attributes in a structure element attribute map. // Parameters: // struct_attribute - Handle to the struct element attribute. // Return value: // The number of attributes, or -1 on error. FPDF_EXPORT int FPDF_CALLCONV FPDF_StructElement_Attr_GetCount(FPDF_STRUCTELEMENT_ATTR struct_attribute); // Experimental API. // Function: FPDF_StructElement_Attr_GetName // Get the name of an attribute in a structure element attribute map. // Parameters: // struct_attribute - Handle to the struct element attribute. // index - The index of attribute in the map. // buffer - A buffer for output. May be NULL. This is only // modified if |buflen| is longer than the length // of the key. Optional, pass null to just // retrieve the size of the buffer needed. // buflen - The length of the buffer. // out_buflen - A pointer to variable that will receive the // minimum buffer size to contain the key. Not // filled if FALSE is returned. // Return value: // TRUE if the operation was successful, FALSE otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_StructElement_Attr_GetName(FPDF_STRUCTELEMENT_ATTR struct_attribute, int index, void* buffer, unsigned long buflen, unsigned long* out_buflen); // Experimental API. // Function: FPDF_StructElement_Attr_GetValue // Get a handle to a value for an attribute in a structure element // attribute map. // Parameters: // struct_attribute - Handle to the struct element attribute. // name - The attribute name. // Return value: // Returns a handle to the value associated with the input, if any. // Returns NULL on failure. The caller does not own the handle. // The handle remains valid as long as |struct_attribute| remains // valid. FPDF_EXPORT FPDF_STRUCTELEMENT_ATTR_VALUE FPDF_CALLCONV FPDF_StructElement_Attr_GetValue(FPDF_STRUCTELEMENT_ATTR struct_attribute, FPDF_BYTESTRING name); // Experimental API. // Function: FPDF_StructElement_Attr_GetType // Get the type of an attribute in a structure element attribute map. // Parameters: // value - Handle to the value. // Return value: // Returns the type of the value, or FPDF_OBJECT_UNKNOWN in case of // failure. Note that this will never return FPDF_OBJECT_REFERENCE, as // references are always dereferenced. FPDF_EXPORT FPDF_OBJECT_TYPE FPDF_CALLCONV FPDF_StructElement_Attr_GetType(FPDF_STRUCTELEMENT_ATTR_VALUE value); // Experimental API. // Function: FPDF_StructElement_Attr_GetBooleanValue // Get the value of a boolean attribute in an attribute map as // FPDF_BOOL. FPDF_StructElement_Attr_GetType() should have returned // FPDF_OBJECT_BOOLEAN for this property. // Parameters: // value - Handle to the value. // out_value - A pointer to variable that will receive the value. Not // filled if false is returned. // Return value: // Returns TRUE if the attribute maps to a boolean value, FALSE // otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_StructElement_Attr_GetBooleanValue(FPDF_STRUCTELEMENT_ATTR_VALUE value, FPDF_BOOL* out_value); // Experimental API. // Function: FPDF_StructElement_Attr_GetNumberValue // Get the value of a number attribute in an attribute map as float. // FPDF_StructElement_Attr_GetType() should have returned // FPDF_OBJECT_NUMBER for this property. // Parameters: // value - Handle to the value. // out_value - A pointer to variable that will receive the value. Not // filled if false is returned. // Return value: // Returns TRUE if the attribute maps to a number value, FALSE // otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_StructElement_Attr_GetNumberValue(FPDF_STRUCTELEMENT_ATTR_VALUE value, float* out_value); // Experimental API. // Function: FPDF_StructElement_Attr_GetStringValue // Get the value of a string attribute in an attribute map as string. // FPDF_StructElement_Attr_GetType() should have returned // FPDF_OBJECT_STRING or FPDF_OBJECT_NAME for this property. // Parameters: // value - Handle to the value. // buffer - A buffer for holding the returned key in UTF-16LE. // This is only modified if |buflen| is longer than the // length of the key. Optional, pass null to just // retrieve the size of the buffer needed. // buflen - The length of the buffer. // out_buflen - A pointer to variable that will receive the minimum // buffer size to contain the key. Not filled if FALSE is // returned. // Return value: // Returns TRUE if the attribute maps to a string value, FALSE // otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_StructElement_Attr_GetStringValue(FPDF_STRUCTELEMENT_ATTR_VALUE value, void* buffer, unsigned long buflen, unsigned long* out_buflen); // Experimental API. // Function: FPDF_StructElement_Attr_GetBlobValue // Get the value of a blob attribute in an attribute map as string. // Parameters: // value - Handle to the value. // buffer - A buffer for holding the returned value. This is only // modified if |buflen| is at least as long as the length // of the value. Optional, pass null to just retrieve the // size of the buffer needed. // buflen - The length of the buffer. // out_buflen - A pointer to variable that will receive the minimum // buffer size to contain the key. Not filled if FALSE is // returned. // Return value: // Returns TRUE if the attribute maps to a string value, FALSE // otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_StructElement_Attr_GetBlobValue(FPDF_STRUCTELEMENT_ATTR_VALUE value, void* buffer, unsigned long buflen, unsigned long* out_buflen); // Experimental API. // Function: FPDF_StructElement_Attr_CountChildren // Count the number of children values in an attribute. // Parameters: // value - Handle to the value. // Return value: // The number of children, or -1 on error. FPDF_EXPORT int FPDF_CALLCONV FPDF_StructElement_Attr_CountChildren(FPDF_STRUCTELEMENT_ATTR_VALUE value); // Experimental API. // Function: FPDF_StructElement_Attr_GetChildAtIndex // Get a child from an attribute. // Parameters: // value - Handle to the value. // index - The index for the child, 0-based. // Return value: // The child at the n-th index or NULL on error. // Comments: // The |index| must be less than the // FPDF_StructElement_Attr_CountChildren() return value. FPDF_EXPORT FPDF_STRUCTELEMENT_ATTR_VALUE FPDF_CALLCONV FPDF_StructElement_Attr_GetChildAtIndex(FPDF_STRUCTELEMENT_ATTR_VALUE value, int index); // Experimental API. // Function: FPDF_StructElement_GetMarkedContentIdCount // Get the count of marked content ids for a given element. // Parameters: // struct_element - Handle to the struct element. // Return value: // The count of marked content ids or -1 if none exists. FPDF_EXPORT int FPDF_CALLCONV FPDF_StructElement_GetMarkedContentIdCount(FPDF_STRUCTELEMENT struct_element); // Experimental API. // Function: FPDF_StructElement_GetMarkedContentIdAtIndex // Get the marked content id at a given index for a given element. // Parameters: // struct_element - Handle to the struct element. // index - The index of the marked content id, 0-based. // Return value: // The marked content ID of the element. If no ID exists, returns // -1. // Comments: // The |index| must be less than the // FPDF_StructElement_GetMarkedContentIdCount() return value. // This will likely supersede FPDF_StructElement_GetMarkedContentID(). FPDF_EXPORT int FPDF_CALLCONV FPDF_StructElement_GetMarkedContentIdAtIndex(FPDF_STRUCTELEMENT struct_element, int index); #ifdef __cplusplus } // extern "C" #endif #endif // PUBLIC_FPDF_STRUCTTREE_H_ ================================================ FILE: external/pdfium/windows-x64/include/fpdf_sysfontinfo.h ================================================ // Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #ifndef PUBLIC_FPDF_SYSFONTINFO_H_ #define PUBLIC_FPDF_SYSFONTINFO_H_ #include // clang-format off // NOLINTNEXTLINE(build/include) #include "fpdfview.h" // Character sets for the font #define FXFONT_ANSI_CHARSET 0 #define FXFONT_DEFAULT_CHARSET 1 #define FXFONT_SYMBOL_CHARSET 2 #define FXFONT_SHIFTJIS_CHARSET 128 #define FXFONT_HANGEUL_CHARSET 129 #define FXFONT_GB2312_CHARSET 134 #define FXFONT_CHINESEBIG5_CHARSET 136 #define FXFONT_GREEK_CHARSET 161 #define FXFONT_VIETNAMESE_CHARSET 163 #define FXFONT_HEBREW_CHARSET 177 #define FXFONT_ARABIC_CHARSET 178 #define FXFONT_CYRILLIC_CHARSET 204 #define FXFONT_THAI_CHARSET 222 #define FXFONT_EASTERNEUROPEAN_CHARSET 238 // Font pitch and family flags #define FXFONT_FF_FIXEDPITCH (1 << 0) #define FXFONT_FF_ROMAN (1 << 4) #define FXFONT_FF_SCRIPT (4 << 4) // Typical weight values #define FXFONT_FW_NORMAL 400 #define FXFONT_FW_BOLD 700 // Exported Functions #ifdef __cplusplus extern "C" { #endif // Interface: FPDF_SYSFONTINFO // Interface for getting system font information and font mapping typedef struct _FPDF_SYSFONTINFO { // Version number of the interface. Currently must be 1 or 2. // Version 1: Traditional behavior - calls EnumFonts during initialization. // Version 2: Per-request behavior - skips EnumFonts, relies on MapFont. // Experimental: Subject to change based on feedback. int version; // Method: Release // Give implementation a chance to release any data after the // interface is no longer used. // Interface Version: // 1 and 2 // Implementation Required: // No // Parameters: // pThis - Pointer to the interface structure itself // Return Value: // None // Comments: // Called by PDFium during the final cleanup process. void (*Release)(struct _FPDF_SYSFONTINFO* pThis); // Method: EnumFonts // Enumerate all fonts installed on the system // Interface Version: // 1 // Implementation Required: // No // Parameters: // pThis - Pointer to the interface structure itself // pMapper - An opaque pointer to internal font mapper, used // when calling FPDF_AddInstalledFont(). // Return Value: // None // Comments: // Implementations should call FPDF_AddInstalledFont() function for // each font found. Only TrueType/OpenType and Type1 fonts are // accepted by PDFium. // NOTE: This method will not be called when version is set to 2. // Version 2 relies entirely on MapFont() for per-request matching. void (*EnumFonts)(struct _FPDF_SYSFONTINFO* pThis, void* pMapper); // Method: MapFont // Use the system font mapper to get a font handle from requested // parameters. // Interface Version: // 1 and 2 // Implementation Required: // Required if GetFont method is not implemented. // Parameters: // pThis - Pointer to the interface structure itself // weight - Weight of the requested font. 400 is normal and // 700 is bold. // bItalic - Italic option of the requested font, TRUE or // FALSE. // charset - Character set identifier for the requested font. // See above defined constants. // pitch_family - A combination of flags. See above defined // constants. // face - Typeface name. Currently use system local encoding // only. // bExact - Obsolete: this parameter is now ignored. // Return Value: // An opaque pointer for font handle, or NULL if system mapping is // not supported. // Comments: // If the system supports native font mapper (like Windows), // implementation can implement this method to get a font handle. // Otherwise, PDFium will do the mapping and then call GetFont // method. Only TrueType/OpenType and Type1 fonts are accepted // by PDFium. void* (*MapFont)(struct _FPDF_SYSFONTINFO* pThis, int weight, FPDF_BOOL bItalic, int charset, int pitch_family, const char* face, FPDF_BOOL* bExact); // Method: GetFont // Get a handle to a particular font by its internal ID // Interface Version: // 1 and 2 // Implementation Required: // Required if MapFont method is not implemented. // Return Value: // An opaque pointer for font handle. // Parameters: // pThis - Pointer to the interface structure itself // face - Typeface name in system local encoding. // Comments: // If the system mapping not supported, PDFium will do the font // mapping and use this method to get a font handle. void* (*GetFont)(struct _FPDF_SYSFONTINFO* pThis, const char* face); // Method: GetFontData // Get font data from a font // Interface Version: // 1 and 2 // Implementation Required: // Yes // Parameters: // pThis - Pointer to the interface structure itself // hFont - Font handle returned by MapFont or GetFont method // table - TrueType/OpenType table identifier (refer to // TrueType specification), or 0 for the whole file. // buffer - The buffer receiving the font data. Can be NULL if // not provided. // buf_size - Buffer size, can be zero if not provided. // Return Value: // Number of bytes needed, if buffer not provided or not large // enough, or number of bytes written into buffer otherwise. // Comments: // Can read either the full font file, or a particular // TrueType/OpenType table. unsigned long (*GetFontData)(struct _FPDF_SYSFONTINFO* pThis, void* hFont, unsigned int table, unsigned char* buffer, unsigned long buf_size); // Method: GetFaceName // Get face name from a font handle // Interface Version: // 1 and 2 // Implementation Required: // No // Parameters: // pThis - Pointer to the interface structure itself // hFont - Font handle returned by MapFont or GetFont method // buffer - The buffer receiving the face name. Can be NULL if // not provided // buf_size - Buffer size, can be zero if not provided // Return Value: // Number of bytes needed, if buffer not provided or not large // enough, or number of bytes written into buffer otherwise. unsigned long (*GetFaceName)(struct _FPDF_SYSFONTINFO* pThis, void* hFont, char* buffer, unsigned long buf_size); // Method: GetFontCharset // Get character set information for a font handle // Interface Version: // 1 and 2 // Implementation Required: // No // Parameters: // pThis - Pointer to the interface structure itself // hFont - Font handle returned by MapFont or GetFont method // Return Value: // Character set identifier. See defined constants above. int (*GetFontCharset)(struct _FPDF_SYSFONTINFO* pThis, void* hFont); // Method: DeleteFont // Delete a font handle // Interface Version: // 1 and 2 // Implementation Required: // Yes // Parameters: // pThis - Pointer to the interface structure itself // hFont - Font handle returned by MapFont or GetFont method // Return Value: // None void (*DeleteFont)(struct _FPDF_SYSFONTINFO* pThis, void* hFont); } FPDF_SYSFONTINFO; // Struct: FPDF_CharsetFontMap // Provides the name of a font to use for a given charset value. typedef struct FPDF_CharsetFontMap_ { int charset; // Character Set Enum value, see FXFONT_*_CHARSET above. const char* fontname; // Name of default font to use with that charset. } FPDF_CharsetFontMap; // Function: FPDF_GetDefaultTTFMap // Returns a pointer to the default character set to TT Font name map. The // map is an array of FPDF_CharsetFontMap structs, with its end indicated // by a { -1, NULL } entry. // Parameters: // None. // Return Value: // Pointer to the Charset Font Map. // Note: // Once FPDF_GetDefaultTTFMapCount() and FPDF_GetDefaultTTFMapEntry() are no // longer experimental, this API will be marked as deprecated. // See https://crbug.com/348468114 FPDF_EXPORT const FPDF_CharsetFontMap* FPDF_CALLCONV FPDF_GetDefaultTTFMap(); // Experimental API. // // Function: FPDF_GetDefaultTTFMapCount // Returns the number of entries in the default character set to TT Font name // map. // Parameters: // None. // Return Value: // The number of entries in the map. FPDF_EXPORT size_t FPDF_CALLCONV FPDF_GetDefaultTTFMapCount(); // Experimental API. // // Function: FPDF_GetDefaultTTFMapEntry // Returns an entry in the default character set to TT Font name map. // Parameters: // index - The index to the entry in the map to retrieve. // Return Value: // A pointer to the entry, if it is in the map, or NULL if the index is out // of bounds. FPDF_EXPORT const FPDF_CharsetFontMap* FPDF_CALLCONV FPDF_GetDefaultTTFMapEntry(size_t index); // Function: FPDF_AddInstalledFont // Add a system font to the list in PDFium. // Comments: // This function is only called during the system font list building // process. // Parameters: // mapper - Opaque pointer to Foxit font mapper // face - The font face name // charset - Font character set. See above defined constants. // Return Value: // None. FPDF_EXPORT void FPDF_CALLCONV FPDF_AddInstalledFont(void* mapper, const char* face, int charset); // Function: FPDF_SetSystemFontInfo // Set the system font info interface into PDFium // Parameters: // font_info - Pointer to a FPDF_SYSFONTINFO structure // Return Value: // None // Comments: // Platform support implementation should implement required methods of // FFDF_SYSFONTINFO interface, then call this function during PDFium // initialization process. // // Call this with NULL to tell PDFium to stop using a previously set // |FPDF_SYSFONTINFO|. FPDF_EXPORT void FPDF_CALLCONV FPDF_SetSystemFontInfo(FPDF_SYSFONTINFO* font_info); // Function: FPDF_GetDefaultSystemFontInfo // Get default system font info interface for current platform // Parameters: // None // Return Value: // Pointer to a FPDF_SYSFONTINFO structure describing the default // interface, or NULL if the platform doesn't have a default interface. // Application should call FPDF_FreeDefaultSystemFontInfo to free the // returned pointer. // Comments: // For some platforms, PDFium implements a default version of system // font info interface. The default implementation can be passed to // FPDF_SetSystemFontInfo(). FPDF_EXPORT FPDF_SYSFONTINFO* FPDF_CALLCONV FPDF_GetDefaultSystemFontInfo(); // Function: FPDF_FreeDefaultSystemFontInfo // Free a default system font info interface // Parameters: // font_info - Pointer to a FPDF_SYSFONTINFO structure // Return Value: // None // Comments: // This function should be called on the output from // FPDF_GetDefaultSystemFontInfo() once it is no longer needed. FPDF_EXPORT void FPDF_CALLCONV FPDF_FreeDefaultSystemFontInfo(FPDF_SYSFONTINFO* font_info); #ifdef __cplusplus } #endif #endif // PUBLIC_FPDF_SYSFONTINFO_H_ ================================================ FILE: external/pdfium/windows-x64/include/fpdf_text.h ================================================ // Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #ifndef PUBLIC_FPDF_TEXT_H_ #define PUBLIC_FPDF_TEXT_H_ // clang-format off // NOLINTNEXTLINE(build/include) #include "fpdfview.h" // Exported Functions #ifdef __cplusplus extern "C" { #endif // Function: FPDFText_LoadPage // Prepare information about all characters in a page. // Parameters: // page - Handle to the page. Returned by FPDF_LoadPage function // (in FPDFVIEW module). // Return value: // A handle to the text page information structure. // NULL if something goes wrong. // Comments: // Application must call FPDFText_ClosePage to release the text page // information. // FPDF_EXPORT FPDF_TEXTPAGE FPDF_CALLCONV FPDFText_LoadPage(FPDF_PAGE page); // Function: FPDFText_ClosePage // Release all resources allocated for a text page information // structure. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // Return Value: // None. // FPDF_EXPORT void FPDF_CALLCONV FPDFText_ClosePage(FPDF_TEXTPAGE text_page); // Function: FPDFText_CountChars // Get number of characters in a page. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // Return value: // Number of characters in the page. Return -1 for error. // Generated characters, like additional space characters, new line // characters, are also counted. // Comments: // Characters in a page form a "stream", inside the stream, each // character has an index. // We will use the index parameters in many of FPDFTEXT functions. The // first character in the page // has an index value of zero. // FPDF_EXPORT int FPDF_CALLCONV FPDFText_CountChars(FPDF_TEXTPAGE text_page); // Function: FPDFText_GetUnicode // Get Unicode of a character in a page. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // index - Zero-based index of the character. // Return value: // The Unicode of the particular character. // If a character is not encoded in Unicode and Foxit engine can't // convert to Unicode, // the return value will be zero. // FPDF_EXPORT unsigned int FPDF_CALLCONV FPDFText_GetUnicode(FPDF_TEXTPAGE text_page, int index); // Experimental API. // Function: FPDFText_GetTextObject // Get the FPDF_PAGEOBJECT associated with a given character. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // index - Zero-based index of the character. // Return value: // The associated text object for the character at |index|, or NULL on // error. The returned text object, if non-null, is of type // |FPDF_PAGEOBJ_TEXT|. The caller does not own the returned object. // FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV FPDFText_GetTextObject(FPDF_TEXTPAGE text_page, int index); // Experimental API. // Function: FPDFText_IsGenerated // Get if a character in a page is generated by PDFium. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // index - Zero-based index of the character. // Return value: // 1 if the character is generated by PDFium. // 0 if the character is not generated by PDFium. // -1 if there was an error. // FPDF_EXPORT int FPDF_CALLCONV FPDFText_IsGenerated(FPDF_TEXTPAGE text_page, int index); // Experimental API. // Function: FPDFText_IsHyphen // Get if a character in a page is a hyphen. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // index - Zero-based index of the character. // Return value: // 1 if the character is a hyphen. // 0 if the character is not a hyphen. // -1 if there was an error. // FPDF_EXPORT int FPDF_CALLCONV FPDFText_IsHyphen(FPDF_TEXTPAGE text_page, int index); // Experimental API. // Function: FPDFText_HasUnicodeMapError // Get if a character in a page has an invalid unicode mapping. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // index - Zero-based index of the character. // Return value: // 1 if the character has an invalid unicode mapping. // 0 if the character has no known unicode mapping issues. // -1 if there was an error. // FPDF_EXPORT int FPDF_CALLCONV FPDFText_HasUnicodeMapError(FPDF_TEXTPAGE text_page, int index); // Function: FPDFText_GetFontSize // Get the font size of a particular character. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // index - Zero-based index of the character. // Return value: // The font size of the particular character, measured in points (about // 1/72 inch). This is the typographic size of the font (so called // "em size"). // FPDF_EXPORT double FPDF_CALLCONV FPDFText_GetFontSize(FPDF_TEXTPAGE text_page, int index); // Experimental API. // Function: FPDFText_GetFontInfo // Get the font name and flags of a particular character. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // index - Zero-based index of the character. // buffer - A buffer receiving the font name. // buflen - The length of |buffer| in bytes. // flags - Optional pointer to an int receiving the font flags. // These flags should be interpreted per PDF spec 1.7 // Section 5.7.1 Font Descriptor Flags. // Return value: // On success, return the length of the font name, including the // trailing NUL character, in bytes. If this length is less than or // equal to |length|, |buffer| is set to the font name, |flags| is // set to the font flags. |buffer| is in UTF-8 encoding. Return 0 on // failure. // FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFText_GetFontInfo(FPDF_TEXTPAGE text_page, int index, void* buffer, unsigned long buflen, int* flags); // Experimental API. // Function: FPDFText_GetFontWeight // Get the font weight of a particular character. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // index - Zero-based index of the character. // Return value: // On success, return the font weight of the particular character. If // |text_page| is invalid, if |index| is out of bounds, or if the // character's text object is undefined, return -1. // FPDF_EXPORT int FPDF_CALLCONV FPDFText_GetFontWeight(FPDF_TEXTPAGE text_page, int index); // Experimental API. // Function: FPDFText_GetFillColor // Get the fill color of a particular character. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // index - Zero-based index of the character. // R - Pointer to an unsigned int number receiving the // red value of the fill color. // G - Pointer to an unsigned int number receiving the // green value of the fill color. // B - Pointer to an unsigned int number receiving the // blue value of the fill color. // A - Pointer to an unsigned int number receiving the // alpha value of the fill color. // Return value: // Whether the call succeeded. If false, |R|, |G|, |B| and |A| are // unchanged. // FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFText_GetFillColor(FPDF_TEXTPAGE text_page, int index, unsigned int* R, unsigned int* G, unsigned int* B, unsigned int* A); // Experimental API. // Function: FPDFText_GetStrokeColor // Get the stroke color of a particular character. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // index - Zero-based index of the character. // R - Pointer to an unsigned int number receiving the // red value of the stroke color. // G - Pointer to an unsigned int number receiving the // green value of the stroke color. // B - Pointer to an unsigned int number receiving the // blue value of the stroke color. // A - Pointer to an unsigned int number receiving the // alpha value of the stroke color. // Return value: // Whether the call succeeded. If false, |R|, |G|, |B| and |A| are // unchanged. // FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFText_GetStrokeColor(FPDF_TEXTPAGE text_page, int index, unsigned int* R, unsigned int* G, unsigned int* B, unsigned int* A); // Experimental API. // Function: FPDFText_GetCharAngle // Get character rotation angle. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // index - Zero-based index of the character. // Return Value: // On success, return the angle value in radian. Value will always be // greater or equal to 0. If |text_page| is invalid, or if |index| is // out of bounds, then return -1. // FPDF_EXPORT float FPDF_CALLCONV FPDFText_GetCharAngle(FPDF_TEXTPAGE text_page, int index); // Function: FPDFText_GetCharBox // Get bounding box of a particular character. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // index - Zero-based index of the character. // left - Pointer to a double number receiving left position // of the character box. // right - Pointer to a double number receiving right position // of the character box. // bottom - Pointer to a double number receiving bottom position // of the character box. // top - Pointer to a double number receiving top position of // the character box. // Return Value: // On success, return TRUE and fill in |left|, |right|, |bottom|, and // |top|. If |text_page| is invalid, or if |index| is out of bounds, // then return FALSE, and the out parameters remain unmodified. // Comments: // All positions are measured in PDF "user space". // FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFText_GetCharBox(FPDF_TEXTPAGE text_page, int index, double* left, double* right, double* bottom, double* top); // Experimental API. // Function: FPDFText_GetLooseCharBox // Get a "loose" bounding box of a particular character, i.e., covering // the entire glyph bounds, without taking the actual glyph shape into // account. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // index - Zero-based index of the character. // rect - Pointer to a FS_RECTF receiving the character box. // Return Value: // On success, return TRUE and fill in |rect|. If |text_page| is // invalid, or if |index| is out of bounds, then return FALSE, and the // |rect| out parameter remains unmodified. // Comments: // All positions are measured in PDF "user space". // FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFText_GetLooseCharBox(FPDF_TEXTPAGE text_page, int index, FS_RECTF* rect); // Experimental API. // Function: FPDFText_GetMatrix // Get the effective transformation matrix for a particular character. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage(). // index - Zero-based index of the character. // matrix - Pointer to a FS_MATRIX receiving the transformation // matrix. // Return Value: // On success, return TRUE and fill in |matrix|. If |text_page| is // invalid, or if |index| is out of bounds, or if |matrix| is NULL, // then return FALSE, and |matrix| remains unmodified. // FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFText_GetMatrix(FPDF_TEXTPAGE text_page, int index, FS_MATRIX* matrix); // Function: FPDFText_GetCharOrigin // Get origin of a particular character. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // index - Zero-based index of the character. // x - Pointer to a double number receiving x coordinate of // the character origin. // y - Pointer to a double number receiving y coordinate of // the character origin. // Return Value: // Whether the call succeeded. If false, x and y are unchanged. // Comments: // All positions are measured in PDF "user space". // FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFText_GetCharOrigin(FPDF_TEXTPAGE text_page, int index, double* x, double* y); // Function: FPDFText_GetCharIndexAtPos // Get the index of a character at or nearby a certain position on the // page. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // x - X position in PDF "user space". // y - Y position in PDF "user space". // xTolerance - An x-axis tolerance value for character hit // detection, in point units. // yTolerance - A y-axis tolerance value for character hit // detection, in point units. // Return Value: // The zero-based index of the character at, or nearby the point (x,y). // If there is no character at or nearby the point, return value will // be -1. If an error occurs, -3 will be returned. // FPDF_EXPORT int FPDF_CALLCONV FPDFText_GetCharIndexAtPos(FPDF_TEXTPAGE text_page, double x, double y, double xTolerance, double yTolerance); // Function: FPDFText_GetText // Extract unicode text string from the page. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // start_index - Index for the start characters. // count - Number of UCS-2 values to be extracted. // result - A buffer (allocated by application) receiving the // extracted UCS-2 values. The buffer must be able to // hold `count` UCS-2 values plus a terminator. // Return Value: // Number of characters written into the result buffer, including the // trailing terminator. // Comments: // This function ignores characters without UCS-2 representations. // It considers all characters on the page, even those that are not // visible when the page has a cropbox. To filter out the characters // outside of the cropbox, use FPDF_GetPageBoundingBox() and // FPDFText_GetCharBox(). // FPDF_EXPORT int FPDF_CALLCONV FPDFText_GetText(FPDF_TEXTPAGE text_page, int start_index, int count, unsigned short* result); // Function: FPDFText_CountRects // Counts number of rectangular areas occupied by a segment of text, // and caches the result for subsequent FPDFText_GetRect() calls. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // start_index - Index for the start character. // count - Number of characters, or -1 for all remaining. // Return value: // Number of rectangles, 0 if text_page is null, or -1 on bad // start_index. // Comments: // This function, along with FPDFText_GetRect can be used by // applications to detect the position on the page for a text segment, // so proper areas can be highlighted. The FPDFText_* functions will // automatically merge small character boxes into bigger one if those // characters are on the same line and use same font settings. // FPDF_EXPORT int FPDF_CALLCONV FPDFText_CountRects(FPDF_TEXTPAGE text_page, int start_index, int count); // Function: FPDFText_GetRect // Get a rectangular area from the result generated by // FPDFText_CountRects. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // rect_index - Zero-based index for the rectangle. // left - Pointer to a double value receiving the rectangle // left boundary. // top - Pointer to a double value receiving the rectangle // top boundary. // right - Pointer to a double value receiving the rectangle // right boundary. // bottom - Pointer to a double value receiving the rectangle // bottom boundary. // Return Value: // On success, return TRUE and fill in |left|, |top|, |right|, and // |bottom|. If |text_page| is invalid then return FALSE, and the out // parameters remain unmodified. If |text_page| is valid but // |rect_index| is out of bounds, then return FALSE and set the out // parameters to 0. // FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFText_GetRect(FPDF_TEXTPAGE text_page, int rect_index, double* left, double* top, double* right, double* bottom); // Function: FPDFText_GetBoundedText // Extract unicode text within a rectangular boundary on the page. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // left - Left boundary. // top - Top boundary. // right - Right boundary. // bottom - Bottom boundary. // buffer - Caller-allocated buffer to receive UTF-16 values. // buflen - Number of UTF-16 values (not bytes) that `buffer` // is capable of holding. // Return Value: // If buffer is NULL or buflen is zero, return number of UTF-16 // values (not bytes) of text present within the rectangle, excluding // a terminating NUL. Generally you should pass a buffer at least one // larger than this if you want a terminating NUL, which will be // provided if space is available. Otherwise, return number of UTF-16 // values copied into the buffer, including the terminating NUL when // space for it is available. // Comment: // If the buffer is too small, as much text as will fit is copied into // it. May return a split surrogate in that case. // FPDF_EXPORT int FPDF_CALLCONV FPDFText_GetBoundedText(FPDF_TEXTPAGE text_page, double left, double top, double right, double bottom, unsigned short* buffer, int buflen); // Flags used by FPDFText_FindStart function. // // If not set, it will not match case by default. #define FPDF_MATCHCASE 0x00000001 // If not set, it will not match the whole word by default. #define FPDF_MATCHWHOLEWORD 0x00000002 // If not set, it will skip past the current match to look for the next match. #define FPDF_CONSECUTIVE 0x00000004 // Function: FPDFText_FindStart // Start a search. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // findwhat - A unicode match pattern. // flags - Option flags. // start_index - Start from this character. -1 for end of the page. // Return Value: // A handle for the search context. FPDFText_FindClose must be called // to release this handle. // FPDF_EXPORT FPDF_SCHHANDLE FPDF_CALLCONV FPDFText_FindStart(FPDF_TEXTPAGE text_page, FPDF_WIDESTRING findwhat, unsigned long flags, int start_index); // Function: FPDFText_FindNext // Search in the direction from page start to end. // Parameters: // handle - A search context handle returned by // FPDFText_FindStart. // Return Value: // Whether a match is found. // FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFText_FindNext(FPDF_SCHHANDLE handle); // Function: FPDFText_FindPrev // Search in the direction from page end to start. // Parameters: // handle - A search context handle returned by // FPDFText_FindStart. // Return Value: // Whether a match is found. // FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFText_FindPrev(FPDF_SCHHANDLE handle); // Function: FPDFText_GetSchResultIndex // Get the starting character index of the search result. // Parameters: // handle - A search context handle returned by // FPDFText_FindStart. // Return Value: // Index for the starting character. // FPDF_EXPORT int FPDF_CALLCONV FPDFText_GetSchResultIndex(FPDF_SCHHANDLE handle); // Function: FPDFText_GetSchCount // Get the number of matched characters in the search result. // Parameters: // handle - A search context handle returned by // FPDFText_FindStart. // Return Value: // Number of matched characters. // FPDF_EXPORT int FPDF_CALLCONV FPDFText_GetSchCount(FPDF_SCHHANDLE handle); // Function: FPDFText_FindClose // Release a search context. // Parameters: // handle - A search context handle returned by // FPDFText_FindStart. // Return Value: // None. // FPDF_EXPORT void FPDF_CALLCONV FPDFText_FindClose(FPDF_SCHHANDLE handle); // Function: FPDFLink_LoadWebLinks // Prepare information about weblinks in a page. // Parameters: // text_page - Handle to a text page information structure. // Returned by FPDFText_LoadPage function. // Return Value: // A handle to the page's links information structure, or // NULL if something goes wrong. // Comments: // Weblinks are those links implicitly embedded in PDF pages. PDF also // has a type of annotation called "link" (FPDFTEXT doesn't deal with // that kind of link). FPDFTEXT weblink feature is useful for // automatically detecting links in the page contents. For example, // things like "https://www.example.com" will be detected, so // applications can allow user to click on those characters to activate // the link, even the PDF doesn't come with link annotations. // // FPDFLink_CloseWebLinks must be called to release resources. // FPDF_EXPORT FPDF_PAGELINK FPDF_CALLCONV FPDFLink_LoadWebLinks(FPDF_TEXTPAGE text_page); // Function: FPDFLink_CountWebLinks // Count number of detected web links. // Parameters: // link_page - Handle returned by FPDFLink_LoadWebLinks. // Return Value: // Number of detected web links. // FPDF_EXPORT int FPDF_CALLCONV FPDFLink_CountWebLinks(FPDF_PAGELINK link_page); // Function: FPDFLink_GetURL // Fetch the URL information for a detected web link. // Parameters: // link_page - Handle returned by FPDFLink_LoadWebLinks. // link_index - Zero-based index for the link. // buffer - A unicode buffer for the result. // buflen - Number of 16-bit code units (not bytes) for the // buffer, including an additional terminator. // Return Value: // If |buffer| is NULL or |buflen| is zero, return the number of 16-bit // code units (not bytes) needed to buffer the result (an additional // terminator is included in this count). // Otherwise, copy the result into |buffer|, truncating at |buflen| if // the result is too large to fit, and return the number of 16-bit code // units actually copied into the buffer (the additional terminator is // also included in this count). // If |link_index| does not correspond to a valid link, then the result // is an empty string. // FPDF_EXPORT int FPDF_CALLCONV FPDFLink_GetURL(FPDF_PAGELINK link_page, int link_index, unsigned short* buffer, int buflen); // Function: FPDFLink_CountRects // Count number of rectangular areas for the link. // Parameters: // link_page - Handle returned by FPDFLink_LoadWebLinks. // link_index - Zero-based index for the link. // Return Value: // Number of rectangular areas for the link. If |link_index| does // not correspond to a valid link, then 0 is returned. // FPDF_EXPORT int FPDF_CALLCONV FPDFLink_CountRects(FPDF_PAGELINK link_page, int link_index); // Function: FPDFLink_GetRect // Fetch the boundaries of a rectangle for a link. // Parameters: // link_page - Handle returned by FPDFLink_LoadWebLinks. // link_index - Zero-based index for the link. // rect_index - Zero-based index for a rectangle. // left - Pointer to a double value receiving the rectangle // left boundary. // top - Pointer to a double value receiving the rectangle // top boundary. // right - Pointer to a double value receiving the rectangle // right boundary. // bottom - Pointer to a double value receiving the rectangle // bottom boundary. // Return Value: // On success, return TRUE and fill in |left|, |top|, |right|, and // |bottom|. If |link_page| is invalid or if |link_index| does not // correspond to a valid link, then return FALSE, and the out // parameters remain unmodified. // FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFLink_GetRect(FPDF_PAGELINK link_page, int link_index, int rect_index, double* left, double* top, double* right, double* bottom); // Experimental API. // Function: FPDFLink_GetTextRange // Fetch the start char index and char count for a link. // Parameters: // link_page - Handle returned by FPDFLink_LoadWebLinks. // link_index - Zero-based index for the link. // start_char_index - pointer to int receiving the start char index // char_count - pointer to int receiving the char count // Return Value: // On success, return TRUE and fill in |start_char_index| and // |char_count|. if |link_page| is invalid or if |link_index| does // not correspond to a valid link, then return FALSE and the out // parameters remain unmodified. // FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFLink_GetTextRange(FPDF_PAGELINK link_page, int link_index, int* start_char_index, int* char_count); // Function: FPDFLink_CloseWebLinks // Release resources used by weblink feature. // Parameters: // link_page - Handle returned by FPDFLink_LoadWebLinks. // Return Value: // None. // FPDF_EXPORT void FPDF_CALLCONV FPDFLink_CloseWebLinks(FPDF_PAGELINK link_page); #ifdef __cplusplus } #endif #endif // PUBLIC_FPDF_TEXT_H_ ================================================ FILE: external/pdfium/windows-x64/include/fpdf_thumbnail.h ================================================ // Copyright 2019 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef PUBLIC_FPDF_THUMBNAIL_H_ #define PUBLIC_FPDF_THUMBNAIL_H_ #include // NOLINTNEXTLINE(build/include) #include "fpdfview.h" #ifdef __cplusplus extern "C" { #endif // Experimental API. // Gets the decoded data from the thumbnail of |page| if it exists. // This only modifies |buffer| if |buflen| less than or equal to the // size of the decoded data. Returns the size of the decoded // data or 0 if thumbnail DNE. Optional, pass null to just retrieve // the size of the buffer needed. // // page - handle to a page. // buffer - buffer for holding the decoded image data. // buflen - length of the buffer in bytes. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFPage_GetDecodedThumbnailData(FPDF_PAGE page, void* buffer, unsigned long buflen); // Experimental API. // Gets the raw data from the thumbnail of |page| if it exists. // This only modifies |buffer| if |buflen| is less than or equal to // the size of the raw data. Returns the size of the raw data or 0 // if thumbnail DNE. Optional, pass null to just retrieve the size // of the buffer needed. // // page - handle to a page. // buffer - buffer for holding the raw image data. // buflen - length of the buffer in bytes. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFPage_GetRawThumbnailData(FPDF_PAGE page, void* buffer, unsigned long buflen); // Experimental API. // Returns the thumbnail of |page| as a FPDF_BITMAP. Returns a nullptr // if unable to access the thumbnail's stream. // // page - handle to a page. FPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV FPDFPage_GetThumbnailAsBitmap(FPDF_PAGE page); #ifdef __cplusplus } #endif #endif // PUBLIC_FPDF_THUMBNAIL_H_ ================================================ FILE: external/pdfium/windows-x64/include/fpdf_transformpage.h ================================================ // Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #ifndef PUBLIC_FPDF_TRANSFORMPAGE_H_ #define PUBLIC_FPDF_TRANSFORMPAGE_H_ // NOLINTNEXTLINE(build/include) #include "fpdfview.h" #ifdef __cplusplus extern "C" { #endif // Set "MediaBox" entry to the page dictionary. // // page - Handle to a page. // left - The left of the rectangle. // bottom - The bottom of the rectangle. // right - The right of the rectangle. // top - The top of the rectangle. FPDF_EXPORT void FPDF_CALLCONV FPDFPage_SetMediaBox(FPDF_PAGE page, float left, float bottom, float right, float top); // Set "CropBox" entry to the page dictionary. // // page - Handle to a page. // left - The left of the rectangle. // bottom - The bottom of the rectangle. // right - The right of the rectangle. // top - The top of the rectangle. FPDF_EXPORT void FPDF_CALLCONV FPDFPage_SetCropBox(FPDF_PAGE page, float left, float bottom, float right, float top); // Set "BleedBox" entry to the page dictionary. // // page - Handle to a page. // left - The left of the rectangle. // bottom - The bottom of the rectangle. // right - The right of the rectangle. // top - The top of the rectangle. FPDF_EXPORT void FPDF_CALLCONV FPDFPage_SetBleedBox(FPDF_PAGE page, float left, float bottom, float right, float top); // Set "TrimBox" entry to the page dictionary. // // page - Handle to a page. // left - The left of the rectangle. // bottom - The bottom of the rectangle. // right - The right of the rectangle. // top - The top of the rectangle. FPDF_EXPORT void FPDF_CALLCONV FPDFPage_SetTrimBox(FPDF_PAGE page, float left, float bottom, float right, float top); // Set "ArtBox" entry to the page dictionary. // // page - Handle to a page. // left - The left of the rectangle. // bottom - The bottom of the rectangle. // right - The right of the rectangle. // top - The top of the rectangle. FPDF_EXPORT void FPDF_CALLCONV FPDFPage_SetArtBox(FPDF_PAGE page, float left, float bottom, float right, float top); // Get "MediaBox" entry from the page dictionary. // // page - Handle to a page. // left - Pointer to a float value receiving the left of the rectangle. // bottom - Pointer to a float value receiving the bottom of the rectangle. // right - Pointer to a float value receiving the right of the rectangle. // top - Pointer to a float value receiving the top of the rectangle. // // On success, return true and write to the out parameters. Otherwise return // false and leave the out parameters unmodified. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_GetMediaBox(FPDF_PAGE page, float* left, float* bottom, float* right, float* top); // Get "CropBox" entry from the page dictionary. // // page - Handle to a page. // left - Pointer to a float value receiving the left of the rectangle. // bottom - Pointer to a float value receiving the bottom of the rectangle. // right - Pointer to a float value receiving the right of the rectangle. // top - Pointer to a float value receiving the top of the rectangle. // // On success, return true and write to the out parameters. Otherwise return // false and leave the out parameters unmodified. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_GetCropBox(FPDF_PAGE page, float* left, float* bottom, float* right, float* top); // Get "BleedBox" entry from the page dictionary. // // page - Handle to a page. // left - Pointer to a float value receiving the left of the rectangle. // bottom - Pointer to a float value receiving the bottom of the rectangle. // right - Pointer to a float value receiving the right of the rectangle. // top - Pointer to a float value receiving the top of the rectangle. // // On success, return true and write to the out parameters. Otherwise return // false and leave the out parameters unmodified. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_GetBleedBox(FPDF_PAGE page, float* left, float* bottom, float* right, float* top); // Get "TrimBox" entry from the page dictionary. // // page - Handle to a page. // left - Pointer to a float value receiving the left of the rectangle. // bottom - Pointer to a float value receiving the bottom of the rectangle. // right - Pointer to a float value receiving the right of the rectangle. // top - Pointer to a float value receiving the top of the rectangle. // // On success, return true and write to the out parameters. Otherwise return // false and leave the out parameters unmodified. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_GetTrimBox(FPDF_PAGE page, float* left, float* bottom, float* right, float* top); // Get "ArtBox" entry from the page dictionary. // // page - Handle to a page. // left - Pointer to a float value receiving the left of the rectangle. // bottom - Pointer to a float value receiving the bottom of the rectangle. // right - Pointer to a float value receiving the right of the rectangle. // top - Pointer to a float value receiving the top of the rectangle. // // On success, return true and write to the out parameters. Otherwise return // false and leave the out parameters unmodified. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_GetArtBox(FPDF_PAGE page, float* left, float* bottom, float* right, float* top); // Apply transforms to |page|. // // If |matrix| is provided it will be applied to transform the page. // If |clipRect| is provided it will be used to clip the resulting page. // If neither |matrix| or |clipRect| are provided this method returns |false|. // Returns |true| if transforms are applied. // // This function will transform the whole page, and would take effect to all the // objects in the page. // // page - Page handle. // matrix - Transform matrix. // clipRect - Clipping rectangle. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_TransFormWithClip(FPDF_PAGE page, const FS_MATRIX* matrix, const FS_RECTF* clipRect); // Transform (scale, rotate, shear, move) the clip path of page object. // page_object - Handle to a page object. Returned by // FPDFPageObj_NewImageObj(). // // a - The coefficient "a" of the matrix. // b - The coefficient "b" of the matrix. // c - The coefficient "c" of the matrix. // d - The coefficient "d" of the matrix. // e - The coefficient "e" of the matrix. // f - The coefficient "f" of the matrix. FPDF_EXPORT void FPDF_CALLCONV FPDFPageObj_TransformClipPath(FPDF_PAGEOBJECT page_object, double a, double b, double c, double d, double e, double f); // Experimental API. // Get the clip path of the page object. // // page object - Handle to a page object. Returned by e.g. // FPDFPage_GetObject(). // // Returns the handle to the clip path, or NULL on failure. The caller does not // take ownership of the returned FPDF_CLIPPATH. Instead, it remains valid until // FPDF_ClosePage() is called for the page containing |page_object|. FPDF_EXPORT FPDF_CLIPPATH FPDF_CALLCONV FPDFPageObj_GetClipPath(FPDF_PAGEOBJECT page_object); // Experimental API. // Get number of paths inside |clip_path|. // // clip_path - handle to a clip_path. // // Returns the number of objects in |clip_path| or -1 on failure. FPDF_EXPORT int FPDF_CALLCONV FPDFClipPath_CountPaths(FPDF_CLIPPATH clip_path); // Experimental API. // Get number of segments inside one path of |clip_path|. // // clip_path - handle to a clip_path. // path_index - index into the array of paths of the clip path. // // Returns the number of segments or -1 on failure. FPDF_EXPORT int FPDF_CALLCONV FPDFClipPath_CountPathSegments(FPDF_CLIPPATH clip_path, int path_index); // Experimental API. // Get segment in one specific path of |clip_path| at index. // // clip_path - handle to a clip_path. // path_index - the index of a path. // segment_index - the index of a segment. // // Returns the handle to the segment, or NULL on failure. The caller does not // take ownership of the returned FPDF_PATHSEGMENT. Instead, it remains valid // until FPDF_ClosePage() is called for the page containing |clip_path|. FPDF_EXPORT FPDF_PATHSEGMENT FPDF_CALLCONV FPDFClipPath_GetPathSegment(FPDF_CLIPPATH clip_path, int path_index, int segment_index); // Create a new clip path, with a rectangle inserted. // // Caller takes ownership of the returned FPDF_CLIPPATH. It should be freed with // FPDF_DestroyClipPath(). // // left - The left of the clip box. // bottom - The bottom of the clip box. // right - The right of the clip box. // top - The top of the clip box. FPDF_EXPORT FPDF_CLIPPATH FPDF_CALLCONV FPDF_CreateClipPath(float left, float bottom, float right, float top); // Destroy the clip path. // // clipPath - A handle to the clip path. It will be invalid after this call. FPDF_EXPORT void FPDF_CALLCONV FPDF_DestroyClipPath(FPDF_CLIPPATH clipPath); // Clip the page content, the page content that outside the clipping region // become invisible. // // A clip path will be inserted before the page content stream or content array. // In this way, the page content will be clipped by this clip path. // // page - A page handle. // clipPath - A handle to the clip path. (Does not take ownership.) FPDF_EXPORT void FPDF_CALLCONV FPDFPage_InsertClipPath(FPDF_PAGE page, FPDF_CLIPPATH clipPath); #ifdef __cplusplus } #endif #endif // PUBLIC_FPDF_TRANSFORMPAGE_H_ ================================================ FILE: external/pdfium/windows-x64/include/fpdfview.h ================================================ // Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com // This is the main header file for embedders of PDFium. It provides APIs to // initialize the library, load documents, and render pages, amongst other // things. // // NOTE: None of the PDFium APIs are thread-safe. They expect to be called // from a single thread. Barring that, embedders are required to ensure (via // a mutex or similar) that only a single PDFium call can be made at a time. // // NOTE: External docs refer to this file as "fpdfview.h", so do not rename // despite lack of consistency with other public files. #ifndef PUBLIC_FPDFVIEW_H_ #define PUBLIC_FPDFVIEW_H_ // clang-format off #include #if defined(_WIN32) && !defined(__WINDOWS__) #include #endif #ifdef PDF_ENABLE_XFA // PDF_USE_XFA is set in confirmation that this version of PDFium can support // XFA forms as requested by the PDF_ENABLE_XFA setting. #define PDF_USE_XFA #endif // PDF_ENABLE_XFA // PDF object types #define FPDF_OBJECT_UNKNOWN 0 #define FPDF_OBJECT_BOOLEAN 1 #define FPDF_OBJECT_NUMBER 2 #define FPDF_OBJECT_STRING 3 #define FPDF_OBJECT_NAME 4 #define FPDF_OBJECT_ARRAY 5 #define FPDF_OBJECT_DICTIONARY 6 #define FPDF_OBJECT_STREAM 7 #define FPDF_OBJECT_NULLOBJ 8 #define FPDF_OBJECT_REFERENCE 9 // PDF text rendering modes typedef enum { FPDF_TEXTRENDERMODE_UNKNOWN = -1, FPDF_TEXTRENDERMODE_FILL = 0, FPDF_TEXTRENDERMODE_STROKE = 1, FPDF_TEXTRENDERMODE_FILL_STROKE = 2, FPDF_TEXTRENDERMODE_INVISIBLE = 3, FPDF_TEXTRENDERMODE_FILL_CLIP = 4, FPDF_TEXTRENDERMODE_STROKE_CLIP = 5, FPDF_TEXTRENDERMODE_FILL_STROKE_CLIP = 6, FPDF_TEXTRENDERMODE_CLIP = 7, FPDF_TEXTRENDERMODE_LAST = FPDF_TEXTRENDERMODE_CLIP, } FPDF_TEXT_RENDERMODE; // PDF types - use incomplete types (never completed) to force API type safety. typedef struct fpdf_action_t__* FPDF_ACTION; typedef struct fpdf_annotation_t__* FPDF_ANNOTATION; typedef struct fpdf_attachment_t__* FPDF_ATTACHMENT; typedef struct fpdf_avail_t__* FPDF_AVAIL; typedef struct fpdf_bitmap_t__* FPDF_BITMAP; typedef struct fpdf_bookmark_t__* FPDF_BOOKMARK; typedef struct fpdf_clippath_t__* FPDF_CLIPPATH; typedef struct fpdf_dest_t__* FPDF_DEST; typedef struct fpdf_document_t__* FPDF_DOCUMENT; typedef struct fpdf_font_t__* FPDF_FONT; typedef struct fpdf_form_handle_t__* FPDF_FORMHANDLE; typedef const struct fpdf_glyphpath_t__* FPDF_GLYPHPATH; typedef struct fpdf_javascript_action_t* FPDF_JAVASCRIPT_ACTION; typedef struct fpdf_link_t__* FPDF_LINK; typedef struct fpdf_page_t__* FPDF_PAGE; typedef struct fpdf_pagelink_t__* FPDF_PAGELINK; typedef struct fpdf_pageobject_t__* FPDF_PAGEOBJECT; // (text, path, etc.) typedef struct fpdf_pageobjectmark_t__* FPDF_PAGEOBJECTMARK; typedef const struct fpdf_pagerange_t__* FPDF_PAGERANGE; typedef const struct fpdf_pathsegment_t* FPDF_PATHSEGMENT; typedef struct fpdf_schhandle_t__* FPDF_SCHHANDLE; typedef const struct fpdf_signature_t__* FPDF_SIGNATURE; typedef void* FPDF_SKIA_CANVAS; // Passed into Skia as an SkCanvas. typedef struct fpdf_structelement_t__* FPDF_STRUCTELEMENT; typedef const struct fpdf_structelement_attr_t__* FPDF_STRUCTELEMENT_ATTR; typedef const struct fpdf_structelement_attr_value_t__* FPDF_STRUCTELEMENT_ATTR_VALUE; typedef struct fpdf_structtree_t__* FPDF_STRUCTTREE; typedef struct fpdf_textpage_t__* FPDF_TEXTPAGE; typedef struct fpdf_widget_t__* FPDF_WIDGET; typedef struct fpdf_xobject_t__* FPDF_XOBJECT; // Basic data types typedef int FPDF_BOOL; typedef int FPDF_RESULT; typedef unsigned long FPDF_DWORD; typedef float FS_FLOAT; // Duplex types typedef enum _FPDF_DUPLEXTYPE_ { DuplexUndefined = 0, Simplex, DuplexFlipShortEdge, DuplexFlipLongEdge } FPDF_DUPLEXTYPE; // String types typedef unsigned short FPDF_WCHAR; // The public PDFium API uses three types of strings: byte string, wide string // (UTF-16LE encoded), and platform dependent string. // Public PDFium API type for byte strings. typedef const char* FPDF_BYTESTRING; // The public PDFium API always uses UTF-16LE encoded wide strings, each // character uses 2 bytes (except surrogation), with the low byte first. typedef const FPDF_WCHAR* FPDF_WIDESTRING; // Structure for persisting a string beyond the duration of a callback. // Note: although represented as a char*, string may be interpreted as // a UTF-16LE formated string. Used only by XFA callbacks. typedef struct FPDF_BSTR_ { char* str; // String buffer, manipulate only with FPDF_BStr_* methods. int len; // Length of the string, in bytes. } FPDF_BSTR; // For Windows programmers: In most cases it's OK to treat FPDF_WIDESTRING as a // Windows unicode string, however, special care needs to be taken if you // expect to process Unicode larger than 0xffff. // // For Linux/Unix programmers: most compiler/library environments use 4 bytes // for a Unicode character, and you have to convert between FPDF_WIDESTRING and // system wide string by yourself. typedef const char* FPDF_STRING; // Matrix for transformation, in the form [a b c d e f], equivalent to: // | a b 0 | // | c d 0 | // | e f 1 | // // Translation is performed with [1 0 0 1 tx ty]. // Scaling is performed with [sx 0 0 sy 0 0]. // See PDF Reference 1.7, 4.2.2 Common Transformations for more. typedef struct _FS_MATRIX_ { float a; float b; float c; float d; float e; float f; } FS_MATRIX; // Rectangle area(float) in device or page coordinate system. typedef struct _FS_RECTF_ { // The x-coordinate of the left-top corner. float left; // The y-coordinate of the left-top corner. float top; // The x-coordinate of the right-bottom corner. float right; // The y-coordinate of the right-bottom corner. float bottom; } * FS_LPRECTF, FS_RECTF; // Const Pointer to FS_RECTF structure. typedef const FS_RECTF* FS_LPCRECTF; // Rectangle size. Coordinate system agnostic. typedef struct FS_SIZEF_ { float width; float height; } * FS_LPSIZEF, FS_SIZEF; // Const Pointer to FS_SIZEF structure. typedef const FS_SIZEF* FS_LPCSIZEF; // 2D Point. Coordinate system agnostic. typedef struct FS_POINTF_ { float x; float y; } * FS_LPPOINTF, FS_POINTF; // Const Pointer to FS_POINTF structure. typedef const FS_POINTF* FS_LPCPOINTF; typedef struct _FS_QUADPOINTSF { FS_FLOAT x1; FS_FLOAT y1; FS_FLOAT x2; FS_FLOAT y2; FS_FLOAT x3; FS_FLOAT y3; FS_FLOAT x4; FS_FLOAT y4; } FS_QUADPOINTSF; // Annotation enums. typedef int FPDF_ANNOTATION_SUBTYPE; typedef int FPDF_ANNOT_APPEARANCEMODE; // Dictionary value types. typedef int FPDF_OBJECT_TYPE; #if defined(WIN32) #if defined(FPDF_IMPLEMENTATION) #define FPDF_EXPORT __declspec(dllexport) #else #define FPDF_EXPORT __declspec(dllimport) #endif // defined(FPDF_IMPLEMENTATION) #else #if defined(FPDF_IMPLEMENTATION) #define FPDF_EXPORT __attribute__((visibility("default"))) #else #define FPDF_EXPORT #endif // defined(FPDF_IMPLEMENTATION) #endif // defined(WIN32) #if defined(WIN32) && defined(FPDFSDK_EXPORTS) #define FPDF_CALLCONV __stdcall #else #define FPDF_CALLCONV #endif // Exported Functions #ifdef __cplusplus extern "C" { #endif // PDF renderer types - Experimental. // Selection of 2D graphics library to use for rendering to FPDF_BITMAPs. typedef enum { // Anti-Grain Geometry - https://sourceforge.net/projects/agg/ FPDF_RENDERERTYPE_AGG = 0, // Skia - https://skia.org/ FPDF_RENDERERTYPE_SKIA = 1, } FPDF_RENDERER_TYPE; // PDF font library types - Experimental. // Selection of font backend library to use. typedef enum { // FreeType - https://freetype.org/ FPDF_FONTBACKENDTYPE_FREETYPE = 0, // Fontations - https://github.com/googlefonts/fontations/ FPDF_FONTBACKENDTYPE_FONTATIONS = 1, } FPDF_FONT_BACKEND_TYPE; // Process-wide options for initializing the library. typedef struct FPDF_LIBRARY_CONFIG_ { // Version number of the interface. Currently must be 2. // Support for version 1 will be deprecated in the future. int version; // Array of paths to scan in place of the defaults when using built-in // FXGE font loading code. The array is terminated by a NULL pointer. // The Array may be NULL itself to use the default paths. May be ignored // entirely depending upon the platform. const char** m_pUserFontPaths; // Version 2. // Pointer to the v8::Isolate to use, or NULL to force PDFium to create one. void* m_pIsolate; // The embedder data slot to use in the v8::Isolate to store PDFium's // per-isolate data. The value needs to be in the range // [0, |v8::Internals::kNumIsolateDataLots|). Note that 0 is fine for most // embedders. unsigned int m_v8EmbedderSlot; // Version 3 - Experimental. // Pointer to the V8::Platform to use. void* m_pPlatform; // Version 4 - Experimental. // Explicit specification of 2D graphics rendering library to use. // |m_RendererType| must be a valid value for |FPDF_LIBRARY_CONFIG| versions // of this level or higher, or else the initialization will fail with an // immediate crash. // Note that use of a specified |FPDF_RENDERER_TYPE| value for which the // corresponding 2D graphics rendering library is not included in the build // will similarly fail with an immediate crash. FPDF_RENDERER_TYPE m_RendererType; // Version 5 - Experimental. // Explicit specification of font library to use when |m_RendererType| is set // to |FPDF_RENDERERTYPE_SKIA|. // |m_FontLibraryType| must be a valid value for |FPDF_LIBRARY_CONFIG| // versions of this level or higher, or else the initialization will fail with // an immediate crash. // Note that use of a specified |FPDF_FONT_BACKEND_TYPE| value for which the // corresponding font library is not included in the build will similarly fail // with an immediate crash. FPDF_FONT_BACKEND_TYPE m_FontLibraryType; } FPDF_LIBRARY_CONFIG; // Function: FPDF_InitLibraryWithConfig // Initialize the PDFium library and allocate global resources for it. // Parameters: // config - configuration information as above. // Return value: // None. // Comments: // You have to call this function before you can call any PDF // processing functions. FPDF_EXPORT void FPDF_CALLCONV FPDF_InitLibraryWithConfig(const FPDF_LIBRARY_CONFIG* config); // Function: FPDF_InitLibrary // Initialize the PDFium library (alternative form). // Parameters: // None // Return value: // None. // Comments: // Convenience function to call FPDF_InitLibraryWithConfig() with a // default configuration for backwards compatibility purposes. New // code should call FPDF_InitLibraryWithConfig() instead. This will // be deprecated in the future. FPDF_EXPORT void FPDF_CALLCONV FPDF_InitLibrary(); // Function: FPDF_DestroyLibrary // Release global resources allocated to the PDFium library by // FPDF_InitLibrary() or FPDF_InitLibraryWithConfig(). // Parameters: // None. // Return value: // None. // Comments: // After this function is called, you must not call any PDF // processing functions. // // Calling this function does not automatically close other // objects. It is recommended to close other objects before // closing the library with this function. FPDF_EXPORT void FPDF_CALLCONV FPDF_DestroyLibrary(); // Policy for accessing the local machine time. #define FPDF_POLICY_MACHINETIME_ACCESS 0 // Function: FPDF_SetSandBoxPolicy // Set the policy for the sandbox environment. // Parameters: // policy - The specified policy for setting, for example: // FPDF_POLICY_MACHINETIME_ACCESS. // enable - True to enable, false to disable the policy. // Return value: // None. FPDF_EXPORT void FPDF_CALLCONV FPDF_SetSandBoxPolicy(FPDF_DWORD policy, FPDF_BOOL enable); #if defined(_WIN32) // Experimental API. // Function: FPDF_SetPrintMode // Set printing mode when printing on Windows. // Parameters: // mode - FPDF_PRINTMODE_EMF to output EMF (default) // FPDF_PRINTMODE_TEXTONLY to output text only (for charstream // devices) // FPDF_PRINTMODE_POSTSCRIPT2 to output level 2 PostScript into // EMF as a series of GDI comments. // FPDF_PRINTMODE_POSTSCRIPT3 to output level 3 PostScript into // EMF as a series of GDI comments. // FPDF_PRINTMODE_POSTSCRIPT2_PASSTHROUGH to output level 2 // PostScript via ExtEscape() in PASSTHROUGH mode. // FPDF_PRINTMODE_POSTSCRIPT3_PASSTHROUGH to output level 3 // PostScript via ExtEscape() in PASSTHROUGH mode. // FPDF_PRINTMODE_EMF_IMAGE_MASKS to output EMF, with more // efficient processing of documents containing image masks. // FPDF_PRINTMODE_POSTSCRIPT3_TYPE42 to output level 3 // PostScript with embedded Type 42 fonts, when applicable, into // EMF as a series of GDI comments. // FPDF_PRINTMODE_POSTSCRIPT3_TYPE42_PASSTHROUGH to output level // 3 PostScript with embedded Type 42 fonts, when applicable, // via ExtEscape() in PASSTHROUGH mode. // Return value: // True if successful, false if unsuccessful (typically invalid input). FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_SetPrintMode(int mode); #endif // defined(_WIN32) // Function: FPDF_LoadDocument // Open and load a PDF document. // Parameters: // file_path - Path to the PDF file (including extension). // password - A string used as the password for the PDF file. // If no password is needed, empty or NULL can be used. // See comments below regarding the encoding. // Return value: // A handle to the loaded document, or NULL on failure. // Comments: // Loaded document can be closed by FPDF_CloseDocument(). // If this function fails, you can use FPDF_GetLastError() to retrieve // the reason why it failed. // // The encoding for |file_path| is UTF-8. // // The encoding for |password| can be either UTF-8 or Latin-1. PDFs, // depending on the security handler revision, will only accept one or // the other encoding. If |password|'s encoding and the PDF's expected // encoding do not match, FPDF_LoadDocument() will automatically // convert |password| to the other encoding. FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV FPDF_LoadDocument(FPDF_STRING file_path, FPDF_BYTESTRING password); // Function: FPDF_LoadMemDocument // Open and load a PDF document from memory. // Parameters: // data_buf - Pointer to a buffer containing the PDF document. // size - Number of bytes in the PDF document. // password - A string used as the password for the PDF file. // If no password is needed, empty or NULL can be used. // Return value: // A handle to the loaded document, or NULL on failure. // Comments: // The memory buffer must remain valid when the document is open. // The loaded document can be closed by FPDF_CloseDocument. // If this function fails, you can use FPDF_GetLastError() to retrieve // the reason why it failed. // // See the comments for FPDF_LoadDocument() regarding the encoding for // |password|. // Notes: // If PDFium is built with the XFA module, the application should call // FPDF_LoadXFA() function after the PDF document loaded to support XFA // fields defined in the fpdfformfill.h file. FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV FPDF_LoadMemDocument(const void* data_buf, int size, FPDF_BYTESTRING password); // Experimental API. // Function: FPDF_LoadMemDocument64 // Open and load a PDF document from memory. // Parameters: // data_buf - Pointer to a buffer containing the PDF document. // size - Number of bytes in the PDF document. // password - A string used as the password for the PDF file. // If no password is needed, empty or NULL can be used. // Return value: // A handle to the loaded document, or NULL on failure. // Comments: // The memory buffer must remain valid when the document is open. // The loaded document can be closed by FPDF_CloseDocument. // If this function fails, you can use FPDF_GetLastError() to retrieve // the reason why it failed. // // See the comments for FPDF_LoadDocument() regarding the encoding for // |password|. // Notes: // If PDFium is built with the XFA module, the application should call // FPDF_LoadXFA() function after the PDF document loaded to support XFA // fields defined in the fpdfformfill.h file. FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV FPDF_LoadMemDocument64(const void* data_buf, size_t size, FPDF_BYTESTRING password); // Structure for custom file access. typedef struct { // File length, in bytes. unsigned long m_FileLen; // A function pointer for getting a block of data from a specific position. // Position is specified by byte offset from the beginning of the file. // The pointer to the buffer is never NULL and the size is never 0. // The position and size will never go out of range of the file length. // It may be possible for PDFium to call this function multiple times for // the same position. // Return value: should be non-zero if successful, zero for error. int (*m_GetBlock)(void* param, unsigned long position, unsigned char* pBuf, unsigned long size); // A custom pointer for all implementation specific data. This pointer will // be used as the first parameter to the m_GetBlock callback. void* m_Param; } FPDF_FILEACCESS; // Structure for file reading or writing (I/O). // // Note: This is a handler and should be implemented by callers, // and is only used from XFA. typedef struct FPDF_FILEHANDLER_ { // User-defined data. // Note: Callers can use this field to track controls. void* clientData; // Callback function to release the current file stream object. // // Parameters: // clientData - Pointer to user-defined data. // Returns: // None. void (*Release)(void* clientData); // Callback function to retrieve the current file stream size. // // Parameters: // clientData - Pointer to user-defined data. // Returns: // Size of file stream. FPDF_DWORD (*GetSize)(void* clientData); // Callback function to read data from the current file stream. // // Parameters: // clientData - Pointer to user-defined data. // offset - Offset position starts from the beginning of file // stream. This parameter indicates reading position. // buffer - Memory buffer to store data which are read from // file stream. This parameter should not be NULL. // size - Size of data which should be read from file stream, // in bytes. The buffer indicated by |buffer| must be // large enough to store specified data. // Returns: // 0 for success, other value for failure. FPDF_RESULT (*ReadBlock)(void* clientData, FPDF_DWORD offset, void* buffer, FPDF_DWORD size); // Callback function to write data into the current file stream. // // Parameters: // clientData - Pointer to user-defined data. // offset - Offset position starts from the beginning of file // stream. This parameter indicates writing position. // buffer - Memory buffer contains data which is written into // file stream. This parameter should not be NULL. // size - Size of data which should be written into file // stream, in bytes. // Returns: // 0 for success, other value for failure. FPDF_RESULT (*WriteBlock)(void* clientData, FPDF_DWORD offset, const void* buffer, FPDF_DWORD size); // Callback function to flush all internal accessing buffers. // // Parameters: // clientData - Pointer to user-defined data. // Returns: // 0 for success, other value for failure. FPDF_RESULT (*Flush)(void* clientData); // Callback function to change file size. // // Description: // This function is called under writing mode usually. Implementer // can determine whether to realize it based on application requests. // Parameters: // clientData - Pointer to user-defined data. // size - New size of file stream, in bytes. // Returns: // 0 for success, other value for failure. FPDF_RESULT (*Truncate)(void* clientData, FPDF_DWORD size); } FPDF_FILEHANDLER; // Function: FPDF_LoadCustomDocument // Load PDF document from a custom access descriptor. // Parameters: // pFileAccess - A structure for accessing the file. // password - Optional password for decrypting the PDF file. // Return value: // A handle to the loaded document, or NULL on failure. // Comments: // The application must keep the file resources |pFileAccess| points to // valid until the returned FPDF_DOCUMENT is closed. |pFileAccess| // itself does not need to outlive the FPDF_DOCUMENT. // // The loaded document can be closed with FPDF_CloseDocument(). // // See the comments for FPDF_LoadDocument() regarding the encoding for // |password|. // Notes: // If PDFium is built with the XFA module, the application should call // FPDF_LoadXFA() function after the PDF document loaded to support XFA // fields defined in the fpdfformfill.h file. FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV FPDF_LoadCustomDocument(FPDF_FILEACCESS* pFileAccess, FPDF_BYTESTRING password); // Function: FPDF_GetFileVersion // Get the file version of the given PDF document. // Parameters: // doc - Handle to a document. // fileVersion - The PDF file version. File version: 14 for 1.4, 15 // for 1.5, ... // Return value: // True if succeeds, false otherwise. // Comments: // If the document was created by FPDF_CreateNewDocument, // then this function will always fail. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_GetFileVersion(FPDF_DOCUMENT doc, int* fileVersion); #define FPDF_ERR_SUCCESS 0 // No error. #define FPDF_ERR_UNKNOWN 1 // Unknown error. #define FPDF_ERR_FILE 2 // File not found or could not be opened. #define FPDF_ERR_FORMAT 3 // File not in PDF format or corrupted. #define FPDF_ERR_PASSWORD 4 // Password required or incorrect password. #define FPDF_ERR_SECURITY 5 // Unsupported security scheme. #define FPDF_ERR_PAGE 6 // Page not found or content error. #ifdef PDF_ENABLE_XFA #define FPDF_ERR_XFALOAD 7 // Load XFA error. #define FPDF_ERR_XFALAYOUT 8 // Layout XFA error. #endif // PDF_ENABLE_XFA // Function: FPDF_GetLastError // Get last error code when a function fails. // Parameters: // None. // Return value: // A 32-bit integer indicating error code as defined above. // Comments: // If the previous SDK call succeeded, the return value of this // function is not defined. This function only works in conjunction // with APIs that mention FPDF_GetLastError() in their documentation. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetLastError(); // Experimental API. // Function: FPDF_DocumentHasValidCrossReferenceTable // Whether the document's cross reference table is valid or not. // Parameters: // document - Handle to a document. Returned by FPDF_LoadDocument. // Return value: // True if the PDF parser did not encounter problems parsing the cross // reference table. False if the parser could not parse the cross // reference table and the table had to be rebuild from other data // within the document. // Comments: // The return value can change over time as the PDF parser evolves. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_DocumentHasValidCrossReferenceTable(FPDF_DOCUMENT document); // Experimental API. // Function: FPDF_GetTrailerEnds // Get the byte offsets of trailer ends. // Parameters: // document - Handle to document. Returned by FPDF_LoadDocument(). // buffer - The address of a buffer that receives the // byte offsets. // length - The size, in ints, of |buffer|. // Return value: // Returns the number of ints in the buffer on success, 0 on error. // // |buffer| is an array of integers that describes the exact byte offsets of the // trailer ends in the document. If |length| is less than the returned length, // or |document| or |buffer| is NULL, |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetTrailerEnds(FPDF_DOCUMENT document, unsigned int* buffer, unsigned long length); // Function: FPDF_GetDocPermissions // Get file permission flags of the document. // Parameters: // document - Handle to a document. Returned by FPDF_LoadDocument. // Return value: // A 32-bit integer indicating permission flags. Please refer to the // PDF Reference for detailed descriptions. If the document is not // protected or was unlocked by the owner, 0xffffffff will be returned. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetDocPermissions(FPDF_DOCUMENT document); // Function: FPDF_GetDocUserPermissions // Get user file permission flags of the document. // Parameters: // document - Handle to a document. Returned by FPDF_LoadDocument. // Return value: // A 32-bit integer indicating permission flags. Please refer to the // PDF Reference for detailed descriptions. If the document is not // protected, 0xffffffff will be returned. Always returns user // permissions, even if the document was unlocked by the owner. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetDocUserPermissions(FPDF_DOCUMENT document); // Function: FPDF_GetSecurityHandlerRevision // Get the revision for the security handler. // Parameters: // document - Handle to a document. Returned by FPDF_LoadDocument. // Return value: // The security handler revision number. Please refer to the PDF // Reference for a detailed description. If the document is not // protected, -1 will be returned. FPDF_EXPORT int FPDF_CALLCONV FPDF_GetSecurityHandlerRevision(FPDF_DOCUMENT document); // Function: FPDF_GetPageCount // Get total number of pages in the document. // Parameters: // document - Handle to document. Returned by FPDF_LoadDocument. // Return value: // Total number of pages in the document. FPDF_EXPORT int FPDF_CALLCONV FPDF_GetPageCount(FPDF_DOCUMENT document); // Function: FPDF_LoadPage // Load a page inside the document. // Parameters: // document - Handle to document. Returned by FPDF_LoadDocument // page_index - Index number of the page. 0 for the first page. // Return value: // A handle to the loaded page, or NULL if page load fails. // Comments: // The loaded page can be rendered to devices using FPDF_RenderPage. // The loaded page can be closed using FPDF_ClosePage. FPDF_EXPORT FPDF_PAGE FPDF_CALLCONV FPDF_LoadPage(FPDF_DOCUMENT document, int page_index); // Experimental API // Function: FPDF_GetPageWidthF // Get page width. // Parameters: // page - Handle to the page. Returned by FPDF_LoadPage(). // Return value: // Page width (excluding non-displayable area) measured in points. // One point is 1/72 inch (around 0.3528 mm). // Comments: // Changing the rotation of |page| affects the return value. FPDF_EXPORT float FPDF_CALLCONV FPDF_GetPageWidthF(FPDF_PAGE page); // Function: FPDF_GetPageWidth // Get page width. // Parameters: // page - Handle to the page. Returned by FPDF_LoadPage. // Return value: // Page width (excluding non-displayable area) measured in points. // One point is 1/72 inch (around 0.3528 mm). // Note: // Prefer FPDF_GetPageWidthF() above. This will be deprecated in the // future. // Comments: // Changing the rotation of |page| affects the return value. FPDF_EXPORT double FPDF_CALLCONV FPDF_GetPageWidth(FPDF_PAGE page); // Experimental API // Function: FPDF_GetPageHeightF // Get page height. // Parameters: // page - Handle to the page. Returned by FPDF_LoadPage(). // Return value: // Page height (excluding non-displayable area) measured in points. // One point is 1/72 inch (around 0.3528 mm) // Comments: // Changing the rotation of |page| affects the return value. FPDF_EXPORT float FPDF_CALLCONV FPDF_GetPageHeightF(FPDF_PAGE page); // Function: FPDF_GetPageHeight // Get page height. // Parameters: // page - Handle to the page. Returned by FPDF_LoadPage. // Return value: // Page height (excluding non-displayable area) measured in points. // One point is 1/72 inch (around 0.3528 mm) // Note: // Prefer FPDF_GetPageHeightF() above. This will be deprecated in the // future. // Comments: // Changing the rotation of |page| affects the return value. FPDF_EXPORT double FPDF_CALLCONV FPDF_GetPageHeight(FPDF_PAGE page); // Experimental API. // Function: FPDF_GetPageBoundingBox // Get the bounding box of the page. This is the intersection between // its media box and its crop box. // Parameters: // page - Handle to the page. Returned by FPDF_LoadPage. // rect - Pointer to a rect to receive the page bounding box. // On an error, |rect| won't be filled. // Return value: // True for success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_GetPageBoundingBox(FPDF_PAGE page, FS_RECTF* rect); // Experimental API. // Function: FPDF_GetPageSizeByIndexF // Get the size of the page at the given index. // Parameters: // document - Handle to document. Returned by FPDF_LoadDocument(). // page_index - Page index, zero for the first page. // size - Pointer to a FS_SIZEF to receive the page size. // (in points). // Return value: // Non-zero for success. 0 for error (document or page not found). FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_GetPageSizeByIndexF(FPDF_DOCUMENT document, int page_index, FS_SIZEF* size); // Function: FPDF_GetPageSizeByIndex // Get the size of the page at the given index. // Parameters: // document - Handle to document. Returned by FPDF_LoadDocument. // page_index - Page index, zero for the first page. // width - Pointer to a double to receive the page width // (in points). // height - Pointer to a double to receive the page height // (in points). // Return value: // Non-zero for success. 0 for error (document or page not found). // Note: // Prefer FPDF_GetPageSizeByIndexF() above. This will be deprecated in // the future. FPDF_EXPORT int FPDF_CALLCONV FPDF_GetPageSizeByIndex(FPDF_DOCUMENT document, int page_index, double* width, double* height); // Page rendering flags. They can be combined with bit-wise OR. // // Set if annotations are to be rendered. #define FPDF_ANNOT 0x01 // Set if using text rendering optimized for LCD display. This flag will only // take effect if anti-aliasing is enabled for text. #define FPDF_LCD_TEXT 0x02 // Don't use the native text output available on some platforms #define FPDF_NO_NATIVETEXT 0x04 // Grayscale output. #define FPDF_GRAYSCALE 0x08 // Obsolete, has no effect, retained for compatibility. #define FPDF_DEBUG_INFO 0x80 // Obsolete, has no effect, retained for compatibility. #define FPDF_NO_CATCH 0x100 // Limit image cache size. #define FPDF_RENDER_LIMITEDIMAGECACHE 0x200 // Always use halftone for image stretching. #define FPDF_RENDER_FORCEHALFTONE 0x400 // Render for printing. #define FPDF_PRINTING 0x800 // Set to disable anti-aliasing on text. This flag will also disable LCD // optimization for text rendering. #define FPDF_RENDER_NO_SMOOTHTEXT 0x1000 // Set to disable anti-aliasing on images. #define FPDF_RENDER_NO_SMOOTHIMAGE 0x2000 // Set to disable anti-aliasing on paths. #define FPDF_RENDER_NO_SMOOTHPATH 0x4000 // Set whether to render in a reverse Byte order, this flag is only used when // rendering to a bitmap. #define FPDF_REVERSE_BYTE_ORDER 0x10 // Set whether fill paths need to be stroked. This flag is only used when // FPDF_COLORSCHEME is passed in, since with a single fill color for paths the // boundaries of adjacent fill paths are less visible. #define FPDF_CONVERT_FILL_TO_STROKE 0x20 // Struct for color scheme. // Each should be a 32-bit value specifying the color, in 8888 ARGB format. typedef struct FPDF_COLORSCHEME_ { FPDF_DWORD path_fill_color; FPDF_DWORD path_stroke_color; FPDF_DWORD text_fill_color; FPDF_DWORD text_stroke_color; } FPDF_COLORSCHEME; #ifdef _WIN32 // Function: FPDF_RenderPage // Render contents of a page to a device (screen, bitmap, or printer). // This function is only supported on Windows. // Parameters: // dc - Handle to the device context. // page - Handle to the page. Returned by FPDF_LoadPage. // start_x - Left pixel position of the display area in // device coordinates. // start_y - Top pixel position of the display area in device // coordinates. // size_x - Horizontal size (in pixels) for displaying the page. // size_y - Vertical size (in pixels) for displaying the page. // rotate - Page orientation: // 0 (normal) // 1 (rotated 90 degrees clockwise) // 2 (rotated 180 degrees) // 3 (rotated 90 degrees counter-clockwise) // flags - 0 for normal display, or combination of flags // defined above. // Return value: // Returns true if the page is rendered successfully, false otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_RenderPage(HDC dc, FPDF_PAGE page, int start_x, int start_y, int size_x, int size_y, int rotate, int flags); #endif // Function: FPDF_RenderPageBitmap // Render contents of a page to a device independent bitmap. // Parameters: // bitmap - Handle to the device independent bitmap (as the // output buffer). The bitmap handle can be created // by FPDFBitmap_Create or retrieved from an image // object by FPDFImageObj_GetBitmap. // page - Handle to the page. Returned by FPDF_LoadPage // start_x - Left pixel position of the display area in // bitmap coordinates. // start_y - Top pixel position of the display area in bitmap // coordinates. // size_x - Horizontal size (in pixels) for displaying the page. // size_y - Vertical size (in pixels) for displaying the page. // rotate - Page orientation: // 0 (normal) // 1 (rotated 90 degrees clockwise) // 2 (rotated 180 degrees) // 3 (rotated 90 degrees counter-clockwise) // flags - 0 for normal display, or combination of the Page // Rendering flags defined above. With the FPDF_ANNOT // flag, it renders all annotations that do not require // user-interaction, which are all annotations except // widget and popup annotations. // Return value: // None. FPDF_EXPORT void FPDF_CALLCONV FPDF_RenderPageBitmap(FPDF_BITMAP bitmap, FPDF_PAGE page, int start_x, int start_y, int size_x, int size_y, int rotate, int flags); // Function: FPDF_RenderPageBitmapWithMatrix // Render contents of a page to a device independent bitmap. // Parameters: // bitmap - Handle to the device independent bitmap (as the // output buffer). The bitmap handle can be created // by FPDFBitmap_Create or retrieved by // FPDFImageObj_GetBitmap. // page - Handle to the page. Returned by FPDF_LoadPage. // matrix - The transform matrix, which must be invertible. // See PDF Reference 1.7, 4.2.2 Common Transformations. // clipping - The rect to clip to in device coords. // flags - 0 for normal display, or combination of the Page // Rendering flags defined above. With the FPDF_ANNOT // flag, it renders all annotations that do not require // user-interaction, which are all annotations except // widget and popup annotations. // Return value: // None. Note that behavior is undefined if det of |matrix| is 0. FPDF_EXPORT void FPDF_CALLCONV FPDF_RenderPageBitmapWithMatrix(FPDF_BITMAP bitmap, FPDF_PAGE page, const FS_MATRIX* matrix, const FS_RECTF* clipping, int flags); #if defined(PDF_USE_SKIA) // Experimental API. // Function: FPDF_RenderPageSkia // Render contents of a page to a Skia SkCanvas. // Parameters: // canvas - SkCanvas to render to. // page - Handle to the page. // size_x - Horizontal size (in pixels) for displaying the page. // size_y - Vertical size (in pixels) for displaying the page. // Return value: // None. FPDF_EXPORT void FPDF_CALLCONV FPDF_RenderPageSkia(FPDF_SKIA_CANVAS canvas, FPDF_PAGE page, int size_x, int size_y); #endif // Function: FPDF_ClosePage // Close a loaded PDF page. // Parameters: // page - Handle to the loaded page. // Return value: // None. FPDF_EXPORT void FPDF_CALLCONV FPDF_ClosePage(FPDF_PAGE page); // Function: FPDF_CloseDocument // Close a loaded PDF document. // Parameters: // document - Handle to the loaded document. // Return value: // None. FPDF_EXPORT void FPDF_CALLCONV FPDF_CloseDocument(FPDF_DOCUMENT document); // Function: FPDF_DeviceToPage // Convert the screen coordinates of a point to page coordinates. // Parameters: // page - Handle to the page. Returned by FPDF_LoadPage. // start_x - Left pixel position of the display area in // device coordinates. // start_y - Top pixel position of the display area in device // coordinates. // size_x - Horizontal size (in pixels) for displaying the page. // size_y - Vertical size (in pixels) for displaying the page. // rotate - Page orientation: // 0 (normal) // 1 (rotated 90 degrees clockwise) // 2 (rotated 180 degrees) // 3 (rotated 90 degrees counter-clockwise) // device_x - X value in device coordinates to be converted. // device_y - Y value in device coordinates to be converted. // page_x - A pointer to a double receiving the converted X // value in page coordinates. // page_y - A pointer to a double receiving the converted Y // value in page coordinates. // Return value: // Returns true if the conversion succeeds, and |page_x| and |page_y| // successfully receives the converted coordinates. // Comments: // The page coordinate system has its origin at the left-bottom corner // of the page, with the X-axis on the bottom going to the right, and // the Y-axis on the left side going up. // // NOTE: this coordinate system can be altered when you zoom, scroll, // or rotate a page, however, a point on the page should always have // the same coordinate values in the page coordinate system. // // The device coordinate system is device dependent. For screen device, // its origin is at the left-top corner of the window. However this // origin can be altered by the Windows coordinate transformation // utilities. // // You must make sure the start_x, start_y, size_x, size_y // and rotate parameters have exactly same values as you used in // the FPDF_RenderPage() function call. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_DeviceToPage(FPDF_PAGE page, int start_x, int start_y, int size_x, int size_y, int rotate, int device_x, int device_y, double* page_x, double* page_y); // Function: FPDF_PageToDevice // Convert the page coordinates of a point to screen coordinates. // Parameters: // page - Handle to the page. Returned by FPDF_LoadPage. // start_x - Left pixel position of the display area in // device coordinates. // start_y - Top pixel position of the display area in device // coordinates. // size_x - Horizontal size (in pixels) for displaying the page. // size_y - Vertical size (in pixels) for displaying the page. // rotate - Page orientation: // 0 (normal) // 1 (rotated 90 degrees clockwise) // 2 (rotated 180 degrees) // 3 (rotated 90 degrees counter-clockwise) // page_x - X value in page coordinates. // page_y - Y value in page coordinate. // device_x - A pointer to an integer receiving the result X // value in device coordinates. // device_y - A pointer to an integer receiving the result Y // value in device coordinates. // Return value: // Returns true if the conversion succeeds, and |device_x| and // |device_y| successfully receives the converted coordinates. // Comments: // See comments for FPDF_DeviceToPage(). FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_PageToDevice(FPDF_PAGE page, int start_x, int start_y, int size_x, int size_y, int rotate, double page_x, double page_y, int* device_x, int* device_y); // Function: FPDFBitmap_Create // Create a device independent bitmap (FXDIB). // Parameters: // width - The number of pixels in width for the bitmap. // Must be greater than 0. // height - The number of pixels in height for the bitmap. // Must be greater than 0. // alpha - A flag indicating whether the alpha channel is used. // Non-zero for using alpha, zero for not using. // Return value: // The created bitmap handle, or NULL if a parameter error or out of // memory. // Comments: // The bitmap always uses 4 bytes per pixel. The first byte is always // double word aligned. // // The byte order is BGRx (the last byte unused if no alpha channel) or // BGRA. // // The pixels in a horizontal line are stored side by side, with the // left most pixel stored first (with lower memory address). // Each line uses width * 4 bytes. // // Lines are stored one after another, with the top most line stored // first. There is no gap between adjacent lines. // // This function allocates enough memory for holding all pixels in the // bitmap, but it doesn't initialize the buffer. Applications can use // FPDFBitmap_FillRect() to fill the bitmap using any color. If the OS // allows it, this function can allocate up to 4 GB of memory. FPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV FPDFBitmap_Create(int width, int height, int alpha); // More DIB formats // Unknown or unsupported format. // All of the colors are listed in order of LSB to MSB. #define FPDFBitmap_Unknown 0 // Gray scale bitmap, one byte per pixel. #define FPDFBitmap_Gray 1 // 3 bytes per pixel, byte order: blue, green, red. #define FPDFBitmap_BGR 2 // 4 bytes per pixel, byte order: blue, green, red, unused. #define FPDFBitmap_BGRx 3 // 4 bytes per pixel, byte order: blue, green, red, alpha. // Pixel components are independent of alpha. #define FPDFBitmap_BGRA 4 // 4 bytes per pixel, byte order: blue, green, red, alpha. // Pixel components are premultiplied by alpha. // Note that this is experimental and only supported when rendering with // |FPDF_RENDERER_TYPE| is set to |FPDF_RENDERERTYPE_SKIA|. #define FPDFBitmap_BGRA_Premul 5 // Function: FPDFBitmap_CreateEx // Create a device independent bitmap (FXDIB) // Parameters: // width - The number of pixels in width for the bitmap. // Must be greater than 0. // height - The number of pixels in height for the bitmap. // Must be greater than 0. // format - A number indicating for bitmap format, as defined // above. // first_scan - A pointer to the first byte of the first line if // using an external buffer. If this parameter is NULL, // then a new buffer will be created. // stride - Number of bytes for each scan line. The value must // be 0 or greater. When the value is 0, // FPDFBitmap_CreateEx() will automatically calculate // the appropriate value using |width| and |format|. // When using an external buffer, it is recommended for // the caller to pass in the value. // When not using an external buffer, it is recommended // for the caller to pass in 0. // Return value: // The bitmap handle, or NULL if parameter error or out of memory. // Comments: // Similar to FPDFBitmap_Create function, but allows for more formats // and an external buffer is supported. The bitmap created by this // function can be used in any place that a FPDF_BITMAP handle is // required. // // If an external buffer is used, then the caller should destroy the // buffer. FPDFBitmap_Destroy() will not destroy the buffer. // // It is recommended to use FPDFBitmap_GetStride() to get the stride // value. FPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV FPDFBitmap_CreateEx(int width, int height, int format, void* first_scan, int stride); // Function: FPDFBitmap_GetFormat // Get the format of the bitmap. // Parameters: // bitmap - Handle to the bitmap. Returned by FPDFBitmap_Create // or FPDFImageObj_GetBitmap. // Return value: // The format of the bitmap. // Comments: // Only formats supported by FPDFBitmap_CreateEx are supported by this // function; see the list of such formats above. FPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetFormat(FPDF_BITMAP bitmap); // Function: FPDFBitmap_FillRect // Fill a rectangle in a bitmap. // Parameters: // bitmap - The handle to the bitmap. Returned by // FPDFBitmap_Create. // left - The left position. Starting from 0 at the // left-most pixel. // top - The top position. Starting from 0 at the // top-most line. // width - Width in pixels to be filled. // height - Height in pixels to be filled. // color - A 32-bit value specifing the color, in 8888 ARGB // format. // Return value: // Returns whether the operation succeeded or not. // Comments: // This function sets the color and (optionally) alpha value in the // specified region of the bitmap. // // NOTE: If the alpha channel is used, this function does NOT // composite the background with the source color, instead the // background will be replaced by the source color and the alpha. // // If the alpha channel is not used, the alpha parameter is ignored. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFBitmap_FillRect(FPDF_BITMAP bitmap, int left, int top, int width, int height, FPDF_DWORD color); // Function: FPDFBitmap_GetBuffer // Get data buffer of a bitmap. // Parameters: // bitmap - Handle to the bitmap. Returned by FPDFBitmap_Create // or FPDFImageObj_GetBitmap. // Return value: // The pointer to the first byte of the bitmap buffer. // Comments: // The stride may be more than width * number of bytes per pixel // // Applications can use this function to get the bitmap buffer pointer, // then manipulate any color and/or alpha values for any pixels in the // bitmap. // // Use FPDFBitmap_GetFormat() to find out the format of the data. FPDF_EXPORT void* FPDF_CALLCONV FPDFBitmap_GetBuffer(FPDF_BITMAP bitmap); // Function: FPDFBitmap_GetWidth // Get width of a bitmap. // Parameters: // bitmap - Handle to the bitmap. Returned by FPDFBitmap_Create // or FPDFImageObj_GetBitmap. // Return value: // The width of the bitmap in pixels. FPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetWidth(FPDF_BITMAP bitmap); // Function: FPDFBitmap_GetHeight // Get height of a bitmap. // Parameters: // bitmap - Handle to the bitmap. Returned by FPDFBitmap_Create // or FPDFImageObj_GetBitmap. // Return value: // The height of the bitmap in pixels. FPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetHeight(FPDF_BITMAP bitmap); // Function: FPDFBitmap_GetStride // Get number of bytes for each line in the bitmap buffer. // Parameters: // bitmap - Handle to the bitmap. Returned by FPDFBitmap_Create // or FPDFImageObj_GetBitmap. // Return value: // The number of bytes for each line in the bitmap buffer. // Comments: // The stride may be more than width * number of bytes per pixel. FPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetStride(FPDF_BITMAP bitmap); // Function: FPDFBitmap_Destroy // Destroy a bitmap and release all related buffers. // Parameters: // bitmap - Handle to the bitmap. Returned by FPDFBitmap_Create // or FPDFImageObj_GetBitmap. // Return value: // None. // Comments: // This function will not destroy any external buffers provided when // the bitmap was created. FPDF_EXPORT void FPDF_CALLCONV FPDFBitmap_Destroy(FPDF_BITMAP bitmap); // Function: FPDF_VIEWERREF_GetPrintScaling // Whether the PDF document prefers to be scaled or not. // Parameters: // document - Handle to the loaded document. // Return value: // None. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_VIEWERREF_GetPrintScaling(FPDF_DOCUMENT document); // Function: FPDF_VIEWERREF_GetNumCopies // Returns the number of copies to be printed. // Parameters: // document - Handle to the loaded document. // Return value: // The number of copies to be printed. FPDF_EXPORT int FPDF_CALLCONV FPDF_VIEWERREF_GetNumCopies(FPDF_DOCUMENT document); // Function: FPDF_VIEWERREF_GetPrintPageRange // Page numbers to initialize print dialog box when file is printed. // Parameters: // document - Handle to the loaded document. // Return value: // The print page range to be used for printing. FPDF_EXPORT FPDF_PAGERANGE FPDF_CALLCONV FPDF_VIEWERREF_GetPrintPageRange(FPDF_DOCUMENT document); // Experimental API. // Function: FPDF_VIEWERREF_GetPrintPageRangeCount // Returns the number of elements in a FPDF_PAGERANGE. // Parameters: // pagerange - Handle to the page range. // Return value: // The number of elements in the page range. Returns 0 on error. FPDF_EXPORT size_t FPDF_CALLCONV FPDF_VIEWERREF_GetPrintPageRangeCount(FPDF_PAGERANGE pagerange); // Experimental API. // Function: FPDF_VIEWERREF_GetPrintPageRangeElement // Returns an element from a FPDF_PAGERANGE. // Parameters: // pagerange - Handle to the page range. // index - Index of the element. // Return value: // The value of the element in the page range at a given index. // Returns -1 on error. FPDF_EXPORT int FPDF_CALLCONV FPDF_VIEWERREF_GetPrintPageRangeElement(FPDF_PAGERANGE pagerange, size_t index); // Function: FPDF_VIEWERREF_GetDuplex // Returns the paper handling option to be used when printing from // the print dialog. // Parameters: // document - Handle to the loaded document. // Return value: // The paper handling option to be used when printing. FPDF_EXPORT FPDF_DUPLEXTYPE FPDF_CALLCONV FPDF_VIEWERREF_GetDuplex(FPDF_DOCUMENT document); // Function: FPDF_VIEWERREF_GetName // Gets the contents for a viewer ref, with a given key. The value must // be of type "name". // Parameters: // document - Handle to the loaded document. // key - Name of the key in the viewer pref dictionary, // encoded in UTF-8. // buffer - Caller-allocate buffer to receive the key, or NULL // - to query the required length. // length - Length of the buffer. // Return value: // The number of bytes in the contents, including the NULL terminator. // Thus if the return value is 0, then that indicates an error, such // as when |document| is invalid. If |length| is less than the required // length, or |buffer| is NULL, |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_VIEWERREF_GetName(FPDF_DOCUMENT document, FPDF_BYTESTRING key, char* buffer, unsigned long length); // Function: FPDF_CountNamedDests // Get the count of named destinations in the PDF document. // Parameters: // document - Handle to a document // Return value: // The count of named destinations. FPDF_EXPORT FPDF_DWORD FPDF_CALLCONV FPDF_CountNamedDests(FPDF_DOCUMENT document); // Function: FPDF_GetNamedDestByName // Get a the destination handle for the given name. // Parameters: // document - Handle to the loaded document. // name - The name of a destination. // Return value: // The handle to the destination. FPDF_EXPORT FPDF_DEST FPDF_CALLCONV FPDF_GetNamedDestByName(FPDF_DOCUMENT document, FPDF_BYTESTRING name); // Function: FPDF_GetNamedDest // Get the named destination by index. // Parameters: // document - Handle to a document // index - The index of a named destination. // buffer - The buffer to store the destination name, // used as wchar_t*. // buflen [in/out] - Size of the buffer in bytes on input, // length of the result in bytes on output // or -1 if the buffer is too small. // Return value: // The destination handle for a given index, or NULL if there is no // named destination corresponding to |index|. // Comments: // Call this function twice to get the name of the named destination: // 1) First time pass in |buffer| as NULL and get buflen. // 2) Second time pass in allocated |buffer| and buflen to retrieve // |buffer|, which should be used as wchar_t*. // // If buflen is not sufficiently large, it will be set to -1 upon // return. FPDF_EXPORT FPDF_DEST FPDF_CALLCONV FPDF_GetNamedDest(FPDF_DOCUMENT document, int index, void* buffer, long* buflen); // Experimental API. // Function: FPDF_GetXFAPacketCount // Get the number of valid packets in the XFA entry. // Parameters: // document - Handle to the document. // Return value: // The number of valid packets, or -1 on error. FPDF_EXPORT int FPDF_CALLCONV FPDF_GetXFAPacketCount(FPDF_DOCUMENT document); // Experimental API. // Function: FPDF_GetXFAPacketName // Get the name of a packet in the XFA array. // Parameters: // document - Handle to the document. // index - Index number of the packet. 0 for the first packet. // buffer - Buffer for holding the name of the XFA packet. // buflen - Length of |buffer| in bytes. // Return value: // The length of the packet name in bytes, or 0 on error. // // |document| must be valid and |index| must be in the range [0, N), where N is // the value returned by FPDF_GetXFAPacketCount(). // |buffer| is only modified if it is non-NULL and |buflen| is greater than or // equal to the length of the packet name. The packet name includes a // terminating NUL character. |buffer| is unmodified on error. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetXFAPacketName( FPDF_DOCUMENT document, int index, void* buffer, unsigned long buflen); // Experimental API. // Function: FPDF_GetXFAPacketContent // Get the content of a packet in the XFA array. // Parameters: // document - Handle to the document. // index - Index number of the packet. 0 for the first packet. // buffer - Buffer for holding the content of the XFA packet. // buflen - Length of |buffer| in bytes. // out_buflen - Pointer to the variable that will receive the minimum // buffer size needed to contain the content of the XFA // packet. // Return value: // Whether the operation succeeded or not. // // |document| must be valid and |index| must be in the range [0, N), where N is // the value returned by FPDF_GetXFAPacketCount(). |out_buflen| must not be // NULL. When the aforementioned arguments are valid, the operation succeeds, // and |out_buflen| receives the content size. |buffer| is only modified if // |buffer| is non-null and long enough to contain the content. Callers must // check both the return value and the input |buflen| is no less than the // returned |out_buflen| before using the data in |buffer|. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_GetXFAPacketContent( FPDF_DOCUMENT document, int index, void* buffer, unsigned long buflen, unsigned long* out_buflen); #ifdef PDF_ENABLE_V8 // Function: FPDF_GetRecommendedV8Flags // Returns a space-separated string of command line flags that are // recommended to be passed into V8 via V8::SetFlagsFromString() // prior to initializing the PDFium library. // Parameters: // None. // Return value: // NUL-terminated string of the form "--flag1 --flag2". // The caller must not attempt to modify or free the result. FPDF_EXPORT const char* FPDF_CALLCONV FPDF_GetRecommendedV8Flags(); // Experimental API. // Function: FPDF_GetArrayBufferAllocatorSharedInstance() // Helper function for initializing V8 isolates that will // use PDFium's internal memory management. // Parameters: // None. // Return Value: // Pointer to a suitable v8::ArrayBuffer::Allocator, returned // as void for C compatibility. // Notes: // Use is optional, but allows external creation of isolates // matching the ones PDFium will make when none is provided // via |FPDF_LIBRARY_CONFIG::m_pIsolate|. // // Can only be called when the library is in an uninitialized or // destroyed state. FPDF_EXPORT void* FPDF_CALLCONV FPDF_GetArrayBufferAllocatorSharedInstance(); #endif // PDF_ENABLE_V8 #ifdef PDF_ENABLE_XFA // Function: FPDF_BStr_Init // Helper function to initialize a FPDF_BSTR. FPDF_EXPORT FPDF_RESULT FPDF_CALLCONV FPDF_BStr_Init(FPDF_BSTR* bstr); // Function: FPDF_BStr_Set // Helper function to copy string data into the FPDF_BSTR. FPDF_EXPORT FPDF_RESULT FPDF_CALLCONV FPDF_BStr_Set(FPDF_BSTR* bstr, const char* cstr, int length); // Function: FPDF_BStr_Clear // Helper function to clear a FPDF_BSTR. FPDF_EXPORT FPDF_RESULT FPDF_CALLCONV FPDF_BStr_Clear(FPDF_BSTR* bstr); #endif // PDF_ENABLE_XFA #ifdef __cplusplus } #endif #endif // PUBLIC_FPDFVIEW_H_ ================================================ FILE: external/pdfium/windows-x64/include/fpdfview.h.orig ================================================ // Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com // This is the main header file for embedders of PDFium. It provides APIs to // initialize the library, load documents, and render pages, amongst other // things. // // NOTE: None of the PDFium APIs are thread-safe. They expect to be called // from a single thread. Barring that, embedders are required to ensure (via // a mutex or similar) that only a single PDFium call can be made at a time. // // NOTE: External docs refer to this file as "fpdfview.h", so do not rename // despite lack of consistency with other public files. #ifndef PUBLIC_FPDFVIEW_H_ #define PUBLIC_FPDFVIEW_H_ // clang-format off #include #if defined(_WIN32) && !defined(__WINDOWS__) #include #endif #ifdef PDF_ENABLE_XFA // PDF_USE_XFA is set in confirmation that this version of PDFium can support // XFA forms as requested by the PDF_ENABLE_XFA setting. #define PDF_USE_XFA #endif // PDF_ENABLE_XFA // PDF object types #define FPDF_OBJECT_UNKNOWN 0 #define FPDF_OBJECT_BOOLEAN 1 #define FPDF_OBJECT_NUMBER 2 #define FPDF_OBJECT_STRING 3 #define FPDF_OBJECT_NAME 4 #define FPDF_OBJECT_ARRAY 5 #define FPDF_OBJECT_DICTIONARY 6 #define FPDF_OBJECT_STREAM 7 #define FPDF_OBJECT_NULLOBJ 8 #define FPDF_OBJECT_REFERENCE 9 // PDF text rendering modes typedef enum { FPDF_TEXTRENDERMODE_UNKNOWN = -1, FPDF_TEXTRENDERMODE_FILL = 0, FPDF_TEXTRENDERMODE_STROKE = 1, FPDF_TEXTRENDERMODE_FILL_STROKE = 2, FPDF_TEXTRENDERMODE_INVISIBLE = 3, FPDF_TEXTRENDERMODE_FILL_CLIP = 4, FPDF_TEXTRENDERMODE_STROKE_CLIP = 5, FPDF_TEXTRENDERMODE_FILL_STROKE_CLIP = 6, FPDF_TEXTRENDERMODE_CLIP = 7, FPDF_TEXTRENDERMODE_LAST = FPDF_TEXTRENDERMODE_CLIP, } FPDF_TEXT_RENDERMODE; // PDF types - use incomplete types (never completed) to force API type safety. typedef struct fpdf_action_t__* FPDF_ACTION; typedef struct fpdf_annotation_t__* FPDF_ANNOTATION; typedef struct fpdf_attachment_t__* FPDF_ATTACHMENT; typedef struct fpdf_avail_t__* FPDF_AVAIL; typedef struct fpdf_bitmap_t__* FPDF_BITMAP; typedef struct fpdf_bookmark_t__* FPDF_BOOKMARK; typedef struct fpdf_clippath_t__* FPDF_CLIPPATH; typedef struct fpdf_dest_t__* FPDF_DEST; typedef struct fpdf_document_t__* FPDF_DOCUMENT; typedef struct fpdf_font_t__* FPDF_FONT; typedef struct fpdf_form_handle_t__* FPDF_FORMHANDLE; typedef const struct fpdf_glyphpath_t__* FPDF_GLYPHPATH; typedef struct fpdf_javascript_action_t* FPDF_JAVASCRIPT_ACTION; typedef struct fpdf_link_t__* FPDF_LINK; typedef struct fpdf_page_t__* FPDF_PAGE; typedef struct fpdf_pagelink_t__* FPDF_PAGELINK; typedef struct fpdf_pageobject_t__* FPDF_PAGEOBJECT; // (text, path, etc.) typedef struct fpdf_pageobjectmark_t__* FPDF_PAGEOBJECTMARK; typedef const struct fpdf_pagerange_t__* FPDF_PAGERANGE; typedef const struct fpdf_pathsegment_t* FPDF_PATHSEGMENT; typedef struct fpdf_schhandle_t__* FPDF_SCHHANDLE; typedef const struct fpdf_signature_t__* FPDF_SIGNATURE; typedef void* FPDF_SKIA_CANVAS; // Passed into Skia as an SkCanvas. typedef struct fpdf_structelement_t__* FPDF_STRUCTELEMENT; typedef const struct fpdf_structelement_attr_t__* FPDF_STRUCTELEMENT_ATTR; typedef const struct fpdf_structelement_attr_value_t__* FPDF_STRUCTELEMENT_ATTR_VALUE; typedef struct fpdf_structtree_t__* FPDF_STRUCTTREE; typedef struct fpdf_textpage_t__* FPDF_TEXTPAGE; typedef struct fpdf_widget_t__* FPDF_WIDGET; typedef struct fpdf_xobject_t__* FPDF_XOBJECT; // Basic data types typedef int FPDF_BOOL; typedef int FPDF_RESULT; typedef unsigned long FPDF_DWORD; typedef float FS_FLOAT; // Duplex types typedef enum _FPDF_DUPLEXTYPE_ { DuplexUndefined = 0, Simplex, DuplexFlipShortEdge, DuplexFlipLongEdge } FPDF_DUPLEXTYPE; // String types typedef unsigned short FPDF_WCHAR; // The public PDFium API uses three types of strings: byte string, wide string // (UTF-16LE encoded), and platform dependent string. // Public PDFium API type for byte strings. typedef const char* FPDF_BYTESTRING; // The public PDFium API always uses UTF-16LE encoded wide strings, each // character uses 2 bytes (except surrogation), with the low byte first. typedef const FPDF_WCHAR* FPDF_WIDESTRING; // Structure for persisting a string beyond the duration of a callback. // Note: although represented as a char*, string may be interpreted as // a UTF-16LE formated string. Used only by XFA callbacks. typedef struct FPDF_BSTR_ { char* str; // String buffer, manipulate only with FPDF_BStr_* methods. int len; // Length of the string, in bytes. } FPDF_BSTR; // For Windows programmers: In most cases it's OK to treat FPDF_WIDESTRING as a // Windows unicode string, however, special care needs to be taken if you // expect to process Unicode larger than 0xffff. // // For Linux/Unix programmers: most compiler/library environments use 4 bytes // for a Unicode character, and you have to convert between FPDF_WIDESTRING and // system wide string by yourself. typedef const char* FPDF_STRING; // Matrix for transformation, in the form [a b c d e f], equivalent to: // | a b 0 | // | c d 0 | // | e f 1 | // // Translation is performed with [1 0 0 1 tx ty]. // Scaling is performed with [sx 0 0 sy 0 0]. // See PDF Reference 1.7, 4.2.2 Common Transformations for more. typedef struct _FS_MATRIX_ { float a; float b; float c; float d; float e; float f; } FS_MATRIX; // Rectangle area(float) in device or page coordinate system. typedef struct _FS_RECTF_ { // The x-coordinate of the left-top corner. float left; // The y-coordinate of the left-top corner. float top; // The x-coordinate of the right-bottom corner. float right; // The y-coordinate of the right-bottom corner. float bottom; } * FS_LPRECTF, FS_RECTF; // Const Pointer to FS_RECTF structure. typedef const FS_RECTF* FS_LPCRECTF; // Rectangle size. Coordinate system agnostic. typedef struct FS_SIZEF_ { float width; float height; } * FS_LPSIZEF, FS_SIZEF; // Const Pointer to FS_SIZEF structure. typedef const FS_SIZEF* FS_LPCSIZEF; // 2D Point. Coordinate system agnostic. typedef struct FS_POINTF_ { float x; float y; } * FS_LPPOINTF, FS_POINTF; // Const Pointer to FS_POINTF structure. typedef const FS_POINTF* FS_LPCPOINTF; typedef struct _FS_QUADPOINTSF { FS_FLOAT x1; FS_FLOAT y1; FS_FLOAT x2; FS_FLOAT y2; FS_FLOAT x3; FS_FLOAT y3; FS_FLOAT x4; FS_FLOAT y4; } FS_QUADPOINTSF; // Annotation enums. typedef int FPDF_ANNOTATION_SUBTYPE; typedef int FPDF_ANNOT_APPEARANCEMODE; // Dictionary value types. typedef int FPDF_OBJECT_TYPE; #if defined(COMPONENT_BUILD) // FPDF_EXPORT should be consistent with |export| in the pdfium_fuzzer // template in testing/fuzzers/BUILD.gn. #if defined(WIN32) #if defined(FPDF_IMPLEMENTATION) #define FPDF_EXPORT __declspec(dllexport) #else #define FPDF_EXPORT __declspec(dllimport) #endif // defined(FPDF_IMPLEMENTATION) #else #if defined(FPDF_IMPLEMENTATION) #define FPDF_EXPORT __attribute__((visibility("default"))) #else #define FPDF_EXPORT #endif // defined(FPDF_IMPLEMENTATION) #endif // defined(WIN32) #else #define FPDF_EXPORT #endif // defined(COMPONENT_BUILD) #if defined(WIN32) && defined(FPDFSDK_EXPORTS) #define FPDF_CALLCONV __stdcall #else #define FPDF_CALLCONV #endif // Exported Functions #ifdef __cplusplus extern "C" { #endif // PDF renderer types - Experimental. // Selection of 2D graphics library to use for rendering to FPDF_BITMAPs. typedef enum { // Anti-Grain Geometry - https://sourceforge.net/projects/agg/ FPDF_RENDERERTYPE_AGG = 0, // Skia - https://skia.org/ FPDF_RENDERERTYPE_SKIA = 1, } FPDF_RENDERER_TYPE; // PDF font library types - Experimental. // Selection of font backend library to use. typedef enum { // FreeType - https://freetype.org/ FPDF_FONTBACKENDTYPE_FREETYPE = 0, // Fontations - https://github.com/googlefonts/fontations/ FPDF_FONTBACKENDTYPE_FONTATIONS = 1, } FPDF_FONT_BACKEND_TYPE; // Process-wide options for initializing the library. typedef struct FPDF_LIBRARY_CONFIG_ { // Version number of the interface. Currently must be 2. // Support for version 1 will be deprecated in the future. int version; // Array of paths to scan in place of the defaults when using built-in // FXGE font loading code. The array is terminated by a NULL pointer. // The Array may be NULL itself to use the default paths. May be ignored // entirely depending upon the platform. const char** m_pUserFontPaths; // Version 2. // Pointer to the v8::Isolate to use, or NULL to force PDFium to create one. void* m_pIsolate; // The embedder data slot to use in the v8::Isolate to store PDFium's // per-isolate data. The value needs to be in the range // [0, |v8::Internals::kNumIsolateDataLots|). Note that 0 is fine for most // embedders. unsigned int m_v8EmbedderSlot; // Version 3 - Experimental. // Pointer to the V8::Platform to use. void* m_pPlatform; // Version 4 - Experimental. // Explicit specification of 2D graphics rendering library to use. // |m_RendererType| must be a valid value for |FPDF_LIBRARY_CONFIG| versions // of this level or higher, or else the initialization will fail with an // immediate crash. // Note that use of a specified |FPDF_RENDERER_TYPE| value for which the // corresponding 2D graphics rendering library is not included in the build // will similarly fail with an immediate crash. FPDF_RENDERER_TYPE m_RendererType; // Version 5 - Experimental. // Explicit specification of font library to use when |m_RendererType| is set // to |FPDF_RENDERERTYPE_SKIA|. // |m_FontLibraryType| must be a valid value for |FPDF_LIBRARY_CONFIG| // versions of this level or higher, or else the initialization will fail with // an immediate crash. // Note that use of a specified |FPDF_FONT_BACKEND_TYPE| value for which the // corresponding font library is not included in the build will similarly fail // with an immediate crash. FPDF_FONT_BACKEND_TYPE m_FontLibraryType; } FPDF_LIBRARY_CONFIG; // Function: FPDF_InitLibraryWithConfig // Initialize the PDFium library and allocate global resources for it. // Parameters: // config - configuration information as above. // Return value: // None. // Comments: // You have to call this function before you can call any PDF // processing functions. FPDF_EXPORT void FPDF_CALLCONV FPDF_InitLibraryWithConfig(const FPDF_LIBRARY_CONFIG* config); // Function: FPDF_InitLibrary // Initialize the PDFium library (alternative form). // Parameters: // None // Return value: // None. // Comments: // Convenience function to call FPDF_InitLibraryWithConfig() with a // default configuration for backwards compatibility purposes. New // code should call FPDF_InitLibraryWithConfig() instead. This will // be deprecated in the future. FPDF_EXPORT void FPDF_CALLCONV FPDF_InitLibrary(); // Function: FPDF_DestroyLibrary // Release global resources allocated to the PDFium library by // FPDF_InitLibrary() or FPDF_InitLibraryWithConfig(). // Parameters: // None. // Return value: // None. // Comments: // After this function is called, you must not call any PDF // processing functions. // // Calling this function does not automatically close other // objects. It is recommended to close other objects before // closing the library with this function. FPDF_EXPORT void FPDF_CALLCONV FPDF_DestroyLibrary(); // Policy for accessing the local machine time. #define FPDF_POLICY_MACHINETIME_ACCESS 0 // Function: FPDF_SetSandBoxPolicy // Set the policy for the sandbox environment. // Parameters: // policy - The specified policy for setting, for example: // FPDF_POLICY_MACHINETIME_ACCESS. // enable - True to enable, false to disable the policy. // Return value: // None. FPDF_EXPORT void FPDF_CALLCONV FPDF_SetSandBoxPolicy(FPDF_DWORD policy, FPDF_BOOL enable); #if defined(_WIN32) // Experimental API. // Function: FPDF_SetPrintMode // Set printing mode when printing on Windows. // Parameters: // mode - FPDF_PRINTMODE_EMF to output EMF (default) // FPDF_PRINTMODE_TEXTONLY to output text only (for charstream // devices) // FPDF_PRINTMODE_POSTSCRIPT2 to output level 2 PostScript into // EMF as a series of GDI comments. // FPDF_PRINTMODE_POSTSCRIPT3 to output level 3 PostScript into // EMF as a series of GDI comments. // FPDF_PRINTMODE_POSTSCRIPT2_PASSTHROUGH to output level 2 // PostScript via ExtEscape() in PASSTHROUGH mode. // FPDF_PRINTMODE_POSTSCRIPT3_PASSTHROUGH to output level 3 // PostScript via ExtEscape() in PASSTHROUGH mode. // FPDF_PRINTMODE_EMF_IMAGE_MASKS to output EMF, with more // efficient processing of documents containing image masks. // FPDF_PRINTMODE_POSTSCRIPT3_TYPE42 to output level 3 // PostScript with embedded Type 42 fonts, when applicable, into // EMF as a series of GDI comments. // FPDF_PRINTMODE_POSTSCRIPT3_TYPE42_PASSTHROUGH to output level // 3 PostScript with embedded Type 42 fonts, when applicable, // via ExtEscape() in PASSTHROUGH mode. // Return value: // True if successful, false if unsuccessful (typically invalid input). FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_SetPrintMode(int mode); #endif // defined(_WIN32) // Function: FPDF_LoadDocument // Open and load a PDF document. // Parameters: // file_path - Path to the PDF file (including extension). // password - A string used as the password for the PDF file. // If no password is needed, empty or NULL can be used. // See comments below regarding the encoding. // Return value: // A handle to the loaded document, or NULL on failure. // Comments: // Loaded document can be closed by FPDF_CloseDocument(). // If this function fails, you can use FPDF_GetLastError() to retrieve // the reason why it failed. // // The encoding for |file_path| is UTF-8. // // The encoding for |password| can be either UTF-8 or Latin-1. PDFs, // depending on the security handler revision, will only accept one or // the other encoding. If |password|'s encoding and the PDF's expected // encoding do not match, FPDF_LoadDocument() will automatically // convert |password| to the other encoding. FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV FPDF_LoadDocument(FPDF_STRING file_path, FPDF_BYTESTRING password); // Function: FPDF_LoadMemDocument // Open and load a PDF document from memory. // Parameters: // data_buf - Pointer to a buffer containing the PDF document. // size - Number of bytes in the PDF document. // password - A string used as the password for the PDF file. // If no password is needed, empty or NULL can be used. // Return value: // A handle to the loaded document, or NULL on failure. // Comments: // The memory buffer must remain valid when the document is open. // The loaded document can be closed by FPDF_CloseDocument. // If this function fails, you can use FPDF_GetLastError() to retrieve // the reason why it failed. // // See the comments for FPDF_LoadDocument() regarding the encoding for // |password|. // Notes: // If PDFium is built with the XFA module, the application should call // FPDF_LoadXFA() function after the PDF document loaded to support XFA // fields defined in the fpdfformfill.h file. FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV FPDF_LoadMemDocument(const void* data_buf, int size, FPDF_BYTESTRING password); // Experimental API. // Function: FPDF_LoadMemDocument64 // Open and load a PDF document from memory. // Parameters: // data_buf - Pointer to a buffer containing the PDF document. // size - Number of bytes in the PDF document. // password - A string used as the password for the PDF file. // If no password is needed, empty or NULL can be used. // Return value: // A handle to the loaded document, or NULL on failure. // Comments: // The memory buffer must remain valid when the document is open. // The loaded document can be closed by FPDF_CloseDocument. // If this function fails, you can use FPDF_GetLastError() to retrieve // the reason why it failed. // // See the comments for FPDF_LoadDocument() regarding the encoding for // |password|. // Notes: // If PDFium is built with the XFA module, the application should call // FPDF_LoadXFA() function after the PDF document loaded to support XFA // fields defined in the fpdfformfill.h file. FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV FPDF_LoadMemDocument64(const void* data_buf, size_t size, FPDF_BYTESTRING password); // Structure for custom file access. typedef struct { // File length, in bytes. unsigned long m_FileLen; // A function pointer for getting a block of data from a specific position. // Position is specified by byte offset from the beginning of the file. // The pointer to the buffer is never NULL and the size is never 0. // The position and size will never go out of range of the file length. // It may be possible for PDFium to call this function multiple times for // the same position. // Return value: should be non-zero if successful, zero for error. int (*m_GetBlock)(void* param, unsigned long position, unsigned char* pBuf, unsigned long size); // A custom pointer for all implementation specific data. This pointer will // be used as the first parameter to the m_GetBlock callback. void* m_Param; } FPDF_FILEACCESS; // Structure for file reading or writing (I/O). // // Note: This is a handler and should be implemented by callers, // and is only used from XFA. typedef struct FPDF_FILEHANDLER_ { // User-defined data. // Note: Callers can use this field to track controls. void* clientData; // Callback function to release the current file stream object. // // Parameters: // clientData - Pointer to user-defined data. // Returns: // None. void (*Release)(void* clientData); // Callback function to retrieve the current file stream size. // // Parameters: // clientData - Pointer to user-defined data. // Returns: // Size of file stream. FPDF_DWORD (*GetSize)(void* clientData); // Callback function to read data from the current file stream. // // Parameters: // clientData - Pointer to user-defined data. // offset - Offset position starts from the beginning of file // stream. This parameter indicates reading position. // buffer - Memory buffer to store data which are read from // file stream. This parameter should not be NULL. // size - Size of data which should be read from file stream, // in bytes. The buffer indicated by |buffer| must be // large enough to store specified data. // Returns: // 0 for success, other value for failure. FPDF_RESULT (*ReadBlock)(void* clientData, FPDF_DWORD offset, void* buffer, FPDF_DWORD size); // Callback function to write data into the current file stream. // // Parameters: // clientData - Pointer to user-defined data. // offset - Offset position starts from the beginning of file // stream. This parameter indicates writing position. // buffer - Memory buffer contains data which is written into // file stream. This parameter should not be NULL. // size - Size of data which should be written into file // stream, in bytes. // Returns: // 0 for success, other value for failure. FPDF_RESULT (*WriteBlock)(void* clientData, FPDF_DWORD offset, const void* buffer, FPDF_DWORD size); // Callback function to flush all internal accessing buffers. // // Parameters: // clientData - Pointer to user-defined data. // Returns: // 0 for success, other value for failure. FPDF_RESULT (*Flush)(void* clientData); // Callback function to change file size. // // Description: // This function is called under writing mode usually. Implementer // can determine whether to realize it based on application requests. // Parameters: // clientData - Pointer to user-defined data. // size - New size of file stream, in bytes. // Returns: // 0 for success, other value for failure. FPDF_RESULT (*Truncate)(void* clientData, FPDF_DWORD size); } FPDF_FILEHANDLER; // Function: FPDF_LoadCustomDocument // Load PDF document from a custom access descriptor. // Parameters: // pFileAccess - A structure for accessing the file. // password - Optional password for decrypting the PDF file. // Return value: // A handle to the loaded document, or NULL on failure. // Comments: // The application must keep the file resources |pFileAccess| points to // valid until the returned FPDF_DOCUMENT is closed. |pFileAccess| // itself does not need to outlive the FPDF_DOCUMENT. // // The loaded document can be closed with FPDF_CloseDocument(). // // See the comments for FPDF_LoadDocument() regarding the encoding for // |password|. // Notes: // If PDFium is built with the XFA module, the application should call // FPDF_LoadXFA() function after the PDF document loaded to support XFA // fields defined in the fpdfformfill.h file. FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV FPDF_LoadCustomDocument(FPDF_FILEACCESS* pFileAccess, FPDF_BYTESTRING password); // Function: FPDF_GetFileVersion // Get the file version of the given PDF document. // Parameters: // doc - Handle to a document. // fileVersion - The PDF file version. File version: 14 for 1.4, 15 // for 1.5, ... // Return value: // True if succeeds, false otherwise. // Comments: // If the document was created by FPDF_CreateNewDocument, // then this function will always fail. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_GetFileVersion(FPDF_DOCUMENT doc, int* fileVersion); #define FPDF_ERR_SUCCESS 0 // No error. #define FPDF_ERR_UNKNOWN 1 // Unknown error. #define FPDF_ERR_FILE 2 // File not found or could not be opened. #define FPDF_ERR_FORMAT 3 // File not in PDF format or corrupted. #define FPDF_ERR_PASSWORD 4 // Password required or incorrect password. #define FPDF_ERR_SECURITY 5 // Unsupported security scheme. #define FPDF_ERR_PAGE 6 // Page not found or content error. #ifdef PDF_ENABLE_XFA #define FPDF_ERR_XFALOAD 7 // Load XFA error. #define FPDF_ERR_XFALAYOUT 8 // Layout XFA error. #endif // PDF_ENABLE_XFA // Function: FPDF_GetLastError // Get last error code when a function fails. // Parameters: // None. // Return value: // A 32-bit integer indicating error code as defined above. // Comments: // If the previous SDK call succeeded, the return value of this // function is not defined. This function only works in conjunction // with APIs that mention FPDF_GetLastError() in their documentation. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetLastError(); // Experimental API. // Function: FPDF_DocumentHasValidCrossReferenceTable // Whether the document's cross reference table is valid or not. // Parameters: // document - Handle to a document. Returned by FPDF_LoadDocument. // Return value: // True if the PDF parser did not encounter problems parsing the cross // reference table. False if the parser could not parse the cross // reference table and the table had to be rebuild from other data // within the document. // Comments: // The return value can change over time as the PDF parser evolves. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_DocumentHasValidCrossReferenceTable(FPDF_DOCUMENT document); // Experimental API. // Function: FPDF_GetTrailerEnds // Get the byte offsets of trailer ends. // Parameters: // document - Handle to document. Returned by FPDF_LoadDocument(). // buffer - The address of a buffer that receives the // byte offsets. // length - The size, in ints, of |buffer|. // Return value: // Returns the number of ints in the buffer on success, 0 on error. // // |buffer| is an array of integers that describes the exact byte offsets of the // trailer ends in the document. If |length| is less than the returned length, // or |document| or |buffer| is NULL, |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetTrailerEnds(FPDF_DOCUMENT document, unsigned int* buffer, unsigned long length); // Function: FPDF_GetDocPermissions // Get file permission flags of the document. // Parameters: // document - Handle to a document. Returned by FPDF_LoadDocument. // Return value: // A 32-bit integer indicating permission flags. Please refer to the // PDF Reference for detailed descriptions. If the document is not // protected or was unlocked by the owner, 0xffffffff will be returned. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetDocPermissions(FPDF_DOCUMENT document); // Function: FPDF_GetDocUserPermissions // Get user file permission flags of the document. // Parameters: // document - Handle to a document. Returned by FPDF_LoadDocument. // Return value: // A 32-bit integer indicating permission flags. Please refer to the // PDF Reference for detailed descriptions. If the document is not // protected, 0xffffffff will be returned. Always returns user // permissions, even if the document was unlocked by the owner. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetDocUserPermissions(FPDF_DOCUMENT document); // Function: FPDF_GetSecurityHandlerRevision // Get the revision for the security handler. // Parameters: // document - Handle to a document. Returned by FPDF_LoadDocument. // Return value: // The security handler revision number. Please refer to the PDF // Reference for a detailed description. If the document is not // protected, -1 will be returned. FPDF_EXPORT int FPDF_CALLCONV FPDF_GetSecurityHandlerRevision(FPDF_DOCUMENT document); // Function: FPDF_GetPageCount // Get total number of pages in the document. // Parameters: // document - Handle to document. Returned by FPDF_LoadDocument. // Return value: // Total number of pages in the document. FPDF_EXPORT int FPDF_CALLCONV FPDF_GetPageCount(FPDF_DOCUMENT document); // Function: FPDF_LoadPage // Load a page inside the document. // Parameters: // document - Handle to document. Returned by FPDF_LoadDocument // page_index - Index number of the page. 0 for the first page. // Return value: // A handle to the loaded page, or NULL if page load fails. // Comments: // The loaded page can be rendered to devices using FPDF_RenderPage. // The loaded page can be closed using FPDF_ClosePage. FPDF_EXPORT FPDF_PAGE FPDF_CALLCONV FPDF_LoadPage(FPDF_DOCUMENT document, int page_index); // Experimental API // Function: FPDF_GetPageWidthF // Get page width. // Parameters: // page - Handle to the page. Returned by FPDF_LoadPage(). // Return value: // Page width (excluding non-displayable area) measured in points. // One point is 1/72 inch (around 0.3528 mm). // Comments: // Changing the rotation of |page| affects the return value. FPDF_EXPORT float FPDF_CALLCONV FPDF_GetPageWidthF(FPDF_PAGE page); // Function: FPDF_GetPageWidth // Get page width. // Parameters: // page - Handle to the page. Returned by FPDF_LoadPage. // Return value: // Page width (excluding non-displayable area) measured in points. // One point is 1/72 inch (around 0.3528 mm). // Note: // Prefer FPDF_GetPageWidthF() above. This will be deprecated in the // future. // Comments: // Changing the rotation of |page| affects the return value. FPDF_EXPORT double FPDF_CALLCONV FPDF_GetPageWidth(FPDF_PAGE page); // Experimental API // Function: FPDF_GetPageHeightF // Get page height. // Parameters: // page - Handle to the page. Returned by FPDF_LoadPage(). // Return value: // Page height (excluding non-displayable area) measured in points. // One point is 1/72 inch (around 0.3528 mm) // Comments: // Changing the rotation of |page| affects the return value. FPDF_EXPORT float FPDF_CALLCONV FPDF_GetPageHeightF(FPDF_PAGE page); // Function: FPDF_GetPageHeight // Get page height. // Parameters: // page - Handle to the page. Returned by FPDF_LoadPage. // Return value: // Page height (excluding non-displayable area) measured in points. // One point is 1/72 inch (around 0.3528 mm) // Note: // Prefer FPDF_GetPageHeightF() above. This will be deprecated in the // future. // Comments: // Changing the rotation of |page| affects the return value. FPDF_EXPORT double FPDF_CALLCONV FPDF_GetPageHeight(FPDF_PAGE page); // Experimental API. // Function: FPDF_GetPageBoundingBox // Get the bounding box of the page. This is the intersection between // its media box and its crop box. // Parameters: // page - Handle to the page. Returned by FPDF_LoadPage. // rect - Pointer to a rect to receive the page bounding box. // On an error, |rect| won't be filled. // Return value: // True for success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_GetPageBoundingBox(FPDF_PAGE page, FS_RECTF* rect); // Experimental API. // Function: FPDF_GetPageSizeByIndexF // Get the size of the page at the given index. // Parameters: // document - Handle to document. Returned by FPDF_LoadDocument(). // page_index - Page index, zero for the first page. // size - Pointer to a FS_SIZEF to receive the page size. // (in points). // Return value: // Non-zero for success. 0 for error (document or page not found). FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_GetPageSizeByIndexF(FPDF_DOCUMENT document, int page_index, FS_SIZEF* size); // Function: FPDF_GetPageSizeByIndex // Get the size of the page at the given index. // Parameters: // document - Handle to document. Returned by FPDF_LoadDocument. // page_index - Page index, zero for the first page. // width - Pointer to a double to receive the page width // (in points). // height - Pointer to a double to receive the page height // (in points). // Return value: // Non-zero for success. 0 for error (document or page not found). // Note: // Prefer FPDF_GetPageSizeByIndexF() above. This will be deprecated in // the future. FPDF_EXPORT int FPDF_CALLCONV FPDF_GetPageSizeByIndex(FPDF_DOCUMENT document, int page_index, double* width, double* height); // Page rendering flags. They can be combined with bit-wise OR. // // Set if annotations are to be rendered. #define FPDF_ANNOT 0x01 // Set if using text rendering optimized for LCD display. This flag will only // take effect if anti-aliasing is enabled for text. #define FPDF_LCD_TEXT 0x02 // Don't use the native text output available on some platforms #define FPDF_NO_NATIVETEXT 0x04 // Grayscale output. #define FPDF_GRAYSCALE 0x08 // Obsolete, has no effect, retained for compatibility. #define FPDF_DEBUG_INFO 0x80 // Obsolete, has no effect, retained for compatibility. #define FPDF_NO_CATCH 0x100 // Limit image cache size. #define FPDF_RENDER_LIMITEDIMAGECACHE 0x200 // Always use halftone for image stretching. #define FPDF_RENDER_FORCEHALFTONE 0x400 // Render for printing. #define FPDF_PRINTING 0x800 // Set to disable anti-aliasing on text. This flag will also disable LCD // optimization for text rendering. #define FPDF_RENDER_NO_SMOOTHTEXT 0x1000 // Set to disable anti-aliasing on images. #define FPDF_RENDER_NO_SMOOTHIMAGE 0x2000 // Set to disable anti-aliasing on paths. #define FPDF_RENDER_NO_SMOOTHPATH 0x4000 // Set whether to render in a reverse Byte order, this flag is only used when // rendering to a bitmap. #define FPDF_REVERSE_BYTE_ORDER 0x10 // Set whether fill paths need to be stroked. This flag is only used when // FPDF_COLORSCHEME is passed in, since with a single fill color for paths the // boundaries of adjacent fill paths are less visible. #define FPDF_CONVERT_FILL_TO_STROKE 0x20 // Struct for color scheme. // Each should be a 32-bit value specifying the color, in 8888 ARGB format. typedef struct FPDF_COLORSCHEME_ { FPDF_DWORD path_fill_color; FPDF_DWORD path_stroke_color; FPDF_DWORD text_fill_color; FPDF_DWORD text_stroke_color; } FPDF_COLORSCHEME; #ifdef _WIN32 // Function: FPDF_RenderPage // Render contents of a page to a device (screen, bitmap, or printer). // This function is only supported on Windows. // Parameters: // dc - Handle to the device context. // page - Handle to the page. Returned by FPDF_LoadPage. // start_x - Left pixel position of the display area in // device coordinates. // start_y - Top pixel position of the display area in device // coordinates. // size_x - Horizontal size (in pixels) for displaying the page. // size_y - Vertical size (in pixels) for displaying the page. // rotate - Page orientation: // 0 (normal) // 1 (rotated 90 degrees clockwise) // 2 (rotated 180 degrees) // 3 (rotated 90 degrees counter-clockwise) // flags - 0 for normal display, or combination of flags // defined above. // Return value: // Returns true if the page is rendered successfully, false otherwise. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_RenderPage(HDC dc, FPDF_PAGE page, int start_x, int start_y, int size_x, int size_y, int rotate, int flags); #endif // Function: FPDF_RenderPageBitmap // Render contents of a page to a device independent bitmap. // Parameters: // bitmap - Handle to the device independent bitmap (as the // output buffer). The bitmap handle can be created // by FPDFBitmap_Create or retrieved from an image // object by FPDFImageObj_GetBitmap. // page - Handle to the page. Returned by FPDF_LoadPage // start_x - Left pixel position of the display area in // bitmap coordinates. // start_y - Top pixel position of the display area in bitmap // coordinates. // size_x - Horizontal size (in pixels) for displaying the page. // size_y - Vertical size (in pixels) for displaying the page. // rotate - Page orientation: // 0 (normal) // 1 (rotated 90 degrees clockwise) // 2 (rotated 180 degrees) // 3 (rotated 90 degrees counter-clockwise) // flags - 0 for normal display, or combination of the Page // Rendering flags defined above. With the FPDF_ANNOT // flag, it renders all annotations that do not require // user-interaction, which are all annotations except // widget and popup annotations. // Return value: // None. FPDF_EXPORT void FPDF_CALLCONV FPDF_RenderPageBitmap(FPDF_BITMAP bitmap, FPDF_PAGE page, int start_x, int start_y, int size_x, int size_y, int rotate, int flags); // Function: FPDF_RenderPageBitmapWithMatrix // Render contents of a page to a device independent bitmap. // Parameters: // bitmap - Handle to the device independent bitmap (as the // output buffer). The bitmap handle can be created // by FPDFBitmap_Create or retrieved by // FPDFImageObj_GetBitmap. // page - Handle to the page. Returned by FPDF_LoadPage. // matrix - The transform matrix, which must be invertible. // See PDF Reference 1.7, 4.2.2 Common Transformations. // clipping - The rect to clip to in device coords. // flags - 0 for normal display, or combination of the Page // Rendering flags defined above. With the FPDF_ANNOT // flag, it renders all annotations that do not require // user-interaction, which are all annotations except // widget and popup annotations. // Return value: // None. Note that behavior is undefined if det of |matrix| is 0. FPDF_EXPORT void FPDF_CALLCONV FPDF_RenderPageBitmapWithMatrix(FPDF_BITMAP bitmap, FPDF_PAGE page, const FS_MATRIX* matrix, const FS_RECTF* clipping, int flags); #if defined(PDF_USE_SKIA) // Experimental API. // Function: FPDF_RenderPageSkia // Render contents of a page to a Skia SkCanvas. // Parameters: // canvas - SkCanvas to render to. // page - Handle to the page. // size_x - Horizontal size (in pixels) for displaying the page. // size_y - Vertical size (in pixels) for displaying the page. // Return value: // None. FPDF_EXPORT void FPDF_CALLCONV FPDF_RenderPageSkia(FPDF_SKIA_CANVAS canvas, FPDF_PAGE page, int size_x, int size_y); #endif // Function: FPDF_ClosePage // Close a loaded PDF page. // Parameters: // page - Handle to the loaded page. // Return value: // None. FPDF_EXPORT void FPDF_CALLCONV FPDF_ClosePage(FPDF_PAGE page); // Function: FPDF_CloseDocument // Close a loaded PDF document. // Parameters: // document - Handle to the loaded document. // Return value: // None. FPDF_EXPORT void FPDF_CALLCONV FPDF_CloseDocument(FPDF_DOCUMENT document); // Function: FPDF_DeviceToPage // Convert the screen coordinates of a point to page coordinates. // Parameters: // page - Handle to the page. Returned by FPDF_LoadPage. // start_x - Left pixel position of the display area in // device coordinates. // start_y - Top pixel position of the display area in device // coordinates. // size_x - Horizontal size (in pixels) for displaying the page. // size_y - Vertical size (in pixels) for displaying the page. // rotate - Page orientation: // 0 (normal) // 1 (rotated 90 degrees clockwise) // 2 (rotated 180 degrees) // 3 (rotated 90 degrees counter-clockwise) // device_x - X value in device coordinates to be converted. // device_y - Y value in device coordinates to be converted. // page_x - A pointer to a double receiving the converted X // value in page coordinates. // page_y - A pointer to a double receiving the converted Y // value in page coordinates. // Return value: // Returns true if the conversion succeeds, and |page_x| and |page_y| // successfully receives the converted coordinates. // Comments: // The page coordinate system has its origin at the left-bottom corner // of the page, with the X-axis on the bottom going to the right, and // the Y-axis on the left side going up. // // NOTE: this coordinate system can be altered when you zoom, scroll, // or rotate a page, however, a point on the page should always have // the same coordinate values in the page coordinate system. // // The device coordinate system is device dependent. For screen device, // its origin is at the left-top corner of the window. However this // origin can be altered by the Windows coordinate transformation // utilities. // // You must make sure the start_x, start_y, size_x, size_y // and rotate parameters have exactly same values as you used in // the FPDF_RenderPage() function call. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_DeviceToPage(FPDF_PAGE page, int start_x, int start_y, int size_x, int size_y, int rotate, int device_x, int device_y, double* page_x, double* page_y); // Function: FPDF_PageToDevice // Convert the page coordinates of a point to screen coordinates. // Parameters: // page - Handle to the page. Returned by FPDF_LoadPage. // start_x - Left pixel position of the display area in // device coordinates. // start_y - Top pixel position of the display area in device // coordinates. // size_x - Horizontal size (in pixels) for displaying the page. // size_y - Vertical size (in pixels) for displaying the page. // rotate - Page orientation: // 0 (normal) // 1 (rotated 90 degrees clockwise) // 2 (rotated 180 degrees) // 3 (rotated 90 degrees counter-clockwise) // page_x - X value in page coordinates. // page_y - Y value in page coordinate. // device_x - A pointer to an integer receiving the result X // value in device coordinates. // device_y - A pointer to an integer receiving the result Y // value in device coordinates. // Return value: // Returns true if the conversion succeeds, and |device_x| and // |device_y| successfully receives the converted coordinates. // Comments: // See comments for FPDF_DeviceToPage(). FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_PageToDevice(FPDF_PAGE page, int start_x, int start_y, int size_x, int size_y, int rotate, double page_x, double page_y, int* device_x, int* device_y); // Function: FPDFBitmap_Create // Create a device independent bitmap (FXDIB). // Parameters: // width - The number of pixels in width for the bitmap. // Must be greater than 0. // height - The number of pixels in height for the bitmap. // Must be greater than 0. // alpha - A flag indicating whether the alpha channel is used. // Non-zero for using alpha, zero for not using. // Return value: // The created bitmap handle, or NULL if a parameter error or out of // memory. // Comments: // The bitmap always uses 4 bytes per pixel. The first byte is always // double word aligned. // // The byte order is BGRx (the last byte unused if no alpha channel) or // BGRA. // // The pixels in a horizontal line are stored side by side, with the // left most pixel stored first (with lower memory address). // Each line uses width * 4 bytes. // // Lines are stored one after another, with the top most line stored // first. There is no gap between adjacent lines. // // This function allocates enough memory for holding all pixels in the // bitmap, but it doesn't initialize the buffer. Applications can use // FPDFBitmap_FillRect() to fill the bitmap using any color. If the OS // allows it, this function can allocate up to 4 GB of memory. FPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV FPDFBitmap_Create(int width, int height, int alpha); // More DIB formats // Unknown or unsupported format. // All of the colors are listed in order of LSB to MSB. #define FPDFBitmap_Unknown 0 // Gray scale bitmap, one byte per pixel. #define FPDFBitmap_Gray 1 // 3 bytes per pixel, byte order: blue, green, red. #define FPDFBitmap_BGR 2 // 4 bytes per pixel, byte order: blue, green, red, unused. #define FPDFBitmap_BGRx 3 // 4 bytes per pixel, byte order: blue, green, red, alpha. // Pixel components are independent of alpha. #define FPDFBitmap_BGRA 4 // 4 bytes per pixel, byte order: blue, green, red, alpha. // Pixel components are premultiplied by alpha. // Note that this is experimental and only supported when rendering with // |FPDF_RENDERER_TYPE| is set to |FPDF_RENDERERTYPE_SKIA|. #define FPDFBitmap_BGRA_Premul 5 // Function: FPDFBitmap_CreateEx // Create a device independent bitmap (FXDIB) // Parameters: // width - The number of pixels in width for the bitmap. // Must be greater than 0. // height - The number of pixels in height for the bitmap. // Must be greater than 0. // format - A number indicating for bitmap format, as defined // above. // first_scan - A pointer to the first byte of the first line if // using an external buffer. If this parameter is NULL, // then a new buffer will be created. // stride - Number of bytes for each scan line. The value must // be 0 or greater. When the value is 0, // FPDFBitmap_CreateEx() will automatically calculate // the appropriate value using |width| and |format|. // When using an external buffer, it is recommended for // the caller to pass in the value. // When not using an external buffer, it is recommended // for the caller to pass in 0. // Return value: // The bitmap handle, or NULL if parameter error or out of memory. // Comments: // Similar to FPDFBitmap_Create function, but allows for more formats // and an external buffer is supported. The bitmap created by this // function can be used in any place that a FPDF_BITMAP handle is // required. // // If an external buffer is used, then the caller should destroy the // buffer. FPDFBitmap_Destroy() will not destroy the buffer. // // It is recommended to use FPDFBitmap_GetStride() to get the stride // value. FPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV FPDFBitmap_CreateEx(int width, int height, int format, void* first_scan, int stride); // Function: FPDFBitmap_GetFormat // Get the format of the bitmap. // Parameters: // bitmap - Handle to the bitmap. Returned by FPDFBitmap_Create // or FPDFImageObj_GetBitmap. // Return value: // The format of the bitmap. // Comments: // Only formats supported by FPDFBitmap_CreateEx are supported by this // function; see the list of such formats above. FPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetFormat(FPDF_BITMAP bitmap); // Function: FPDFBitmap_FillRect // Fill a rectangle in a bitmap. // Parameters: // bitmap - The handle to the bitmap. Returned by // FPDFBitmap_Create. // left - The left position. Starting from 0 at the // left-most pixel. // top - The top position. Starting from 0 at the // top-most line. // width - Width in pixels to be filled. // height - Height in pixels to be filled. // color - A 32-bit value specifing the color, in 8888 ARGB // format. // Return value: // Returns whether the operation succeeded or not. // Comments: // This function sets the color and (optionally) alpha value in the // specified region of the bitmap. // // NOTE: If the alpha channel is used, this function does NOT // composite the background with the source color, instead the // background will be replaced by the source color and the alpha. // // If the alpha channel is not used, the alpha parameter is ignored. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFBitmap_FillRect(FPDF_BITMAP bitmap, int left, int top, int width, int height, FPDF_DWORD color); // Function: FPDFBitmap_GetBuffer // Get data buffer of a bitmap. // Parameters: // bitmap - Handle to the bitmap. Returned by FPDFBitmap_Create // or FPDFImageObj_GetBitmap. // Return value: // The pointer to the first byte of the bitmap buffer. // Comments: // The stride may be more than width * number of bytes per pixel // // Applications can use this function to get the bitmap buffer pointer, // then manipulate any color and/or alpha values for any pixels in the // bitmap. // // Use FPDFBitmap_GetFormat() to find out the format of the data. FPDF_EXPORT void* FPDF_CALLCONV FPDFBitmap_GetBuffer(FPDF_BITMAP bitmap); // Function: FPDFBitmap_GetWidth // Get width of a bitmap. // Parameters: // bitmap - Handle to the bitmap. Returned by FPDFBitmap_Create // or FPDFImageObj_GetBitmap. // Return value: // The width of the bitmap in pixels. FPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetWidth(FPDF_BITMAP bitmap); // Function: FPDFBitmap_GetHeight // Get height of a bitmap. // Parameters: // bitmap - Handle to the bitmap. Returned by FPDFBitmap_Create // or FPDFImageObj_GetBitmap. // Return value: // The height of the bitmap in pixels. FPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetHeight(FPDF_BITMAP bitmap); // Function: FPDFBitmap_GetStride // Get number of bytes for each line in the bitmap buffer. // Parameters: // bitmap - Handle to the bitmap. Returned by FPDFBitmap_Create // or FPDFImageObj_GetBitmap. // Return value: // The number of bytes for each line in the bitmap buffer. // Comments: // The stride may be more than width * number of bytes per pixel. FPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetStride(FPDF_BITMAP bitmap); // Function: FPDFBitmap_Destroy // Destroy a bitmap and release all related buffers. // Parameters: // bitmap - Handle to the bitmap. Returned by FPDFBitmap_Create // or FPDFImageObj_GetBitmap. // Return value: // None. // Comments: // This function will not destroy any external buffers provided when // the bitmap was created. FPDF_EXPORT void FPDF_CALLCONV FPDFBitmap_Destroy(FPDF_BITMAP bitmap); // Function: FPDF_VIEWERREF_GetPrintScaling // Whether the PDF document prefers to be scaled or not. // Parameters: // document - Handle to the loaded document. // Return value: // None. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_VIEWERREF_GetPrintScaling(FPDF_DOCUMENT document); // Function: FPDF_VIEWERREF_GetNumCopies // Returns the number of copies to be printed. // Parameters: // document - Handle to the loaded document. // Return value: // The number of copies to be printed. FPDF_EXPORT int FPDF_CALLCONV FPDF_VIEWERREF_GetNumCopies(FPDF_DOCUMENT document); // Function: FPDF_VIEWERREF_GetPrintPageRange // Page numbers to initialize print dialog box when file is printed. // Parameters: // document - Handle to the loaded document. // Return value: // The print page range to be used for printing. FPDF_EXPORT FPDF_PAGERANGE FPDF_CALLCONV FPDF_VIEWERREF_GetPrintPageRange(FPDF_DOCUMENT document); // Experimental API. // Function: FPDF_VIEWERREF_GetPrintPageRangeCount // Returns the number of elements in a FPDF_PAGERANGE. // Parameters: // pagerange - Handle to the page range. // Return value: // The number of elements in the page range. Returns 0 on error. FPDF_EXPORT size_t FPDF_CALLCONV FPDF_VIEWERREF_GetPrintPageRangeCount(FPDF_PAGERANGE pagerange); // Experimental API. // Function: FPDF_VIEWERREF_GetPrintPageRangeElement // Returns an element from a FPDF_PAGERANGE. // Parameters: // pagerange - Handle to the page range. // index - Index of the element. // Return value: // The value of the element in the page range at a given index. // Returns -1 on error. FPDF_EXPORT int FPDF_CALLCONV FPDF_VIEWERREF_GetPrintPageRangeElement(FPDF_PAGERANGE pagerange, size_t index); // Function: FPDF_VIEWERREF_GetDuplex // Returns the paper handling option to be used when printing from // the print dialog. // Parameters: // document - Handle to the loaded document. // Return value: // The paper handling option to be used when printing. FPDF_EXPORT FPDF_DUPLEXTYPE FPDF_CALLCONV FPDF_VIEWERREF_GetDuplex(FPDF_DOCUMENT document); // Function: FPDF_VIEWERREF_GetName // Gets the contents for a viewer ref, with a given key. The value must // be of type "name". // Parameters: // document - Handle to the loaded document. // key - Name of the key in the viewer pref dictionary, // encoded in UTF-8. // buffer - Caller-allocate buffer to receive the key, or NULL // - to query the required length. // length - Length of the buffer. // Return value: // The number of bytes in the contents, including the NULL terminator. // Thus if the return value is 0, then that indicates an error, such // as when |document| is invalid. If |length| is less than the required // length, or |buffer| is NULL, |buffer| will not be modified. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_VIEWERREF_GetName(FPDF_DOCUMENT document, FPDF_BYTESTRING key, char* buffer, unsigned long length); // Function: FPDF_CountNamedDests // Get the count of named destinations in the PDF document. // Parameters: // document - Handle to a document // Return value: // The count of named destinations. FPDF_EXPORT FPDF_DWORD FPDF_CALLCONV FPDF_CountNamedDests(FPDF_DOCUMENT document); // Function: FPDF_GetNamedDestByName // Get a the destination handle for the given name. // Parameters: // document - Handle to the loaded document. // name - The name of a destination. // Return value: // The handle to the destination. FPDF_EXPORT FPDF_DEST FPDF_CALLCONV FPDF_GetNamedDestByName(FPDF_DOCUMENT document, FPDF_BYTESTRING name); // Function: FPDF_GetNamedDest // Get the named destination by index. // Parameters: // document - Handle to a document // index - The index of a named destination. // buffer - The buffer to store the destination name, // used as wchar_t*. // buflen [in/out] - Size of the buffer in bytes on input, // length of the result in bytes on output // or -1 if the buffer is too small. // Return value: // The destination handle for a given index, or NULL if there is no // named destination corresponding to |index|. // Comments: // Call this function twice to get the name of the named destination: // 1) First time pass in |buffer| as NULL and get buflen. // 2) Second time pass in allocated |buffer| and buflen to retrieve // |buffer|, which should be used as wchar_t*. // // If buflen is not sufficiently large, it will be set to -1 upon // return. FPDF_EXPORT FPDF_DEST FPDF_CALLCONV FPDF_GetNamedDest(FPDF_DOCUMENT document, int index, void* buffer, long* buflen); // Experimental API. // Function: FPDF_GetXFAPacketCount // Get the number of valid packets in the XFA entry. // Parameters: // document - Handle to the document. // Return value: // The number of valid packets, or -1 on error. FPDF_EXPORT int FPDF_CALLCONV FPDF_GetXFAPacketCount(FPDF_DOCUMENT document); // Experimental API. // Function: FPDF_GetXFAPacketName // Get the name of a packet in the XFA array. // Parameters: // document - Handle to the document. // index - Index number of the packet. 0 for the first packet. // buffer - Buffer for holding the name of the XFA packet. // buflen - Length of |buffer| in bytes. // Return value: // The length of the packet name in bytes, or 0 on error. // // |document| must be valid and |index| must be in the range [0, N), where N is // the value returned by FPDF_GetXFAPacketCount(). // |buffer| is only modified if it is non-NULL and |buflen| is greater than or // equal to the length of the packet name. The packet name includes a // terminating NUL character. |buffer| is unmodified on error. FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetXFAPacketName( FPDF_DOCUMENT document, int index, void* buffer, unsigned long buflen); // Experimental API. // Function: FPDF_GetXFAPacketContent // Get the content of a packet in the XFA array. // Parameters: // document - Handle to the document. // index - Index number of the packet. 0 for the first packet. // buffer - Buffer for holding the content of the XFA packet. // buflen - Length of |buffer| in bytes. // out_buflen - Pointer to the variable that will receive the minimum // buffer size needed to contain the content of the XFA // packet. // Return value: // Whether the operation succeeded or not. // // |document| must be valid and |index| must be in the range [0, N), where N is // the value returned by FPDF_GetXFAPacketCount(). |out_buflen| must not be // NULL. When the aforementioned arguments are valid, the operation succeeds, // and |out_buflen| receives the content size. |buffer| is only modified if // |buffer| is non-null and long enough to contain the content. Callers must // check both the return value and the input |buflen| is no less than the // returned |out_buflen| before using the data in |buffer|. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_GetXFAPacketContent( FPDF_DOCUMENT document, int index, void* buffer, unsigned long buflen, unsigned long* out_buflen); #ifdef PDF_ENABLE_V8 // Function: FPDF_GetRecommendedV8Flags // Returns a space-separated string of command line flags that are // recommended to be passed into V8 via V8::SetFlagsFromString() // prior to initializing the PDFium library. // Parameters: // None. // Return value: // NUL-terminated string of the form "--flag1 --flag2". // The caller must not attempt to modify or free the result. FPDF_EXPORT const char* FPDF_CALLCONV FPDF_GetRecommendedV8Flags(); // Experimental API. // Function: FPDF_GetArrayBufferAllocatorSharedInstance() // Helper function for initializing V8 isolates that will // use PDFium's internal memory management. // Parameters: // None. // Return Value: // Pointer to a suitable v8::ArrayBuffer::Allocator, returned // as void for C compatibility. // Notes: // Use is optional, but allows external creation of isolates // matching the ones PDFium will make when none is provided // via |FPDF_LIBRARY_CONFIG::m_pIsolate|. // // Can only be called when the library is in an uninitialized or // destroyed state. FPDF_EXPORT void* FPDF_CALLCONV FPDF_GetArrayBufferAllocatorSharedInstance(); #endif // PDF_ENABLE_V8 #ifdef PDF_ENABLE_XFA // Function: FPDF_BStr_Init // Helper function to initialize a FPDF_BSTR. FPDF_EXPORT FPDF_RESULT FPDF_CALLCONV FPDF_BStr_Init(FPDF_BSTR* bstr); // Function: FPDF_BStr_Set // Helper function to copy string data into the FPDF_BSTR. FPDF_EXPORT FPDF_RESULT FPDF_CALLCONV FPDF_BStr_Set(FPDF_BSTR* bstr, const char* cstr, int length); // Function: FPDF_BStr_Clear // Helper function to clear a FPDF_BSTR. FPDF_EXPORT FPDF_RESULT FPDF_CALLCONV FPDF_BStr_Clear(FPDF_BSTR* bstr); #endif // PDF_ENABLE_XFA #ifdef __cplusplus } #endif #endif // PUBLIC_FPDFVIEW_H_ ================================================ FILE: external/pdfium/windows-x64/licenses/abseil.txt ================================================ Apache License Version 2.0, January 2004 https://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: external/pdfium/windows-x64/licenses/agg23.txt ================================================ //---------------------------------------------------------------------------- // Anti-Grain Geometry - Version 2.3 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) // // Permission to copy, use, modify, sell and distribute this software // is granted provided this copyright notice appears in all copies. // This software is provided "as is" without express or implied // warranty, and with no claim as to its suitability for any purpose. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- ================================================ FILE: external/pdfium/windows-x64/licenses/fast_float.txt ================================================ MIT License Copyright (c) 2021 The fast_float authors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: external/pdfium/windows-x64/licenses/freetype.txt ================================================ The FreeType Project LICENSE ---------------------------- 2006-Jan-27 Copyright 1996-2002, 2006 by David Turner, Robert Wilhelm, and Werner Lemberg Introduction ============ The FreeType Project is distributed in several archive packages; some of them may contain, in addition to the FreeType font engine, various tools and contributions which rely on, or relate to, the FreeType Project. This license applies to all files found in such packages, and which do not fall under their own explicit license. The license affects thus the FreeType font engine, the test programs, documentation and makefiles, at the very least. This license was inspired by the BSD, Artistic, and IJG (Independent JPEG Group) licenses, which all encourage inclusion and use of free software in commercial and freeware products alike. As a consequence, its main points are that: o We don't promise that this software works. However, we will be interested in any kind of bug reports. (`as is' distribution) o You can use this software for whatever you want, in parts or full form, without having to pay us. (`royalty-free' usage) o You may not pretend that you wrote this software. If you use it, or only parts of it, in a program, you must acknowledge somewhere in your documentation that you have used the FreeType code. (`credits') We specifically permit and encourage the inclusion of this software, with or without modifications, in commercial products. We disclaim all warranties covering The FreeType Project and assume no liability related to The FreeType Project. Finally, many people asked us for a preferred form for a credit/disclaimer to use in compliance with this license. We thus encourage you to use the following text: """ Portions of this software are copyright The FreeType Project (www.freetype.org). All rights reserved. """ Please replace with the value from the FreeType version you actually use. Legal Terms =========== 0. Definitions -------------- Throughout this license, the terms `package', `FreeType Project', and `FreeType archive' refer to the set of files originally distributed by the authors (David Turner, Robert Wilhelm, and Werner Lemberg) as the `FreeType Project', be they named as alpha, beta or final release. `You' refers to the licensee, or person using the project, where `using' is a generic term including compiling the project's source code as well as linking it to form a `program' or `executable'. This program is referred to as `a program using the FreeType engine'. This license applies to all files distributed in the original FreeType Project, including all source code, binaries and documentation, unless otherwise stated in the file in its original, unmodified form as distributed in the original archive. If you are unsure whether or not a particular file is covered by this license, you must contact us to verify this. The FreeType Project is copyright (C) 1996-2000 by David Turner, Robert Wilhelm, and Werner Lemberg. All rights reserved except as specified below. 1. No Warranty -------------- THE FREETYPE PROJECT IS PROVIDED `AS IS' WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL ANY OF THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY DAMAGES CAUSED BY THE USE OR THE INABILITY TO USE, OF THE FREETYPE PROJECT. 2. Redistribution ----------------- This license grants a worldwide, royalty-free, perpetual and irrevocable right and license to use, execute, perform, compile, display, copy, create derivative works of, distribute and sublicense the FreeType Project (in both source and object code forms) and derivative works thereof for any purpose; and to authorize others to exercise some or all of the rights granted herein, subject to the following conditions: o Redistribution of source code must retain this license file (`FTL.TXT') unaltered; any additions, deletions or changes to the original files must be clearly indicated in accompanying documentation. The copyright notices of the unaltered, original files must be preserved in all copies of source files. o Redistribution in binary form must provide a disclaimer that states that the software is based in part of the work of the FreeType Team, in the distribution documentation. We also encourage you to put an URL to the FreeType web page in your documentation, though this isn't mandatory. These conditions apply to any software derived from or based on the FreeType Project, not just the unmodified files. If you use our work, you must acknowledge us. However, no fee need be paid to us. 3. Advertising -------------- Neither the FreeType authors and contributors nor you shall use the name of the other for commercial, advertising, or promotional purposes without specific prior written permission. We suggest, but do not require, that you use one or more of the following phrases to refer to this software in your documentation or advertising materials: `FreeType Project', `FreeType Engine', `FreeType library', or `FreeType Distribution'. As you have not signed this license, you are not required to accept it. However, as the FreeType Project is copyrighted material, only this license, or another one contracted with the authors, grants you the right to use, distribute, and modify it. Therefore, by using, distributing, or modifying the FreeType Project, you indicate that you understand and accept all the terms of this license. 4. Contacts ----------- There are two mailing lists related to FreeType: o freetype@nongnu.org Discusses general use and applications of FreeType, as well as future and wanted additions to the library and distribution. If you are looking for support, start in this list if you haven't found anything to help you in the documentation. o freetype-devel@nongnu.org Discusses bugs, as well as engine internals, design issues, specific licenses, porting, etc. Our home page can be found at http://www.freetype.org --- end of FTL.TXT --- ================================================ FILE: external/pdfium/windows-x64/licenses/icu.txt ================================================ UNICODE LICENSE V3 COPYRIGHT AND PERMISSION NOTICE Copyright © 2016-2025 Unicode, Inc. NOTICE TO USER: Carefully read the following legal agreement. BY DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING DATA FILES, AND/OR SOFTWARE, YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE TERMS AND CONDITIONS OF THIS AGREEMENT. IF YOU DO NOT AGREE, DO NOT DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE THE DATA FILES OR SOFTWARE. Permission is hereby granted, free of charge, to any person obtaining a copy of data files and any associated documentation (the "Data Files") or software and any associated documentation (the "Software") to deal in the Data Files or Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, and/or sell copies of the Data Files or Software, and to permit persons to whom the Data Files or Software are furnished to do so, provided that either (a) this copyright and permission notice appear with all copies of the Data Files or Software, or (b) this copyright and permission notice appear in associated Documentation. THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE DATA FILES OR SOFTWARE. Except as contained in this notice, the name of a copyright holder shall not be used in advertising or otherwise to promote the sale, use or other dealings in these Data Files or Software without prior written authorization of the copyright holder. SPDX-License-Identifier: Unicode-3.0 ---------------------------------------------------------------------- Third-Party Software Licenses This section contains third-party software notices and/or additional terms for licensed third-party software components included within ICU libraries. ---------------------------------------------------------------------- ICU License - ICU 1.8.1 to ICU 57.1 COPYRIGHT AND PERMISSION NOTICE Copyright (c) 1995-2016 International Business Machines Corporation and others All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, provided that the above copyright notice(s) and this permission notice appear in all copies of the Software and that both the above copyright notice(s) and this permission notice appear in supporting documentation. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. Except as contained in this notice, the name of a copyright holder shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization of the copyright holder. All trademarks and registered trademarks mentioned herein are the property of their respective owners. ---------------------------------------------------------------------- Chinese/Japanese Word Break Dictionary Data (cjdict.txt) # The Google Chrome software developed by Google is licensed under # the BSD license. Other software included in this distribution is # provided under other licenses, as set forth below. # # The BSD License # http://opensource.org/licenses/bsd-license.php # Copyright (C) 2006-2008, Google Inc. # # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # Redistributions of source code must retain the above copyright notice, # this list of conditions and the following disclaimer. # Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided with # the distribution. # Neither the name of Google Inc. nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. # # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND # CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR # BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # # The word list in cjdict.txt are generated by combining three word lists # listed below with further processing for compound word breaking. The # frequency is generated with an iterative training against Google web # corpora. # # * Libtabe (Chinese) # - https://sourceforge.net/project/?group_id=1519 # - Its license terms and conditions are shown below. # # * IPADIC (Japanese) # - http://chasen.aist-nara.ac.jp/chasen/distribution.html # - Its license terms and conditions are shown below. # # ---------COPYING.libtabe ---- BEGIN-------------------- # # /* # * Copyright (c) 1999 TaBE Project. # * Copyright (c) 1999 Pai-Hsiang Hsiao. # * All rights reserved. # * # * Redistribution and use in source and binary forms, with or without # * modification, are permitted provided that the following conditions # * are met: # * # * . Redistributions of source code must retain the above copyright # * notice, this list of conditions and the following disclaimer. # * . Redistributions in binary form must reproduce the above copyright # * notice, this list of conditions and the following disclaimer in # * the documentation and/or other materials provided with the # * distribution. # * . Neither the name of the TaBE Project nor the names of its # * contributors may be used to endorse or promote products derived # * from this software without specific prior written permission. # * # * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # * REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES # * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR # * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, # * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED # * OF THE POSSIBILITY OF SUCH DAMAGE. # */ # # /* # * Copyright (c) 1999 Computer Systems and Communication Lab, # * Institute of Information Science, Academia # * Sinica. All rights reserved. # * # * Redistribution and use in source and binary forms, with or without # * modification, are permitted provided that the following conditions # * are met: # * # * . Redistributions of source code must retain the above copyright # * notice, this list of conditions and the following disclaimer. # * . Redistributions in binary form must reproduce the above copyright # * notice, this list of conditions and the following disclaimer in # * the documentation and/or other materials provided with the # * distribution. # * . Neither the name of the Computer Systems and Communication Lab # * nor the names of its contributors may be used to endorse or # * promote products derived from this software without specific # * prior written permission. # * # * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # * REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES # * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR # * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, # * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED # * OF THE POSSIBILITY OF SUCH DAMAGE. # */ # # Copyright 1996 Chih-Hao Tsai @ Beckman Institute, # University of Illinois # c-tsai4@uiuc.edu http://casper.beckman.uiuc.edu/~c-tsai4 # # ---------------COPYING.libtabe-----END-------------------------------- # # # ---------------COPYING.ipadic-----BEGIN------------------------------- # # Copyright 2000, 2001, 2002, 2003 Nara Institute of Science # and Technology. All Rights Reserved. # # Use, reproduction, and distribution of this software is permitted. # Any copy of this software, whether in its original form or modified, # must include both the above copyright notice and the following # paragraphs. # # Nara Institute of Science and Technology (NAIST), # the copyright holders, disclaims all warranties with regard to this # software, including all implied warranties of merchantability and # fitness, in no event shall NAIST be liable for # any special, indirect or consequential damages or any damages # whatsoever resulting from loss of use, data or profits, whether in an # action of contract, negligence or other tortuous action, arising out # of or in connection with the use or performance of this software. # # A large portion of the dictionary entries # originate from ICOT Free Software. The following conditions for ICOT # Free Software applies to the current dictionary as well. # # Each User may also freely distribute the Program, whether in its # original form or modified, to any third party or parties, PROVIDED # that the provisions of Section 3 ("NO WARRANTY") will ALWAYS appear # on, or be attached to, the Program, which is distributed substantially # in the same form as set out herein and that such intended # distribution, if actually made, will neither violate or otherwise # contravene any of the laws and regulations of the countries having # jurisdiction over the User or the intended distribution itself. # # NO WARRANTY # # The program was produced on an experimental basis in the course of the # research and development conducted during the project and is provided # to users as so produced on an experimental basis. Accordingly, the # program is provided without any warranty whatsoever, whether express, # implied, statutory or otherwise. The term "warranty" used herein # includes, but is not limited to, any warranty of the quality, # performance, merchantability and fitness for a particular purpose of # the program and the nonexistence of any infringement or violation of # any right of any third party. # # Each user of the program will agree and understand, and be deemed to # have agreed and understood, that there is no warranty whatsoever for # the program and, accordingly, the entire risk arising from or # otherwise connected with the program is assumed by the user. # # Therefore, neither ICOT, the copyright holder, or any other # organization that participated in or was otherwise related to the # development of the program and their respective officials, directors, # officers and other employees shall be held liable for any and all # damages, including, without limitation, general, special, incidental # and consequential damages, arising out of or otherwise in connection # with the use or inability to use the program or any product, material # or result produced or otherwise obtained by using the program, # regardless of whether they have been advised of, or otherwise had # knowledge of, the possibility of such damages at any time during the # project or thereafter. Each user will be deemed to have agreed to the # foregoing by his or her commencement of use of the program. The term # "use" as used herein includes, but is not limited to, the use, # modification, copying and distribution of the program and the # production of secondary products from the program. # # In the case where the program, whether in its original form or # modified, was distributed or delivered to or received by a user from # any person, organization or entity other than ICOT, unless it makes or # grants independently of ICOT any specific warranty to the user in # writing, such person, organization or entity, will also be exempted # from and not be held liable to the user for any such damages as noted # above as far as the program is concerned. # # ---------------COPYING.ipadic-----END---------------------------------- ---------------------------------------------------------------------- Lao Word Break Dictionary Data (laodict.txt) # Copyright (C) 2016 and later: Unicode, Inc. and others. # License & terms of use: http://www.unicode.org/copyright.html # Copyright (c) 2015 International Business Machines Corporation # and others. All Rights Reserved. # # Project: https://github.com/rober42539/lao-dictionary # Dictionary: https://github.com/rober42539/lao-dictionary/laodict.txt # License: https://github.com/rober42539/lao-dictionary/LICENSE.txt # (copied below) # # This file is derived from the above dictionary version of Nov 22, 2020 # ---------------------------------------------------------------------- # Copyright (C) 2013 Brian Eugene Wilson, Robert Martin Campbell. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # Redistributions of source code must retain the above copyright notice, this # list of conditions and the following disclaimer. Redistributions in binary # form must reproduce the above copyright notice, this list of conditions and # the following disclaimer in the documentation and/or other materials # provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, # INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED # OF THE POSSIBILITY OF SUCH DAMAGE. # -------------------------------------------------------------------------- ---------------------------------------------------------------------- Burmese Word Break Dictionary Data (burmesedict.txt) # Copyright (c) 2014 International Business Machines Corporation # and others. All Rights Reserved. # # This list is part of a project hosted at: # github.com/kanyawtech/myanmar-karen-word-lists # # -------------------------------------------------------------------------- # Copyright (c) 2013, LeRoy Benjamin Sharon # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: Redistributions of source code must retain the above # copyright notice, this list of conditions and the following # disclaimer. Redistributions in binary form must reproduce the # above copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # # Neither the name Myanmar Karen Word Lists, nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND # CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED # TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR # TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF # THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # -------------------------------------------------------------------------- ---------------------------------------------------------------------- Time Zone Database ICU uses the public domain data and code derived from Time Zone Database for its time zone support. The ownership of the TZ database is explained in BCP 175: Procedure for Maintaining the Time Zone Database section 7. # 7. Database Ownership # # The TZ database itself is not an IETF Contribution or an IETF # document. Rather it is a pre-existing and regularly updated work # that is in the public domain, and is intended to remain in the # public domain. Therefore, BCPs 78 [RFC5378] and 79 [RFC3979] do # not apply to the TZ Database or contributions that individuals make # to it. Should any claims be made and substantiated against the TZ # Database, the organization that is providing the IANA # Considerations defined in this RFC, under the memorandum of # understanding with the IETF, currently ICANN, may act in accordance # with all competent court orders. No ownership claims will be made # by ICANN or the IETF Trust on the database or the code. Any person # making a contribution to the database or code waives all rights to # future claims in that contribution or in the TZ Database. ---------------------------------------------------------------------- Google double-conversion Copyright 2006-2011, the V8 project authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Google Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- JSON parsing library (nlohmann/json) File: vendor/json/upstream/single_include/nlohmann/json.hpp (only for ICU4C) MIT License Copyright (c) 2013-2022 Niels Lohmann Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ---------------------------------------------------------------------- File: aclocal.m4 (only for ICU4C) Section: pkg.m4 - Macros to locate and utilise pkg-config. Copyright © 2004 Scott James Remnant . Copyright © 2012-2015 Dan Nicholson 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 2 of the License, or (at your option) 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. As a special exception to the GNU General Public License, if you distribute this file as part of a program that contains a configuration script generated by Autoconf, you may include it under the same distribution terms that you use for the rest of that program. (The condition for the exception is fulfilled because ICU4C includes a configuration script generated by Autoconf, namely the `configure` script.) ---------------------------------------------------------------------- File: config.guess (only for ICU4C) This file 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 (at your option) 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, see . As a special exception to the GNU General Public License, if you distribute this file as part of a program that contains a configuration script generated by Autoconf, you may include it under the same distribution terms that you use for the rest of that program. This Exception is an additional permission under section 7 of the GNU General Public License, version 3 ("GPLv3"). (The condition for the exception is fulfilled because ICU4C includes a configuration script generated by Autoconf, namely the `configure` script.) ---------------------------------------------------------------------- File: install-sh (only for ICU4C) Copyright 1991 by the Massachusetts Institute of Technology Permission to use, copy, modify, distribute, and sell this software and its documentation for any purpose is hereby granted without fee, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the name of M.I.T. not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. M.I.T. makes no representations about the suitability of this software for any purpose. It is provided "as is" without express or implied warranty. ================================================ FILE: external/pdfium/windows-x64/licenses/lcms.txt ================================================ //--------------------------------------------------------------------------------- // // Little Color Management System // Copyright (c) 1998-2023 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), // to deal in the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the Software // is furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO // THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // //--------------------------------------------------------------------------------- // // Version 2.15 // ================================================ FILE: external/pdfium/windows-x64/licenses/libjpeg_turbo.ijg ================================================ libjpeg-turbo note: This file has been modified by The libjpeg-turbo Project to include only information relevant to libjpeg-turbo, to wordsmith certain sections, and to remove impolitic language that existed in the libjpeg v8 README. It is included only for reference. Please see README.md for information specific to libjpeg-turbo. The Independent JPEG Group's JPEG software ========================================== This distribution contains a release of the Independent JPEG Group's free JPEG software. You are welcome to redistribute this software and to use it for any purpose, subject to the conditions under LEGAL ISSUES, below. This software is the work of Tom Lane, Guido Vollbeding, Philip Gladstone, Bill Allombert, Jim Boucher, Lee Crocker, Bob Friesenhahn, Ben Jackson, Julian Minguillon, Luis Ortiz, George Phillips, Davide Rossi, Ge' Weijers, and other members of the Independent JPEG Group. IJG is not affiliated with the ISO/IEC JTC1/SC29/WG1 standards committee (also known as JPEG, together with ITU-T SG16). DOCUMENTATION ROADMAP ===================== This file contains the following sections: OVERVIEW General description of JPEG and the IJG software. LEGAL ISSUES Copyright, lack of warranty, terms of distribution. REFERENCES Where to learn more about JPEG. ARCHIVE LOCATIONS Where to find newer versions of this software. FILE FORMAT WARS Software *not* to get. TO DO Plans for future IJG releases. Other documentation files in the distribution are: User documentation: doc/usage.txt Usage instructions for cjpeg, djpeg, jpegtran, rdjpgcom, and wrjpgcom. doc/*.1 Unix-style man pages for programs (same info as usage.txt). doc/wizard.txt Advanced usage instructions for JPEG wizards only. doc/change.log Version-to-version change highlights. Programmer and internal documentation: doc/libjpeg.txt How to use the JPEG library in your own programs. src/example.c Sample code for calling the JPEG library. doc/structure.txt Overview of the JPEG library's internal structure. doc/coderules.txt Coding style rules --- please read if you contribute code. Please read at least usage.txt. Some information can also be found in the JPEG FAQ (Frequently Asked Questions) article. See ARCHIVE LOCATIONS below to find out where to obtain the FAQ article. If you want to understand how the JPEG code works, we suggest reading one or more of the REFERENCES, then looking at the documentation files (in roughly the order listed) before diving into the code. OVERVIEW ======== This package contains C software to implement JPEG image encoding, decoding, and transcoding. JPEG (pronounced "jay-peg") is a standardized compression method for full-color and grayscale images. JPEG's strong suit is compressing photographic images or other types of images that have smooth color and brightness transitions between neighboring pixels. Images with sharp lines or other abrupt features may not compress well with JPEG, and a higher JPEG quality may have to be used to avoid visible compression artifacts with such images. JPEG is normally lossy, meaning that the output pixels are not necessarily identical to the input pixels. However, on photographic content and other "smooth" images, very good compression ratios can be obtained with no visible compression artifacts, and extremely high compression ratios are possible if you are willing to sacrifice image quality (by reducing the "quality" setting in the compressor.) This software implements JPEG baseline, extended-sequential, progressive, and lossless compression processes. Provision is made for supporting all variants of these processes, although some uncommon parameter settings aren't implemented yet. We have made no provision for supporting the hierarchical processes defined in the standard. We provide a set of library routines for reading and writing JPEG image files, plus two sample applications "cjpeg" and "djpeg", which use the library to perform conversion between JPEG and some other popular image file formats. The library is intended to be reused in other applications. In order to support file conversion and viewing software, we have included considerable functionality beyond the bare JPEG coding/decoding capability; for example, the color quantization modules are not strictly part of JPEG decoding, but they are essential for output to colormapped file formats. These extra functions can be compiled out of the library if not required for a particular application. We have also included "jpegtran", a utility for lossless transcoding between different JPEG processes, and "rdjpgcom" and "wrjpgcom", two simple applications for inserting and extracting textual comments in JFIF files. The emphasis in designing this software has been on achieving portability and flexibility, while also making it fast enough to be useful. In particular, the software is not intended to be read as a tutorial on JPEG. (See the REFERENCES section for introductory material.) Rather, it is intended to be reliable, portable, industrial-strength code. We do not claim to have achieved that goal in every aspect of the software, but we strive for it. We welcome the use of this software as a component of commercial products. No royalty is required, but we do ask for an acknowledgement in product documentation, as described under LEGAL ISSUES. LEGAL ISSUES ============ In plain English: 1. We don't promise that this software works. (But if you find any bugs, please let us know!) 2. You can use this software for whatever you want. You don't have to pay us. 3. You may not pretend that you wrote this software. If you use it in a program, you must acknowledge somewhere in your documentation that you've used the IJG code. In legalese: The authors make NO WARRANTY or representation, either express or implied, with respect to this software, its quality, accuracy, merchantability, or fitness for a particular purpose. This software is provided "AS IS", and you, its user, assume the entire risk as to its quality and accuracy. This software is copyright (C) 1991-2020, Thomas G. Lane, Guido Vollbeding. All Rights Reserved except as specified below. Permission is hereby granted to use, copy, modify, and distribute this software (or portions thereof) for any purpose, without fee, subject to these conditions: (1) If any part of the source code for this software is distributed, then this README file must be included, with this copyright and no-warranty notice unaltered; and any additions, deletions, or changes to the original files must be clearly indicated in accompanying documentation. (2) If only executable code is distributed, then the accompanying documentation must state that "this software is based in part on the work of the Independent JPEG Group". (3) Permission for use of this software is granted only if the user accepts full responsibility for any undesirable consequences; the authors accept NO LIABILITY for damages of any kind. These conditions apply to any software derived from or based on the IJG code, not just to the unmodified library. If you use our work, you ought to acknowledge us. Permission is NOT granted for the use of any IJG author's name or company name in advertising or publicity relating to this software or products derived from it. This software may be referred to only as "the Independent JPEG Group's software". We specifically permit and encourage the use of this software as the basis of commercial products, provided that all warranty or liability claims are assumed by the product vendor. REFERENCES ========== We recommend reading one or more of these references before trying to understand the innards of the JPEG software. The best short technical introduction to the JPEG compression algorithm is Wallace, Gregory K. "The JPEG Still Picture Compression Standard", Communications of the ACM, April 1991 (vol. 34 no. 4), pp. 30-44. (Adjacent articles in that issue discuss MPEG motion picture compression, applications of JPEG, and related topics.) If you don't have the CACM issue handy, a PDF file containing a revised version of Wallace's article is available at http://www.ijg.org/files/Wallace.JPEG.pdf. The file (actually a preprint for an article that appeared in IEEE Trans. Consumer Electronics) omits the sample images that appeared in CACM, but it includes corrections and some added material. Note: the Wallace article is copyright ACM and IEEE, and it may not be used for commercial purposes. A somewhat less technical, more leisurely introduction to JPEG can be found in "The Data Compression Book" by Mark Nelson and Jean-loup Gailly, published by M&T Books (New York), 2nd ed. 1996, ISBN 1-55851-434-1. This book provides good explanations and example C code for a multitude of compression methods including JPEG. It is an excellent source if you are comfortable reading C code but don't know much about data compression in general. The book's JPEG sample code is far from industrial-strength, but when you are ready to look at a full implementation, you've got one here... The best currently available description of JPEG is the textbook "JPEG Still Image Data Compression Standard" by William B. Pennebaker and Joan L. Mitchell, published by Van Nostrand Reinhold, 1993, ISBN 0-442-01272-1. Price US$59.95, 638 pp. The book includes the complete text of the ISO JPEG standards (DIS 10918-1 and draft DIS 10918-2). The original JPEG standard is divided into two parts, Part 1 being the actual specification, while Part 2 covers compliance testing methods. Part 1 is titled "Digital Compression and Coding of Continuous-tone Still Images, Part 1: Requirements and guidelines" and has document numbers ISO/IEC IS 10918-1, ITU-T T.81. Part 2 is titled "Digital Compression and Coding of Continuous-tone Still Images, Part 2: Compliance testing" and has document numbers ISO/IEC IS 10918-2, ITU-T T.83. The JPEG standard does not specify all details of an interchangeable file format. For the omitted details, we follow the "JFIF" conventions, revision 1.02. JFIF version 1 has been adopted as ISO/IEC 10918-5 (05/2013) and Recommendation ITU-T T.871 (05/2011): Information technology - Digital compression and coding of continuous-tone still images: JPEG File Interchange Format (JFIF). It is available as a free download in PDF file format from https://www.iso.org/standard/54989.html and http://www.itu.int/rec/T-REC-T.871. A PDF file of the older JFIF 1.02 specification is available at http://www.w3.org/Graphics/JPEG/jfif3.pdf. The TIFF 6.0 file format specification can be obtained from http://mirrors.ctan.org/graphics/tiff/TIFF6.ps.gz. The JPEG incorporation scheme found in the TIFF 6.0 spec of 3-June-92 has a number of serious problems. IJG does not recommend use of the TIFF 6.0 design (TIFF Compression tag 6). Instead, we recommend the JPEG design proposed by TIFF Technical Note #2 (Compression tag 7). Copies of this Note can be obtained from http://www.ijg.org/files/. It is expected that the next revision of the TIFF spec will replace the 6.0 JPEG design with the Note's design. Although IJG's own code does not support TIFF/JPEG, the free libtiff library uses our library to implement TIFF/JPEG per the Note. ARCHIVE LOCATIONS ================= The "official" archive site for this software is www.ijg.org. The most recent released version can always be found there in directory "files". The JPEG FAQ (Frequently Asked Questions) article is a source of some general information about JPEG. It is available at http://www.faqs.org/faqs/jpeg-faq. FILE FORMAT COMPATIBILITY ========================= This software implements ITU T.81 | ISO/IEC 10918 with some extensions from ITU T.871 | ISO/IEC 10918-5 (JPEG File Interchange Format-- see REFERENCES). Informally, the term "JPEG image" or "JPEG file" most often refers to JFIF or a subset thereof, but there are other formats containing the name "JPEG" that are incompatible with the original JPEG standard or with JFIF (for instance, JPEG 2000 and JPEG XR). This software therefore does not support these formats. Indeed, one of the original reasons for developing this free software was to help force convergence on a common, interoperable format standard for JPEG files. JFIF is a minimal or "low end" representation. TIFF/JPEG (TIFF revision 6.0 as modified by TIFF Technical Note #2) can be used for "high end" applications that need to record a lot of additional data about an image. TO DO ===== Please send bug reports, offers of help, etc. to jpeg-info@jpegclub.org. ================================================ FILE: external/pdfium/windows-x64/licenses/libjpeg_turbo.md ================================================ libjpeg-turbo Licenses ====================== libjpeg-turbo is covered by two compatible BSD-style open source licenses: - The IJG (Independent JPEG Group) License, which is listed in [README.ijg](README.ijg) This license applies to the libjpeg API library and associated programs, including any code inherited from libjpeg and any modifications to that code. Note that the libjpeg-turbo SIMD source code bears the [zlib License](https://opensource.org/licenses/Zlib), but in the context of the overall libjpeg API library, the terms of the zlib License are subsumed by the terms of the IJG License. - The Modified (3-clause) BSD License, which is listed below This license applies to the TurboJPEG API library and associated programs, as well as the build system. Note that the TurboJPEG API library wraps the libjpeg API library, so in the context of the overall TurboJPEG API library, both the terms of the IJG License and the terms of the Modified (3-clause) BSD License apply. Complying with the libjpeg-turbo Licenses ========================================= This section provides a roll-up of the libjpeg-turbo licensing terms, to the best of our understanding. This is not a license in and of itself. It is intended solely for clarification. 1. If you are distributing a modified version of the libjpeg-turbo source, then: 1. You cannot alter or remove any existing copyright or license notices from the source. **Origin** - Clause 1 of the IJG License - Clause 1 of the Modified BSD License - Clauses 1 and 3 of the zlib License 2. You must add your own copyright notice to the header of each source file you modified, so others can tell that you modified that file. (If there is not an existing copyright header in that file, then you can simply add a notice stating that you modified the file.) **Origin** - Clause 1 of the IJG License - Clause 2 of the zlib License 3. You must include the IJG README file, and you must not alter any of the copyright or license text in that file. **Origin** - Clause 1 of the IJG License 2. If you are distributing only libjpeg-turbo binaries without the source, or if you are distributing an application that statically links with libjpeg-turbo, then: 1. Your product documentation must include a message stating: This software is based in part on the work of the Independent JPEG Group. **Origin** - Clause 2 of the IJG license 2. If your binary distribution includes or uses the TurboJPEG API, then your product documentation must include the text of the Modified BSD License (see below.) **Origin** - Clause 2 of the Modified BSD License 3. You cannot use the name of the IJG or The libjpeg-turbo Project or the contributors thereof in advertising, publicity, etc. **Origin** - IJG License - Clause 3 of the Modified BSD License 4. The IJG and The libjpeg-turbo Project do not warrant libjpeg-turbo to be free of defects, nor do we accept any liability for undesirable consequences resulting from your use of the software. **Origin** - IJG License - Modified BSD License - zlib License The Modified (3-clause) BSD License =================================== Copyright (C)2009-2024 D. R. Commander. All Rights Reserved.
Copyright (C)2015 Viktor Szathmáry. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - Neither the name of the libjpeg-turbo Project nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Why Two Licenses? ================= The zlib License could have been used instead of the Modified (3-clause) BSD License, and since the IJG License effectively subsumes the distribution conditions of the zlib License, this would have effectively placed libjpeg-turbo binary distributions under the IJG License. However, the IJG License specifically refers to the Independent JPEG Group and does not extend attribution and endorsement protections to other entities. Thus, it was desirable to choose a license that granted us the same protections for new code that were granted to the IJG for code derived from their software. ================================================ FILE: external/pdfium/windows-x64/licenses/libopenjpeg.txt ================================================ /* * The copyright in this software is being made available under the 2-clauses * BSD License, included below. This software may be subject to other third * party and contributor rights, including patent rights, and no such rights * are granted under this license. * * Copyright (c) 2005, Herve Drolon, FreeImage Team * Copyright (c) 2008, 2011-2012, Centre National d'Etudes Spatiales (CNES), FR * Copyright (c) 2012, CS Systemes d'Information, France * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ ================================================ FILE: external/pdfium/windows-x64/licenses/libpng.txt ================================================ COPYRIGHT NOTICE, DISCLAIMER, and LICENSE ========================================= PNG Reference Library License version 2 --------------------------------------- * Copyright (c) 1995-2019 The PNG Reference Library Authors. * Copyright (c) 2018-2019 Cosmin Truta. * Copyright (c) 2000-2002, 2004, 2006-2018 Glenn Randers-Pehrson. * Copyright (c) 1996-1997 Andreas Dilger. * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. The software is supplied "as is", without warranty of any kind, express or implied, including, without limitation, the warranties of merchantability, fitness for a particular purpose, title, and non-infringement. In no event shall the Copyright owners, or anyone distributing the software, be liable for any damages or other liability, whether in contract, tort or otherwise, arising from, out of, or in connection with the software, or the use or other dealings in the software, even if advised of the possibility of such damage. Permission is hereby granted to use, copy, modify, and distribute this software, or portions hereof, for any purpose, without fee, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated, but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This Copyright notice may not be removed or altered from any source or altered source distribution. PNG Reference Library License version 1 (for libpng 0.5 through 1.6.35) ----------------------------------------------------------------------- libpng versions 1.0.7, July 1, 2000, through 1.6.35, July 15, 2018 are Copyright (c) 2000-2002, 2004, 2006-2018 Glenn Randers-Pehrson, are derived from libpng-1.0.6, and are distributed according to the same disclaimer and license as libpng-1.0.6 with the following individuals added to the list of Contributing Authors: Simon-Pierre Cadieux Eric S. Raymond Mans Rullgard Cosmin Truta Gilles Vollant James Yu Mandar Sahastrabuddhe Google Inc. Vadim Barkov and with the following additions to the disclaimer: There is no warranty against interference with your enjoyment of the library or against infringement. There is no warranty that our efforts or the library will fulfill any of your particular purposes or needs. This library is provided with all faults, and the entire risk of satisfactory quality, performance, accuracy, and effort is with the user. Some files in the "contrib" directory and some configure-generated files that are distributed with libpng have other copyright owners, and are released under other open source licenses. libpng versions 0.97, January 1998, through 1.0.6, March 20, 2000, are Copyright (c) 1998-2000 Glenn Randers-Pehrson, are derived from libpng-0.96, and are distributed according to the same disclaimer and license as libpng-0.96, with the following individuals added to the list of Contributing Authors: Tom Lane Glenn Randers-Pehrson Willem van Schaik libpng versions 0.89, June 1996, through 0.96, May 1997, are Copyright (c) 1996-1997 Andreas Dilger, are derived from libpng-0.88, and are distributed according to the same disclaimer and license as libpng-0.88, with the following individuals added to the list of Contributing Authors: John Bowler Kevin Bracey Sam Bushell Magnus Holmgren Greg Roelofs Tom Tanner Some files in the "scripts" directory have other copyright owners, but are released under this license. libpng versions 0.5, May 1995, through 0.88, January 1996, are Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. For the purposes of this copyright and license, "Contributing Authors" is defined as the following set of individuals: Andreas Dilger Dave Martindale Guy Eric Schalnat Paul Schmidt Tim Wegner The PNG Reference Library is supplied "AS IS". The Contributing Authors and Group 42, Inc. disclaim all warranties, expressed or implied, including, without limitation, the warranties of merchantability and of fitness for any purpose. The Contributing Authors and Group 42, Inc. assume no liability for direct, indirect, incidental, special, exemplary, or consequential damages, which may result from the use of the PNG Reference Library, even if advised of the possibility of such damage. Permission is hereby granted to use, copy, modify, and distribute this source code, or portions hereof, for any purpose, without fee, subject to the following restrictions: 1. The origin of this source code must not be misrepresented. 2. Altered versions must be plainly marked as such and must not be misrepresented as being the original source. 3. This Copyright notice may not be removed or altered from any source or altered source distribution. The Contributing Authors and Group 42, Inc. specifically permit, without fee, and encourage the use of this source code as a component to supporting the PNG file format in commercial products. If you use this source code in a product, acknowledgment is not required but would be appreciated. ================================================ FILE: external/pdfium/windows-x64/licenses/libtiff.txt ================================================ Copyright (c) 1988-1997 Sam Leffler Copyright (c) 1991-1997 Silicon Graphics, Inc. Permission to use, copy, modify, distribute, and sell this software and its documentation for any purpose is hereby granted without fee, provided that (i) the above copyright notices and this permission notice appear in all copies of the software and related documentation, and (ii) the names of Sam Leffler and Silicon Graphics may not be used in any advertising or publicity relating to the software without the specific, prior written permission of Sam Leffler and Silicon Graphics. THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ================================================ FILE: external/pdfium/windows-x64/licenses/llvm-libc.txt ================================================ ============================================================================== The LLVM Project is under the Apache License v2.0 with LLVM Exceptions: ============================================================================== Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ---- LLVM Exceptions to the Apache 2.0 License ---- As an exception, if, as a result of your compiling your source code, portions of this Software are embedded into an Object form of such source code, you may redistribute such embedded portions in such Object form without complying with the conditions of Sections 4(a), 4(b) and 4(d) of the License. In addition, if you combine or link compiled forms of this Software with software that is licensed under the GPLv2 ("Combined Software") and if a court of competent jurisdiction determines that the patent provision (Section 3), the indemnity provision (Section 9) or other Section of the License conflicts with the conditions of the GPLv2, you may retroactively and prospectively choose to deem waived or otherwise exclude such Section(s) of the License, but only in their entirety and only with respect to the Combined Software. ============================================================================== Software from third parties included in the LLVM Project: ============================================================================== The LLVM Project contains third party software which is under different license terms. All such code will be identified clearly using at least one of two mechanisms: 1) It will be in a separate directory tree with its own `LICENSE.txt` or `LICENSE` file at the top containing the specific license and restrictions which apply to that software, or 2) It will contain specific license and restriction terms at the top of every file. ============================================================================== Legacy LLVM License (https://llvm.org/docs/DeveloperPolicy.html#legacy): ============================================================================== University of Illinois/NCSA Open Source License Copyright (c) 2007-2019 University of Illinois at Urbana-Champaign. All rights reserved. Developed by: LLVM Team University of Illinois at Urbana-Champaign http://llvm.org Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal with the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimers. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimers in the documentation and/or other materials provided with the distribution. * Neither the names of the LLVM Team, University of Illinois at Urbana-Champaign, nor the names of its contributors may be used to endorse or promote products derived from this Software without specific prior written permission. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE. ================================================ FILE: external/pdfium/windows-x64/licenses/pdfium.txt ================================================ Copyright 2014 The PDFium Authors Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Google Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Apache License Version 2.0, January 2004 https://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: external/pdfium/windows-x64/licenses/simdutf.txt ================================================ Copyright 2021 The simdutf authors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: external/pdfium/windows-x64/licenses/zlib.txt ================================================ /* zlib.h -- interface of the 'zlib' general purpose compression library version 1.3.1, January 22nd, 2024 Copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. Jean-loup Gailly Mark Adler jloup@gzip.org madler@alumni.caltech.edu The data format used by the zlib library is described by RFCs (Request for Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950 (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format). */ ================================================ FILE: external/pugixml/CMakeLists.txt ================================================ cmake_minimum_required(VERSION 3.5...3.30) # Policy configuration; this *MUST* be specified before project is defined if(POLICY CMP0091) cmake_policy(SET CMP0091 NEW) # Enables use of MSVC_RUNTIME_LIBRARY endif() project(pugixml VERSION 1.15 LANGUAGES CXX) include(CMakePackageConfigHelpers) include(CMakeDependentOption) include(GNUInstallDirs) cmake_dependent_option(PUGIXML_USE_VERSIONED_LIBDIR "Use a private subdirectory to install the headers and libraries" OFF "CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR" OFF) cmake_dependent_option(PUGIXML_USE_POSTFIX "Use separate postfix for each configuration to make sure you can install multiple build outputs" OFF "CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR" OFF) cmake_dependent_option(PUGIXML_STATIC_CRT "Use static MSVC RT libraries" OFF "MSVC" OFF) cmake_dependent_option(PUGIXML_BUILD_TESTS "Build pugixml tests" OFF "CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR" OFF) # Custom build defines set(PUGIXML_BUILD_DEFINES CACHE STRING "Build defines for custom options") separate_arguments(PUGIXML_BUILD_DEFINES) # Technically not needed for this file. This is builtin CMAKE global variable. option(BUILD_SHARED_LIBS "Build shared instead of static library" OFF) # Expose option to build PUGIXML as static as well when the global BUILD_SHARED_LIBS variable is set cmake_dependent_option(PUGIXML_BUILD_SHARED_AND_STATIC_LIBS "Build both shared and static libraries" OFF "BUILD_SHARED_LIBS" OFF) # Expose options from the pugiconfig.hpp option(PUGIXML_WCHAR_MODE "Enable wchar_t mode" OFF) option(PUGIXML_COMPACT "Enable compact mode" OFF) option(PUGIXML_INSTALL "Enable installation rules" ON) # Advanced options from pugiconfig.hpp option(PUGIXML_NO_XPATH "Disable XPath" OFF) option(PUGIXML_NO_STL "Disable STL" OFF) option(PUGIXML_NO_EXCEPTIONS "Disable Exceptions" OFF) mark_as_advanced(PUGIXML_NO_XPATH PUGIXML_NO_STL PUGIXML_NO_EXCEPTIONS) if (APPLE) option(PUGIXML_BUILD_APPLE_FRAMEWORK "Build as Apple Frameworks" OFF) endif() set(PUGIXML_PUBLIC_DEFINITIONS $<$:PUGIXML_WCHAR_MODE> $<$:PUGIXML_COMPACT> $<$:PUGIXML_NO_XPATH> $<$:PUGIXML_NO_STL> $<$:PUGIXML_NO_EXCEPTIONS> ) # This is used to backport a CMake 3.15 feature, but is also forwards compatible if (NOT DEFINED CMAKE_MSVC_RUNTIME_LIBRARY) set(CMAKE_MSVC_RUNTIME_LIBRARY MultiThreaded$<$:Debug>$<$>:DLL>) endif() # Set the default C++ standard to C++17 if not set; CMake will automatically downgrade this if the compiler does not support it # When CMAKE_CXX_STANDARD_REQUIRED is set, we fall back to C++11 to avoid breaking older compilers if (NOT DEFINED CMAKE_CXX_STANDARD_REQUIRED AND NOT DEFINED CMAKE_CXX_STANDARD AND NOT CMAKE_VERSION VERSION_LESS 3.8) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED OFF) elseif (NOT DEFINED CMAKE_CXX_STANDARD) set(CMAKE_CXX_STANDARD 11) endif() if (PUGIXML_USE_POSTFIX) set(CMAKE_RELWITHDEBINFO_POSTFIX _r) set(CMAKE_MINSIZEREL_POSTFIX _m) set(CMAKE_DEBUG_POSTFIX _d) endif() if (CMAKE_VERSION VERSION_LESS 3.15) set(msvc-rt $) set(msvc-rt-mtd-shared $) set(msvc-rt-mtd-static $) set(msvc-rt-mt-shared $) set(msvc-rt-mt-static $) unset(msvc-rt) set(msvc-rt-mtd-shared $<${msvc-rt-mtd-shared}:-MDd>) set(msvc-rt-mtd-static $<${msvc-rt-mtd-static}:-MTd>) set(msvc-rt-mt-shared $<${msvc-rt-mt-shared}:-MD>) set(msvc-rt-mt-static $<${msvc-rt-mt-static}:-MT>) endif() set(versioned-dir $<$:/pugixml-${PROJECT_VERSION}>) set(libs) if (BUILD_SHARED_LIBS) add_library(pugixml-shared SHARED ${PROJECT_SOURCE_DIR}/scripts/pugixml_dll.rc ${PROJECT_SOURCE_DIR}/src/pugixml.cpp) add_library(pugixml::shared ALIAS pugixml-shared) list(APPEND libs pugixml-shared) string(CONCAT pugixml.msvc $, $ >) set_property(TARGET pugixml-shared PROPERTY EXPORT_NAME shared) target_include_directories(pugixml-shared PUBLIC $) target_compile_definitions(pugixml-shared PUBLIC ${PUGIXML_BUILD_DEFINES} ${PUGIXML_PUBLIC_DEFINITIONS} PRIVATE PUGIXML_API=$ ) target_compile_options(pugixml-shared PRIVATE ${msvc-rt-mtd-shared} ${msvc-rt-mtd-static} ${msvc-rt-mt-shared} ${msvc-rt-mt-static}) endif() if (NOT BUILD_SHARED_LIBS OR PUGIXML_BUILD_SHARED_AND_STATIC_LIBS) add_library(pugixml-static STATIC ${PROJECT_SOURCE_DIR}/src/pugixml.cpp) add_library(pugixml::static ALIAS pugixml-static) list(APPEND libs pugixml-static) set_property(TARGET pugixml-static PROPERTY EXPORT_NAME static) target_include_directories(pugixml-static PUBLIC $) target_compile_definitions(pugixml-static PUBLIC ${PUGIXML_BUILD_DEFINES} ${PUGIXML_PUBLIC_DEFINITIONS}) target_compile_options(pugixml-static PRIVATE ${msvc-rt-mtd-shared} ${msvc-rt-mtd-static} ${msvc-rt-mt-shared} ${msvc-rt-mt-static}) endif() if (BUILD_SHARED_LIBS) set(pugixml-alias pugixml-shared) else() set(pugixml-alias pugixml-static) endif() add_library(pugixml INTERFACE) target_link_libraries(pugixml INTERFACE ${pugixml-alias}) add_library(pugixml::pugixml ALIAS pugixml) set_target_properties(${libs} PROPERTIES MSVC_RUNTIME_LIBRARY ${CMAKE_MSVC_RUNTIME_LIBRARY} EXCLUDE_FROM_ALL ON POSITION_INDEPENDENT_CODE ON SOVERSION ${PROJECT_VERSION_MAJOR} VERSION ${PROJECT_VERSION} OUTPUT_NAME pugixml) set_target_properties(${libs} PROPERTIES EXCLUDE_FROM_ALL OFF) set(install-targets pugixml ${libs}) if (PUGIXML_BUILD_APPLE_FRAMEWORK) set_target_properties(${libs} PROPERTIES FRAMEWORK TRUE FRAMEWORK_VERSION ${PROJECT_VERSION} XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER com.zeux.pugixml MACOSX_FRAMEWORK_IDENTIFIER com.zeux.pugixml MACOSX_FRAMEWORK_BUNDLE_VERSION ${PROJECT_VERSION} MACOSX_FRAMEWORK_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}) endif() configure_package_config_file( "${PROJECT_SOURCE_DIR}/scripts/pugixml-config.cmake.in" "${PROJECT_BINARY_DIR}/pugixml-config.cmake" INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR} NO_CHECK_REQUIRED_COMPONENTS_MACRO NO_SET_AND_CHECK_MACRO) write_basic_package_version_file( "${PROJECT_BINARY_DIR}/pugixml-config-version.cmake" COMPATIBILITY SameMajorVersion) if (PUGIXML_USE_POSTFIX) if(CMAKE_BUILD_TYPE MATCHES RelWithDebInfo) set(LIB_POSTFIX ${CMAKE_RELWITHDEBINFO_POSTFIX}) elseif(CMAKE_BUILD_TYPE MATCHES MinSizeRel) set(LIB_POSTFIX ${CMAKE_MINSIZEREL_POSTFIX}) elseif(CMAKE_BUILD_TYPE MATCHES Debug) set(LIB_POSTFIX ${CMAKE_DEBUG_POSTFIX}) endif() endif() # Handle both relative and absolute paths (e.g. NixOS) for a relocatable package if(IS_ABSOLUTE "${CMAKE_INSTALL_INCLUDEDIR}") set(PUGIXML_PC_INCLUDEDIR "${CMAKE_INSTALL_INCLUDEDIR}") else() set(PUGIXML_PC_INCLUDEDIR "\${prefix}/${CMAKE_INSTALL_INCLUDEDIR}") endif() if(IS_ABSOLUTE "${CMAKE_INSTALL_LIBDIR}") set(PUGIXML_PC_LIBDIR "${CMAKE_INSTALL_LIBDIR}") else() set(PUGIXML_PC_LIBDIR "\${exec_prefix}/${CMAKE_INSTALL_LIBDIR}") endif() configure_file(scripts/pugixml.pc.in pugixml.pc @ONLY) export(TARGETS ${install-targets} NAMESPACE pugixml:: FILE pugixml-targets.cmake) if(PUGIXML_INSTALL) if (NOT DEFINED PUGIXML_RUNTIME_COMPONENT) set(PUGIXML_RUNTIME_COMPONENT Runtime) endif() if (NOT DEFINED PUGIXML_LIBRARY_COMPONENT) set(PUGIXML_LIBRARY_COMPONENT Library) endif() if (NOT DEFINED PUGIXML_DEVELOPMENT_COMPONENT) set(PUGIXML_DEVELOPMENT_COMPONENT Development) endif() set(namelink-component) if (NOT CMAKE_VERSION VERSION_LESS 3.12) set(namelink-component NAMELINK_COMPONENT ${PUGIXML_DEVELOPMENT_COMPONENT}) endif() install(TARGETS ${install-targets} EXPORT pugixml-targets RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT ${PUGIXML_RUNTIME_COMPONENT} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT ${PUGIXML_LIBRARY_COMPONENT} ${namelink-component} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT ${PUGIXML_DEVELOPMENT_COMPONENT} INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}${versioned-dir} FRAMEWORK DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT runtime OPTIONAL) install(EXPORT pugixml-targets NAMESPACE pugixml:: DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/pugixml COMPONENT ${PUGIXML_DEVELOPMENT_COMPONENT}) install(FILES "${PROJECT_BINARY_DIR}/pugixml-config-version.cmake" "${PROJECT_BINARY_DIR}/pugixml-config.cmake" DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/pugixml COMPONENT ${PUGIXML_DEVELOPMENT_COMPONENT}) install(FILES ${PROJECT_BINARY_DIR}/pugixml.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig COMPONENT ${PUGIXML_DEVELOPMENT_COMPONENT}) install( FILES "${PROJECT_SOURCE_DIR}/src/pugiconfig.hpp" "${PROJECT_SOURCE_DIR}/src/pugixml.hpp" DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}${versioned-dir} COMPONENT ${PUGIXML_DEVELOPMENT_COMPONENT}) endif() if (PUGIXML_BUILD_TESTS) include(CTest) set(fuzz-pattern "tests/fuzz_*.cpp") set(test-pattern "tests/*.cpp") if (CMAKE_VERSION VERSION_GREATER 3.11) list(INSERT fuzz-pattern 0 CONFIGURE_DEPENDS) list(INSERT test-pattern 0 CONFIGURE_DEPENDS) endif() file(GLOB test-sources ${test-pattern}) file(GLOB fuzz-sources ${fuzz-pattern}) list(REMOVE_ITEM test-sources ${fuzz-sources}) add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure) add_executable(pugixml-check ${test-sources}) add_test(NAME pugixml::test COMMAND pugixml-check WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) add_dependencies(check pugixml-check) target_link_libraries(pugixml-check PRIVATE pugixml::pugixml) endif() ================================================ FILE: external/pugixml/LICENSE.md ================================================ MIT License Copyright (c) 2006-2025 Arseny Kapoulkine Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: external/pugixml/docs/manual.html ================================================ pugixml 1.15 manual

1. Overview

1.1. Introduction

pugixml is a light-weight C++ XML processing library. It consists of a DOM-like interface with rich traversal/modification capabilities, an extremely fast XML parser which constructs the DOM tree from an XML file/buffer, and an XPath 1.0 implementation for complex data-driven tree queries. Full Unicode support is also available, with two Unicode interface variants and conversions between different Unicode encodings (which happen automatically during parsing/saving). The library is extremely portable and easy to integrate and use. pugixml is developed and maintained since 2006 and has many users. All code is distributed under the MIT license, making it completely free to use in both open-source and proprietary applications.

pugixml enables very fast, convenient and memory-efficient XML document processing. However, since pugixml has a DOM parser, it can’t process XML documents that do not fit in memory; also the parser is a non-validating one, so if you need DTD or XML Schema validation, the library is not for you.

This is the complete manual for pugixml, which describes all features of the library in detail. If you want to start writing code as quickly as possible, you are advised to read the quick start guide first.

Note
No documentation is perfect; neither is this one. If you find errors or omissions, please don’t hesitate to submit an issue or open a pull request with a fix.

1.2. Feedback

If you believe you’ve found a bug in pugixml (bugs include compilation problems (errors/warnings), crashes, performance degradation and incorrect behavior), please file an issue via issue submission form. Be sure to include the relevant information so that the bug can be reproduced: the version of pugixml, compiler version and target architecture, the code that uses pugixml and exhibits the bug, etc.

Feature requests can be reported the same way as bugs, so if you’re missing some functionality in pugixml or if the API is rough in some places and you can suggest an improvement, file an issue. However please note that there are many factors when considering API changes (compatibility with previous versions, API redundancy, etc.), so generally features that can be implemented via a small function without pugixml modification are not accepted. However, all rules have exceptions.

If you have a contribution to pugixml, such as build script for some build system/IDE, or a well-designed set of helper functions, or a binding to some language other than C++, please file an issue or open a pull request. Your contribution has to be distributed under the terms of a license that’s compatible with pugixml license; i.e. GPL/LGPL licensed code is not accepted.

If filing an issue is not possible due to privacy or other concerns, you can contact pugixml author by e-mail directly: arseny.kapoulkine@gmail.com.

1.3. Acknowledgments

pugixml could not be developed without the help from many people; some of them are listed in this section. If you’ve played a part in pugixml development and you can not find yourself on this list, I’m truly sorry; please send me an e-mail so I can fix this.

Thanks to Kristen Wegner for pugxml parser, which was used as a basis for pugixml.

Thanks to Neville Franks for contributions to pugxml parser.

Thanks to Artyom Palvelev for suggesting a lazy gap contraction approach.

Thanks to Vyacheslav Egorov for documentation proofreading and fuzz testing.

1.4. License

The pugixml library is distributed under the MIT license:

Copyright (c) 2006-2025 Arseny Kapoulkine

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

This means that you can freely use pugixml in your applications, both open-source and proprietary. If you use pugixml in a product, it is sufficient to add an acknowledgment like this to the product distribution:

This software is based on pugixml library (https://pugixml.org).
pugixml is Copyright (C) 2006-2025 Arseny Kapoulkine.

2. Installation

2.1. Getting pugixml

pugixml is distributed in source form. You can either download a source distribution or clone the Git repository.

2.1.1. Source distributions

You can download the latest source distribution as an archive:

pugixml-1.15.zip (Windows line endings) / pugixml-1.15.tar.gz (Unix line endings)

The distribution contains library source, documentation (the manual you’re reading now and the quick start guide) and some code examples. After downloading the distribution, install pugixml by extracting all files from the compressed archive.

If you need an older version, you can download it from the version archive.

2.1.2. Git repository

The Git repository is located at https://github.com/zeux/pugixml/. There is a Git tag "v{version}" for each version; also there is the "latest" tag, which always points to the latest stable release.

For example, to checkout the current version, you can use this command:

git clone https://github.com/zeux/pugixml
cd pugixml
git checkout v1.15

The repository contains library source, documentation, code examples and full unit test suite.

Use latest tag if you want to automatically get new versions. Use other tags if you want to switch to new versions only explicitly. Also please note that the master branch contains the work-in-progress version of the code; while this means that you can get new features and bug fixes from master without waiting for a new release, this also means that occasionally the code can be broken in some configurations.

2.1.3. Subversion repository

You can access the Git repository via Subversion using https://github.com/zeux/pugixml URL. For example, to checkout the current version, you can use this command:

svn checkout https://github.com/zeux/pugixml/tags/v1.15 pugixml

2.1.4. Packages

pugixml is available as a package via various package managers. Note that most packages are maintained separately from the main repository so they do not necessarily contain the latest version.

Here’s an incomplete list of pugixml packages in various systems:

2.2. Building pugixml

pugixml is distributed in source form without any pre-built binaries; you have to build them yourself.

The complete pugixml source consists of three files - one source file, pugixml.cpp, and two header files, pugixml.hpp and pugiconfig.hpp. pugixml.hpp is the primary header which you need to include in order to use pugixml classes/functions; pugiconfig.hpp is a supplementary configuration file (see Additional configuration options). The rest of this guide assumes that pugixml.hpp is either in the current directory or in one of include directories of your projects, so that #include "pugixml.hpp" can find the header; however you can also use relative path (i.e. #include "../libs/pugixml/src/pugixml.hpp") or include directory-relative path (i.e. #include <xml/thirdparty/pugixml/src/pugixml.hpp>).

2.2.1. Building pugixml as a part of another static library/executable

The easiest way to build pugixml is to compile the source file, pugixml.cpp, along with the existing library/executable. This process depends on the method of building your application; for example, if you’re using Microsoft Visual Studio [1], Apple Xcode, Code::Blocks or any other IDE, just add pugixml.cpp to one of your projects.

If you’re using Microsoft Visual Studio and the project has precompiled headers turned on, you’ll see the following error messages:

pugixml.cpp(3477) : fatal error C1010: unexpected end of file while looking for precompiled header. Did you forget to add '#include "stdafx.h"' to your source?

The correct way to resolve this is to disable precompiled headers for pugixml.cpp; you have to set "Create/Use Precompiled Header" option (Properties dialog → C/C++ → Precompiled Headers → Create/Use Precompiled Header) to "Not Using Precompiled Headers". You’ll have to do it for all project configurations/platforms (you can select Configuration "All Configurations" and Platform "All Platforms" before editing the option):

vs2005 pch1
vs2005 pch2
vs2005 pch3
vs2005 pch4

2.2.2. Building pugixml as a standalone static library

It’s possible to compile pugixml as a standalone static library. This process depends on the method of building your application; pugixml distribution comes with project files for several popular IDEs/build systems. There are project files for Apple XCode, Code::Blocks, Codelite, Microsoft Visual Studio 2005, 2008, 2010+, and configuration scripts for CMake and premake4. You’re welcome to submit project files/build scripts for other software; see Feedback.

There are two projects for each version of Microsoft Visual Studio: one for dynamically linked CRT, which has a name like pugixml_vs2008.vcproj, and another one for statically linked CRT, which has a name like pugixml_vs2008_static.vcproj. You should select the version that matches the CRT used in your application; the default option for new projects created by Microsoft Visual Studio is dynamically linked CRT, so unless you changed the defaults, you should use the version with dynamic CRT (i.e. pugixml_vs2008.vcproj for Microsoft Visual Studio 2008).

In addition to adding pugixml project to your workspace, you’ll have to make sure that your application links with pugixml library. If you’re using Microsoft Visual Studio 2005/2008, you can add a dependency from your application project to pugixml one. If you’re using Microsoft Visual Studio 2010+, you’ll have to add a reference to your application project instead. For other IDEs/systems, consult the relevant documentation.

Microsoft Visual Studio 2005/2008 Microsoft Visual Studio 2010+
vs2005 link1
vs2005 link2
vs2010 link1
vs2010 link2

2.2.3. Building pugixml as a standalone shared library

It’s possible to compile pugixml as a standalone shared library. The process is usually similar to the static library approach; however, no preconfigured projects/scripts are included into pugixml distribution, so you’ll have to do it yourself. Generally, if you’re using GCC-based toolchain, the process does not differ from building any other library as DLL (adding -shared to compilation flags should suffice); if you’re using MSVC-based toolchain, you’ll have to explicitly mark exported symbols with a declspec attribute. You can do it by defining PUGIXML_API macro, i.e. via pugiconfig.hpp:

#ifdef _DLL
    #define PUGIXML_API __declspec(dllexport)
#else
    #define PUGIXML_API __declspec(dllimport)
#endif
Caution
If you’re using STL-related functions, you should use the shared runtime library to ensure that a single heap is used for STL allocations in your application and in pugixml; in MSVC, this means selecting the 'Multithreaded DLL' or 'Multithreaded Debug DLL' to 'Runtime library' property (/MD or /MDd linker switch). You should also make sure that your runtime library choice is consistent between different projects.

2.2.4. Using pugixml in header-only mode

It’s possible to use pugixml in header-only mode. This means that all source code for pugixml will be included in every translation unit that includes pugixml.hpp. This is how most of Boost and STL libraries work.

Note that there are advantages and drawbacks of this approach. Header mode may improve tree traversal/modification performance (because many simple functions will be inlined), if your compiler toolchain does not support link-time optimization, or if you have it turned off (with link-time optimization the performance should be similar to non-header mode). However, since compiler now has to compile pugixml source once for each translation unit that includes it, compilation times may increase noticeably. If you want to use pugixml in header mode but do not need XPath support, you can consider disabling it by using PUGIXML_NO_XPATH define to improve compilation time.

To enable header-only mode, you have to define PUGIXML_HEADER_ONLY. You can either do it in pugiconfig.hpp, or provide them via compiler command-line.

Note that it is safe to compile pugixml.cpp if PUGIXML_HEADER_ONLY is defined - so if you want to i.e. use header-only mode only in Release configuration, you can include pugixml.cpp in your project (see Building pugixml as a part of another static library/executable), and conditionally enable header-only mode in pugiconfig.hpp like this:

#ifndef _DEBUG
    #define PUGIXML_HEADER_ONLY
#endif

2.2.5. Additional configuration options

pugixml uses several defines to control the compilation process. There are two ways to define them: either put the needed definitions to pugiconfig.hpp (it has some examples that are commented out) or provide them via compiler command-line. Consistency is important: the definitions should match in all source files that include pugixml.hpp (including pugixml sources) throughout the application. Adding defines to pugiconfig.hpp lets you guarantee this, unless your macro definition is wrapped in preprocessor #if/#ifdef directive and this directive is not consistent. pugiconfig.hpp will never contain anything but comments, which means that when upgrading to a new version, you can safely leave your modified version intact.

PUGIXML_WCHAR_MODE define toggles between UTF-8 style interface (the in-memory text encoding is assumed to be UTF-8, most functions use char as character type) and UTF-16/32 style interface (the in-memory text encoding is assumed to be UTF-16/32, depending on wchar_t size, most functions use wchar_t as character type). See Unicode interface for more details.

PUGIXML_COMPACT define activates a different internal representation of document storage that is much more memory efficient for documents with a lot of markup (i.e. nodes and attributes), but is slightly slower to parse and access. For details see Compact mode.

PUGIXML_NO_XPATH define disables XPath. Both XPath interfaces and XPath implementation are excluded from compilation. This option is provided in case you do not need XPath functionality and need to save code space.

PUGIXML_NO_STL define disables use of STL in pugixml. The functions that operate on STL types are no longer present (i.e. load/save via iostream) if this macro is defined. This option is provided in case your target platform does not have a standard-compliant STL implementation.

PUGIXML_NO_EXCEPTIONS define disables use of exceptions in pugixml. This option is provided in case your target platform does not have exception handling capabilities.

PUGIXML_API, PUGIXML_CLASS and PUGIXML_FUNCTION defines let you specify custom attributes (i.e. declspec or calling conventions) for pugixml classes and non-member functions. In absence of PUGIXML_CLASS or PUGIXML_FUNCTION definitions, PUGIXML_API definition is used instead. For example, to specify fixed calling convention, you can define PUGIXML_FUNCTION to i.e. __fastcall. Another example is DLL import/export attributes in MSVC (see Building pugixml as a standalone shared library).

Note
In that example PUGIXML_API is inconsistent between several source files; this is an exception to the consistency rule.

PUGIXML_MEMORY_PAGE_SIZE, PUGIXML_MEMORY_OUTPUT_STACK and PUGIXML_MEMORY_XPATH_PAGE_SIZE can be used to customize certain important sizes to optimize memory usage for the application-specific patterns. For details see Memory consumption tuning.

PUGIXML_HAS_LONG_LONG define enables support for long long type in pugixml. This define is automatically enabled if your platform is known to have long long support (i.e. has C++11 support or uses a reasonably modern version of a known compiler); if pugixml does not recognize that your platform supports long long but in fact it does, you can enable the define manually.

PUGIXML_HAS_STRING_VIEW define enables function overloads that accept std::string_view arguments. This define is automatically enabled if built targeting C++17 or later; if pugixml does not recognize that your platform supports std::string_view but in fact it does, you can enable the define manually.

2.3. Portability

pugixml is written in standard-compliant C++ with some compiler-specific workarounds where appropriate. pugixml is compatible with the C++11 standard, but does not require C++11 support. Each version is tested with a unit test suite with code coverage exceeding 99%.

pugixml runs on a variety of desktop platforms (including Microsoft Windows, Linux, FreeBSD, Apple MacOSX and Sun Solaris), game consoles (inclusing Microsoft Xbox 360, Microsoft Xbox One, Nintendo Wii, Sony Playstation Portable and Sony Playstation 3) and mobile platforms (including Android, iOS, BlackBerry, Samsung bada and Microsoft Windows CE).

pugixml supports various architectures, such as x86/x86-64, PowerPC, ARM, MIPS and SPARC. In general it should run on any architecture since it does not use architecture-specific code and does not rely on features such as unaligned memory access.

pugixml can be compiled using any C++ compiler; it was tested with all versions of Microsoft Visual C++ from 6.0 up to 2015, GCC from 3.4 up to 5.2, Clang from 3.2 up to 3.7, as well as a variety of other compilers (e.g. Borland C++, Digital Mars C++, Intel C++, Metrowerks CodeWarrior and PathScale). The code is written to avoid compilation warnings even on reasonably high warning levels.

Note that some platforms may have very bare-bones support of C++; in some cases you’ll have to use PUGIXML_NO_STL and/or PUGIXML_NO_EXCEPTIONS to compile without issues. This mostly applies to old game consoles and embedded systems.

3. Document object model

pugixml stores XML data in DOM-like way: the entire XML document (both document structure and element data) is stored in memory as a tree. The tree can be loaded from a character stream (file, string, C++ I/O stream), then traversed with the special API or XPath expressions. The whole tree is mutable: both node structure and node/attribute data can be changed at any time. Finally, the result of document transformations can be saved to a character stream (file, C++ I/O stream or custom transport).

3.1. Tree structure

The XML document is represented with a tree data structure. The root of the tree is the document itself, which corresponds to C++ type xml_document. Document has one or more child nodes, which correspond to C++ type xml_node. Nodes have different types; depending on a type, a node can have a collection of child nodes, a collection of attributes, which correspond to C++ type xml_attribute, and some additional data (i.e. name).

The tree nodes can be of one of the following types (which together form the enumeration xml_node_type):

  • Document node (node_document) - this is the root of the tree, which consists of several child nodes. This node corresponds to xml_document class; note that xml_document is a sub-class of xml_node, so the entire node interface is also available. However, document node is special in several ways, which are covered below. There can be only one document node in the tree; document node does not have any XML representation. Document generally has one child element node (see document_element()), although documents parsed from XML fragments (see parse_fragment) can have more than one.

  • Element/tag node (node_element) - this is the most common type of node, which represents XML elements. Element nodes have a name, a collection of attributes and a collection of child nodes (both of which may be empty). The attribute is a simple name/value pair. The example XML representation of element nodes is as follows:

    <node attr="value"><child/></node>

    There are two element nodes here: one has name "node", single attribute "attr" and single child "child", another has name "child" and does not have any attributes or child nodes.

  • Plain character data nodes (node_pcdata) represent plain text in XML. PCDATA nodes have a value, but do not have a name or children/attributes. Note that plain character data is not a part of the element node but instead has its own node; an element node can have several child PCDATA nodes. The example XML representation of text nodes is as follows:

    <node> text1 <child/> text2 </node>

    Here "node" element has three children, two of which are PCDATA nodes with values " text1 " and " text2 ".

  • Character data nodes (node_cdata) represent text in XML that is quoted in a special way. CDATA nodes do not differ from PCDATA nodes except in XML representation - the above text example looks like this with CDATA:

    <node> <![CDATA[text1]]> <child/> <![CDATA[text2]]> </node>

    CDATA nodes make it easy to include non-escaped <, & and > characters in plain text. CDATA value can not contain the character sequence ]]>, since it is used to determine the end of node contents.

  • Comment nodes (node_comment) represent comments in XML. Comment nodes have a value, but do not have a name or children/attributes. The example XML representation of a comment node is as follows:

    <!-- comment text -->

    Here the comment node has value "comment text". By default comment nodes are treated as non-essential part of XML markup and are not loaded during XML parsing. You can override this behavior with parse_comments flag.

  • Processing instruction node (node_pi) represent processing instructions (PI) in XML. PI nodes have a name and an optional value, but do not have children/attributes. The example XML representation of a PI node is as follows:

    <?name value?>

    Here the name (also called PI target) is "name", and the value is "value". By default PI nodes are treated as non-essential part of XML markup and are not loaded during XML parsing. You can override this behavior with parse_pi flag.

  • Declaration node (node_declaration) represents document declarations in XML. Declaration nodes have a name ("xml") and an optional collection of attributes, but do not have value or children. There can be only one declaration node in a document; moreover, it should be the topmost node (its parent should be the document). The example XML representation of a declaration node is as follows:

    <?xml version="1.0"?>

    Here the node has name "xml" and a single attribute with name "version" and value "1.0". By default declaration nodes are treated as non-essential part of XML markup and are not loaded during XML parsing. You can override this behavior with parse_declaration flag. Also, by default a dummy declaration is output when XML document is saved unless there is already a declaration in the document; you can disable this with format_no_declaration flag.

  • Document type declaration node (node_doctype) represents document type declarations in XML. Document type declaration nodes have a value, which corresponds to the entire document type contents; no additional nodes are created for inner elements like <!ENTITY>. There can be only one document type declaration node in a document; moreover, it should be the topmost node (its parent should be the document). The example XML representation of a document type declaration node is as follows:

    <!DOCTYPE greeting [ <!ELEMENT greeting (#PCDATA)> ]>

    Here the node has value "greeting [ <!ELEMENT greeting (#PCDATA)> ]". By default document type declaration nodes are treated as non-essential part of XML markup and are not loaded during XML parsing. You can override this behavior with parse_doctype flag.

Finally, here is a complete example of XML document and the corresponding tree representation (samples/tree.xml):

<?xml version="1.0"?>
<mesh name="mesh_root">
    <!-- here is a mesh node -->
    some text
    <![CDATA[someothertext]]>
    some more text
    <node attr1="value1" attr2="value2" />
    <node attr1="value2">
        <innernode/>
    </node>
</mesh>
<?include somedata?>
dom tree

3.2. C++ interface

Note
All pugixml classes and functions are located in the pugi namespace; you have to either use explicit name qualification (i.e. pugi::xml_node), or to gain access to relevant symbols via using directive (i.e. using pugi::xml_node; or using namespace pugi;). The namespace will be omitted from all declarations in this documentation hereafter; all code examples will use fully qualified names.

Despite the fact that there are several node types, there are only three C++ classes representing the tree (xml_document, xml_node, xml_attribute); some operations on xml_node are only valid for certain node types. The classes are described below.

xml_document is the owner of the entire document structure; it is a non-copyable class. The interface of xml_document consists of loading functions (see Loading document), saving functions (see Saving document) and the entire interface of xml_node, which allows for document inspection and/or modification. Note that while xml_document is a sub-class of xml_node, xml_node is not a polymorphic type; the inheritance is present only to simplify usage. Alternatively you can use the document_element function to get the element node that’s the immediate child of the document.

Default constructor of xml_document initializes the document to the tree with only a root node (document node). You can then populate it with data using either tree modification functions or loading functions; all loading functions destroy the previous tree with all occupied memory, which puts existing node/attribute handles for this document to invalid state. If you want to destroy the previous tree, you can use the xml_document::reset function; it destroys the tree and replaces it with either an empty one or a copy of the specified document. Destructor of xml_document also destroys the tree, thus the lifetime of the document object should exceed the lifetimes of any node/attribute handles that point to the tree.

Caution
While technically node/attribute handles can be alive when the tree they’re referring to is destroyed, calling any member function for these handles results in undefined behavior. Thus it is recommended to make sure that the document is destroyed only after all references to its nodes/attributes are destroyed.

xml_node is the handle to document node; it can point to any node in the document, including the document node itself. There is a common interface for nodes of all types; the actual node type can be queried via the xml_node::type() method. Note that xml_node is only a handle to the actual node, not the node itself - you can have several xml_node handles pointing to the same underlying object. Destroying xml_node handle does not destroy the node and does not remove it from the tree. The size of xml_node is equal to that of a pointer, so it is nothing more than a lightweight wrapper around a pointer; you can safely pass or return xml_node objects by value without additional overhead.

There is a special value of xml_node type, known as null node or empty node (such nodes have type node_null). It does not correspond to any node in any document, and thus resembles null pointer. However, all operations are defined on empty nodes; generally the operations don’t do anything and return empty nodes/attributes or empty strings as their result (see documentation for specific functions for more detailed information). This is useful for chaining calls; i.e. you can get the grandparent of a node like so: node.parent().parent(); if a node is a null node or it does not have a parent, the first parent() call returns null node; the second parent() call then also returns null node, which makes error handling easier.

xml_attribute is the handle to an XML attribute; it has the same semantics as xml_node, i.e. there can be several xml_attribute handles pointing to the same underlying object and there is a special null attribute value, which propagates to function results.

Both xml_node and xml_attribute have the default constructor which initializes them to null objects.

xml_node and xml_attribute try to behave like pointers, that is, they can be compared with other objects of the same type, making it possible to use them as keys in associative containers. All handles to the same underlying object are equal, and any two handles to different underlying objects are not equal. Null handles only compare as equal to null handles. The result of relational comparison can not be reliably determined from the order of nodes in file or in any other way. Do not use relational comparison operators except for search optimization (i.e. associative container keys).

If you want to use xml_node or xml_attribute objects as keys in hash-based associative containers, you can use the hash_value member functions. They return the hash values that are guaranteed to be the same for all handles to the same underlying object. The hash value for null handles is 0. Note that hash value does not depend on the content of the node, only on the location of the underlying structure in memory - this means that loading the same document twice will likely produce different hash values, and copying the node will not preserve the hash.

Finally handles can be implicitly cast to boolean-like objects, so that you can test if the node/attribute is empty with the following code: if (node) { …​ } or if (!node) { …​ } else { …​ }. Alternatively you can check if a given xml_node/xml_attribute handle is null by calling the following methods:

bool xml_attribute::empty() const;
bool xml_node::empty() const;

Nodes and attributes do not exist without a document tree, so you can’t create them without adding them to some document. Once underlying node/attribute objects are destroyed, the handles to those objects become invalid. While this means that destruction of the entire tree invalidates all node/attribute handles, it also means that destroying a subtree (by calling xml_node::remove_child) or removing an attribute invalidates the corresponding handles. There is no way to check handle validity; you have to ensure correctness through external mechanisms.

3.3. Unicode interface

There are two choices of interface and internal representation when configuring pugixml: you can either choose the UTF-8 (also called char) interface or UTF-16/32 (also called wchar_t) one. The choice is controlled via PUGIXML_WCHAR_MODE define; you can set it via pugiconfig.hpp or via preprocessor options, as discussed in Additional configuration options. If this define is set, the wchar_t interface is used; otherwise (by default) the char interface is used. The exact wide character encoding is assumed to be either UTF-16 or UTF-32 and is determined based on the size of wchar_t type.

Note
If the size of wchar_t is 2, pugixml assumes UTF-16 encoding instead of UCS-2, which means that some characters are represented as two code points.

All tree functions that work with strings work with either C-style null terminated strings or STL strings of the selected character type. For example, node name accessors look like this in char mode:

const char* xml_node::name() const;
bool xml_node::set_name(const char* value);

and like this in wchar_t mode:

const wchar_t* xml_node::name() const;
bool xml_node::set_name(const wchar_t* value);

There is a special type, pugi::char_t, that is defined as the character type and depends on the library configuration; it will be also used in the documentation hereafter. There is also a type pugi::string_t, which is defined as the STL string of the character type; it corresponds to std::string in char mode and to std::wstring in wchar_t mode. Similarly, string_view_t is defined to be std::basic_string_view<char_t>. Overloads for string_view_t are only available when building for C++17 or later (see PUGIXML_HAS_STRING_VIEW).

In addition to the interface, the internal implementation changes to store XML data as pugi::char_t; this means that these two modes have different memory usage characteristics - generally UTF-8 mode is more memory and performance efficient, especially if sizeof(wchar_t) is 4. The conversion to pugi::char_t upon document loading and from pugi::char_t upon document saving happen automatically, which also carries minor performance penalty. The general advice however is to select the character mode based on usage scenario, i.e. if UTF-8 is inconvenient to process and most of your XML data is non-ASCII, wchar_t mode is probably a better choice.

There are cases when you’ll have to convert string data between UTF-8 and wchar_t encodings; the following helper functions are provided for such purposes:

std::string as_utf8(const wchar_t* str);
std::wstring as_wide(const char* str);

Both functions accept a null-terminated string as an argument str, and return the converted string. as_utf8 performs conversion from UTF-16/32 to UTF-8; as_wide performs conversion from UTF-8 to UTF-16/32. Invalid UTF sequences are silently discarded upon conversion. str has to be a valid string; passing null pointer results in undefined behavior. There are also two overloads with the same semantics which accept a string as an argument:

std::string as_utf8(const std::wstring& str);
std::wstring as_wide(const std::string& str);
Note

Most examples in this documentation assume char interface and therefore will not compile with PUGIXML_WCHAR_MODE. This is done to simplify the documentation; usually the only changes you’ll have to make is to pass wchar_t string literals, i.e. instead of

xml_node node = doc.child("bookstore").find_child_by_attribute("book", "id", "12345");

you’ll have to use

xml_node node = doc.child(L"bookstore").find_child_by_attribute(L"book", L"id", L"12345");

3.4. Thread-safety guarantees

Almost all functions in pugixml have the following thread-safety guarantees:

  • it is safe to call free (non-member) functions from multiple threads

  • it is safe to perform concurrent read-only accesses to the same tree (all constant member functions do not modify the tree)

  • it is safe to perform concurrent read/write accesses on multiple trees, as long as each tree is only accessed from a single thread at a time

Concurrent read/write access to a single tree requires synchronization, for example via a reader-writer lock. Modification includes altering document structure and altering individual node/attribute data, i.e. changing names/values.

The only exception is set_memory_management_functions; it modifies global variables and as such is not thread-safe. Its usage policy has more restrictions, see Custom memory allocation/deallocation functions.

3.5. Exception guarantees

With the exception of XPath, pugixml itself does not throw any exceptions. Additionally, most pugixml functions have a no-throw exception guarantee.

This is not applicable to functions that operate on STL strings or IOstreams; such functions have either strong guarantee (functions that operate on strings) or basic guarantee (functions that operate on streams). Also functions that call user-defined callbacks (i.e. xml_node::traverse or xml_node::find_node) do not provide any exception guarantees beyond the ones provided by the callback.

If exception handling is not disabled with PUGIXML_NO_EXCEPTIONS define, XPath functions may throw xpath_exception on parsing errors; also, XPath functions may throw std::bad_alloc in low memory conditions. Still, XPath functions provide strong exception guarantee.

3.6. Memory management

pugixml requests the memory needed for document storage in big chunks, and allocates document data inside those chunks. This section discusses replacing functions used for chunk allocation and internal memory management implementation.

3.6.1. Custom memory allocation/deallocation functions

All memory for tree structure, tree data and XPath objects is allocated via globally specified functions, which default to malloc/free. You can set your own allocation functions with set_memory_management function. The function interfaces are the same as that of malloc/free:

typedef void* (*allocation_function)(size_t size);
typedef void (*deallocation_function)(void* ptr);

You can use the following accessor functions to change or get current memory management functions:

void set_memory_management_functions(allocation_function allocate, deallocation_function deallocate);
allocation_function get_memory_allocation_function();
deallocation_function get_memory_deallocation_function();

Allocation function is called with the size (in bytes) as an argument and should return a pointer to a memory block with alignment that is suitable for storage of primitive types (usually a maximum of void* and double types alignment is sufficient) and size that is greater than or equal to the requested one. If the allocation fails, the function has to either return null pointer or to throw an exception.

Deallocation function is called with the pointer that was returned by some call to allocation function; it is never called with a null pointer. If memory management functions are not thread-safe, library thread safety is not guaranteed.

This is a simple example of custom memory management (samples/custom_memory_management.cpp):

void* custom_allocate(size_t size)
{
    return new (std::nothrow) char[size];
}

void custom_deallocate(void* ptr)
{
    delete[] static_cast<char*>(ptr);
}
pugi::set_memory_management_functions(custom_allocate, custom_deallocate);

When setting new memory management functions, care must be taken to make sure that there are no live pugixml objects. Otherwise when the objects are destroyed, the new deallocation function will be called with the memory obtained by the old allocation function, resulting in undefined behavior.

3.6.2. Memory consumption tuning

There are several important buffering optimizations in pugixml that rely on predefined constants. These constants have default values that were tuned for common usage patterns; for some applications, changing these constants might improve memory consumption or increase performance. Changing these constants is not recommended unless their default values result in visible problems.

These constants can be tuned via configuration defines, as discussed in Additional configuration options; it is recommended to set them in pugiconfig.hpp.

  • PUGIXML_MEMORY_PAGE_SIZE controls the page size for document memory allocation. Memory for node/attribute objects is allocated in pages of the specified size. The default size is 32 Kb; for some applications the size is too large (i.e. embedded systems with little heap space or applications that keep lots of XML documents in memory). A minimum size of 1 Kb is recommended.

  • PUGIXML_MEMORY_OUTPUT_STACK controls the cumulative stack space required to output the node. Any output operation (i.e. saving a subtree to file) uses an internal buffering scheme for performance reasons. The default size is 10 Kb; if you’re using node output from threads with little stack space, decreasing this value can prevent stack overflows. A minimum size of 1 Kb is recommended.

  • PUGIXML_MEMORY_XPATH_PAGE_SIZE controls the page size for XPath memory allocation. Memory for XPath query objects as well as internal memory for XPath evaluation is allocated in pages of the specified size. The default size is 4 Kb; if you have a lot of resident XPath query objects, you might need to decrease the size to improve memory consumption. A minimum size of 256 bytes is recommended.

3.6.3. Document memory management internals

Constructing a document object using the default constructor does not result in any allocations; document node is stored inside the xml_document object.

When the document is loaded from file/buffer, unless an inplace loading function is used (see Loading document from memory), a complete copy of character stream is made; all names/values of nodes and attributes are allocated in this buffer. This buffer is allocated via a single large allocation and is only freed when document memory is reclaimed (i.e. if the xml_document object is destroyed or if another document is loaded in the same object). Also when loading from file or stream, an additional large allocation may be performed if encoding conversion is required; a temporary buffer is allocated, and it is freed before load function returns.

All additional memory, such as memory for document structure (node/attribute objects) and memory for node/attribute names/values is allocated in pages on the order of 32 Kb; actual objects are allocated inside the pages using a memory management scheme optimized for fast allocation/deallocation of many small objects. Because of the scheme specifics, the pages are only destroyed if all objects inside them are destroyed; also, generally destroying an object does not mean that subsequent object creation will reuse the same memory. This means that it is possible to devise a usage scheme which will lead to higher memory usage than expected; one example is adding a lot of nodes, and them removing all even numbered ones; not a single page is reclaimed in the process. However this is an example specifically crafted to produce unsatisfying behavior; in all practical usage scenarios the memory consumption is less than that of a general-purpose allocator because allocation meta-data is very small in size.

3.6.4. Compact mode

By default nodes and attributes are optimized for efficiency of access. This can cause them to take a significant amount of memory - for documents with a lot of nodes and not a lot of contents (short attribute values/node text), and depending on the pointer size, the document structure can take noticeably more memory than the document itself (e.g. on a 64-bit platform in UTF-8 mode a markup-heavy document with the file size of 2.1 Mb can use 2.1 Mb for document buffer and 8.3 Mb for document structure).

If you are processing big documents or your platform is memory constrained and you’re willing to sacrifice a bit of performance for memory, you can compile pugixml with PUGIXML_COMPACT define which will activate compact mode. Compact mode uses a different representation of the document structure that assumes locality of reference between nodes and attributes to optimize memory usage. As a result you get significantly smaller node/attribute objects; usually most objects in most documents don’t require additional storage, but in the worst case - if assumptions about locality of reference don’t hold - additional memory will be allocated to store the extra data required.

The compact storage supports all existing operations - including tree modification - with the same amortized complexity (that is, all basic document manipulations are still O(1) on average). The operations are slightly slower; you can usually expect 10-50% slowdown in terms of processing time unless your processing was memory-bound.

On 32-bit architectures document structure in compact mode is typically reduced by around 2.5x; on 64-bit architectures the ratio is around 5x. Thus for big markup-heavy documents compact mode can make the difference between the processing of a multi-gigabyte document running completely from RAM vs requiring swapping to disk. Even if the document fits into memory, compact storage can use CPU caches more efficiently by taking less space and causing less cache/TLB misses.

4. Loading document

pugixml provides several functions for loading XML data from various places - files, C++ iostreams, memory buffers. All functions use an extremely fast non-validating parser. This parser is not fully W3C conformant - it can load any valid XML document, but does not perform some well-formedness checks. While considerable effort is made to reject invalid XML documents, some validation is not performed for performance reasons. Also some XML transformations (i.e. EOL handling or attribute value normalization) can impact parsing speed and thus can be disabled. However for vast majority of XML documents there is no performance difference between different parsing options. Parsing options also control whether certain XML nodes are parsed; see Parsing options for more information.

XML data is always converted to internal character format (see Unicode interface) before parsing. pugixml supports all popular Unicode encodings (UTF-8, UTF-16 (big and little endian), UTF-32 (big and little endian); UCS-2 is naturally supported since it’s a strict subset of UTF-16) as well as some non-Unicode encodings (Latin-1) and handles all encoding conversions automatically. Unless explicit encoding is specified, loading functions perform automatic encoding detection based on source XML data, so in most cases you do not have to specify document encoding. Encoding conversion is described in more detail in Encodings.

4.1. Loading document from file

The most common source of XML data is files; pugixml provides dedicated functions for loading an XML document from file:

xml_parse_result xml_document::load_file(const char* path, unsigned int options = parse_default, xml_encoding encoding = encoding_auto);
xml_parse_result xml_document::load_file(const wchar_t* path, unsigned int options = parse_default, xml_encoding encoding = encoding_auto);

These functions accept the file path as its first argument, and also two optional arguments, which specify parsing options (see Parsing options) and input data encoding (see Encodings). The path has the target operating system format, so it can be a relative or absolute one, it should have the delimiters of the target system, it should have the exact case if the target file system is case-sensitive, etc.

File path is passed to the system file opening function as is in case of the first function (which accepts const char* path); the second function either uses a special file opening function if it is provided by the runtime library or converts the path to UTF-8 and uses the system file opening function.

load_file destroys the existing document tree and then tries to load the new tree from the specified file. The result of the operation is returned in an xml_parse_result object; this object contains the operation status and the related information (i.e. last successfully parsed position in the input file, if parsing fails). See Handling parsing errors for error handling details.

This is an example of loading XML document from file (samples/load_file.cpp):

pugi::xml_document doc;

pugi::xml_parse_result result = doc.load_file("tree.xml");

std::cout << "Load result: " << result.description() << ", mesh name: " << doc.child("mesh").attribute("name").value() << std::endl;

4.2. Loading document from memory

Sometimes XML data should be loaded from some other source than a file, i.e. HTTP URL; also you may want to load XML data from file using non-standard functions, i.e. to use your virtual file system facilities or to load XML from GZip-compressed files. All these scenarios require loading document from memory. First you should prepare a contiguous memory block with all XML data; then you have to invoke one of buffer loading functions. These functions will handle the necessary encoding conversions, if any, and then will parse the data into the corresponding XML tree. There are several buffer loading functions, which differ in the behavior and thus in performance/memory usage:

xml_parse_result xml_document::load_buffer(const void* contents, size_t size, unsigned int options = parse_default, xml_encoding encoding = encoding_auto);
xml_parse_result xml_document::load_buffer_inplace(void* contents, size_t size, unsigned int options = parse_default, xml_encoding encoding = encoding_auto);
xml_parse_result xml_document::load_buffer_inplace_own(void* contents, size_t size, unsigned int options = parse_default, xml_encoding encoding = encoding_auto);

All functions accept the buffer which is represented by a pointer to XML data, contents, and data size in bytes. Also there are two optional arguments, which specify parsing options (see Parsing options) and input data encoding (see Encodings). The buffer does not have to be zero-terminated.

load_buffer function works with immutable buffer - it does not ever modify the buffer. Because of this restriction it has to create a private buffer and copy XML data to it before parsing (applying encoding conversions if necessary). This copy operation carries a performance penalty, so inplace functions are provided - load_buffer_inplace and load_buffer_inplace_own store the document data in the buffer, modifying it in the process. In order for the document to stay valid, you have to make sure that the buffer’s lifetime exceeds that of the tree if you’re using inplace functions. In addition to that, load_buffer_inplace does not assume ownership of the buffer, so you’ll have to destroy it yourself; load_buffer_inplace_own assumes ownership of the buffer and destroys it once it is not needed. This means that if you’re using load_buffer_inplace_own, you have to allocate memory with pugixml allocation function (you can get it via get_memory_allocation_function).

The best way from the performance/memory point of view is to load document using load_buffer_inplace_own; this function has maximum control of the buffer with XML data so it is able to avoid redundant copies and reduce peak memory usage while parsing. This is the recommended function if you have to load the document from memory and performance is critical.

There is also a simple helper function for cases when you want to load the XML document from null-terminated character string:

xml_parse_result xml_document::load_string(const char_t* contents, unsigned int options = parse_default);

It is equivalent to calling load_buffer with size being either strlen(contents) or wcslen(contents) * sizeof(wchar_t), depending on the character type. This function assumes native encoding for input data, so it does not do any encoding conversion. In general, this function is fine for loading small documents from string literals, but has more overhead and less functionality than the buffer loading functions.

This is an example of loading XML document from memory using different functions (samples/load_memory.cpp):

const char source[] = "<mesh name='sphere'><bounds>0 0 1 1</bounds></mesh>";
size_t size = sizeof(source);
// You can use load_buffer to load document from immutable memory block:
pugi::xml_parse_result result = doc.load_buffer(source, size);
// You can use load_buffer_inplace to load document from mutable memory block; the block's lifetime must exceed that of document
char* buffer = new char[size];
memcpy(buffer, source, size);

// The block can be allocated by any method; the block is modified during parsing
pugi::xml_parse_result result = doc.load_buffer_inplace(buffer, size);

// You have to destroy the block yourself after the document is no longer used
delete[] buffer;
// You can use load_buffer_inplace_own to load document from mutable memory block and to pass the ownership of this block
// The block has to be allocated via pugixml allocation function - using i.e. operator new here is incorrect
char* buffer = static_cast<char*>(pugi::get_memory_allocation_function()(size));
memcpy(buffer, source, size);

// The block will be deleted by the document
pugi::xml_parse_result result = doc.load_buffer_inplace_own(buffer, size);
// You can use load to load document from null-terminated strings, for example literals:
pugi::xml_parse_result result = doc.load_string("<mesh name='sphere'><bounds>0 0 1 1</bounds></mesh>");

4.3. Loading document from C++ IOstreams

To enhance interoperability, pugixml provides functions for loading document from any object which implements C++ std::istream interface. This allows you to load documents from any standard C++ stream (i.e. file stream) or any third-party compliant implementation (i.e. Boost Iostreams). There are two functions, one works with narrow character streams, another handles wide character ones:

xml_parse_result xml_document::load(std::istream& stream, unsigned int options = parse_default, xml_encoding encoding = encoding_auto);
xml_parse_result xml_document::load(std::wistream& stream, unsigned int options = parse_default);

load with std::istream argument loads the document from stream from the current read position to the end, treating the stream contents as a byte stream of the specified encoding (with encoding autodetection as necessary). Thus calling xml_document::load on an opened std::ifstream object is equivalent to calling xml_document::load_file.

load with std::wstream argument treats the stream contents as a wide character stream (encoding is always encoding_wchar). Because of this, using load with wide character streams requires careful (usually platform-specific) stream setup (i.e. using the imbue function). Generally use of wide streams is discouraged, however it provides you the ability to load documents from non-Unicode encodings, i.e. you can load Shift-JIS encoded data if you set the correct locale.

This is a simple example of loading XML document from file using streams (samples/load_stream.cpp); read the sample code for more complex examples involving wide streams and locales:

std::ifstream stream("weekly-utf-8.xml");
pugi::xml_parse_result result = doc.load(stream);

4.4. Handling parsing errors

All document loading functions return the parsing result via xml_parse_result object. It contains parsing status, the offset of last successfully parsed character from the beginning of the source stream, and the encoding of the source stream:

struct xml_parse_result
{
    xml_parse_status status;
    ptrdiff_t offset;
    xml_encoding encoding;

    operator bool() const;
    const char* description() const;
};

Parsing status is represented as the xml_parse_status enumeration and can be one of the following:

  • status_ok means that no error was encountered during parsing; the source stream represents the valid XML document which was fully parsed and converted to a tree.

  • status_file_not_found is only returned by load_file function and means that file could not be opened.

  • status_io_error is returned by load_file function and by load functions with std::istream/std::wstream arguments; it means that some I/O error has occurred during reading the file/stream.

  • status_out_of_memory means that there was not enough memory during some allocation; any allocation failure during parsing results in this error.

  • status_internal_error means that something went horribly wrong; currently this error does not occur

  • status_unrecognized_tag means that parsing stopped due to a tag with either an empty name or a name which starts with incorrect character, such as #.

  • status_bad_pi means that parsing stopped due to incorrect document declaration/processing instruction

  • status_bad_comment, status_bad_cdata, status_bad_doctype and status_bad_pcdata mean that parsing stopped due to the invalid construct of the respective type

  • status_bad_start_element means that parsing stopped because starting tag either had no closing > symbol or contained some incorrect symbol

  • status_bad_attribute means that parsing stopped because there was an incorrect attribute, such as an attribute without value or with value that is not quoted (note that <node attr=1> is incorrect in XML)

  • status_bad_end_element means that parsing stopped because ending tag had incorrect syntax (i.e. extra non-whitespace symbols between tag name and >)

  • status_end_element_mismatch means that parsing stopped because the closing tag did not match the opening one (i.e. <node></nedo>) or because some tag was not closed at all

  • status_no_document_element means that no element nodes were discovered during parsing; this usually indicates an empty or invalid document

description() member function can be used to convert parsing status to a string; the returned message is always in English, so you’ll have to write your own function if you need a localized string. However please note that the exact messages returned by description() function may change from version to version, so any complex status handling should be based on status value. Note that description() returns a char string even in PUGIXML_WCHAR_MODE; you’ll have to call as_wide to get the wchar_t string.

If parsing failed because the source data was not a valid XML, the resulting tree is not destroyed - despite the fact that load function returns error, you can use the part of the tree that was successfully parsed. Obviously, the last element may have an unexpected name/value; for example, if the attribute value does not end with the necessary quotation mark, like in <node attr="value>some data</node> example, the value of attribute attr will contain the string value>some data</node>.

In addition to the status code, parsing result has an offset member, which contains the offset of last successfully parsed character if parsing failed because of an error in source data; otherwise offset is 0. For parsing efficiency reasons, pugixml does not track the current line during parsing; this offset is in units of pugi::char_t (bytes for character mode, wide characters for wide character mode). Many text editors support 'Go To Position' feature - you can use it to locate the exact error position. Alternatively, if you’re loading the document from memory, you can display the error chunk along with the error description (see the example code below).

Caution
Offset is calculated in the XML buffer in native encoding; if encoding conversion is performed during parsing, offset can not be used to reliably track the error position.

Parsing result also has an encoding member, which can be used to check that the source data encoding was correctly guessed. It is equal to the exact encoding used during parsing (i.e. with the exact endianness); see Encodings for more information.

Parsing result object can be implicitly converted to bool; if you do not want to handle parsing errors thoroughly, you can just check the return value of load functions as if it was a bool: if (doc.load_file("file.xml")) { …​ } else { …​ }.

This is an example of handling loading errors (samples/load_error_handling.cpp):

pugi::xml_document doc;
pugi::xml_parse_result result = doc.load_string(source);

if (result)
{
    std::cout << "XML [" << source << "] parsed without errors, attr value: [" << doc.child("node").attribute("attr").value() << "]\n\n";
}
else
{
    std::cout << "XML [" << source << "] parsed with errors, attr value: [" << doc.child("node").attribute("attr").value() << "]\n";
    std::cout << "Error description: " << result.description() << "\n";
    std::cout << "Error offset: " << result.offset << " (error at [..." << (source + result.offset) << "]\n\n";
}

4.5. Parsing options

All document loading functions accept the optional parameter options. This is a bitmask that customizes the parsing process: you can select the node types that are parsed and various transformations that are performed with the XML text. Disabling certain transformations can improve parsing performance for some documents; however, the code for all transformations is very well optimized, and thus the majority of documents won’t get any performance benefit. As a rule of thumb, only modify parsing flags if you want to get some nodes in the document that are excluded by default (i.e. declaration or comment nodes).

Note
You should use the usual bitwise arithmetics to manipulate the bitmask: to enable a flag, use mask | flag; to disable a flag, use mask & ~flag.

These flags control the resulting tree contents:

  • parse_declaration determines if XML document declaration (node with type node_declaration) is to be put in DOM tree. If this flag is off, it is not put in the tree, but is still parsed and checked for correctness. This flag is off by default.

  • parse_doctype determines if XML document type declaration (node with type node_doctype) is to be put in DOM tree. If this flag is off, it is not put in the tree, but is still parsed and checked for correctness. This flag is off by default.

  • parse_pi determines if processing instructions (nodes with type node_pi) are to be put in DOM tree. If this flag is off, they are not put in the tree, but are still parsed and checked for correctness. Note that <?xml …​?> (document declaration) is not considered to be a PI. This flag is off by default.

  • parse_comments determines if comments (nodes with type node_comment) are to be put in DOM tree. If this flag is off, they are not put in the tree, but are still parsed and checked for correctness. This flag is off by default.

  • parse_cdata determines if CDATA sections (nodes with type node_cdata) are to be put in DOM tree. If this flag is off, they are not put in the tree, but are still parsed and checked for correctness. This flag is on by default.

  • parse_trim_pcdata determines if leading and trailing whitespace characters are to be removed from PCDATA nodes. While for some applications leading/trailing whitespace is significant, often the application only cares about the non-whitespace contents so it’s easier to trim whitespace from text during parsing. This flag is off by default.

  • parse_ws_pcdata determines if PCDATA nodes (nodes with type node_pcdata) that consist only of whitespace characters are to be put in DOM tree. Often whitespace-only data is not significant for the application, and the cost of allocating and storing such nodes (both memory and speed-wise) can be significant. For example, after parsing XML string <node> <a/> </node>, <node> element will have three children when parse_ws_pcdata is set (child with type node_pcdata and value " ", child with type node_element and name "a", and another child with type node_pcdata and value " "), and only one child when parse_ws_pcdata is not set. This flag is off by default.

  • parse_ws_pcdata_single determines if whitespace-only PCDATA nodes that have no sibling nodes are to be put in DOM tree. In some cases application needs to parse the whitespace-only contents of nodes, i.e. <node> </node>, but is not interested in whitespace markup elsewhere. It is possible to use parse_ws_pcdata flag in this case, but it results in excessive allocations and complicates document processing; this flag can be used to avoid that. As an example, after parsing XML string <node> <a> </a> </node> with parse_ws_pcdata_single flag set, <node> element will have one child <a>, and <a> element will have one child with type node_pcdata and value " ". This flag has no effect if parse_ws_pcdata is enabled. This flag is off by default.

  • parse_embed_pcdata determines if PCDATA contents is to be saved as element values. Normally element nodes have names but not values; this flag forces the parser to store the contents as a value if PCDATA is the first child of the element node (otherwise PCDATA node is created as usual). This can significantly reduce the memory required for documents with many PCDATA nodes. To retrieve the data you can use xml_node::value() on the element nodes or any of the higher-level functions like child_value or text. This flag is off by default. Since this flag significantly changes the DOM structure it is only recommended for parsing documents with many PCDATA nodes in memory-constrained environments. This flag is off by default.

  • parse_merge_pcdata determines if PCDATA contents is to be merged with the previous PCDATA node when no intermediary nodes are present between them. If the PCDATA contains CDATA sections, PI nodes, or comments in between, and either of the flags parse_cdata ,parse_pi ,parse_comments is not set, the contents of the PCDATA node will be merged with the previous one. This flag is off by default. Note that this flag is not compatible with parse_embed_pcdata.

  • parse_fragment determines if document should be treated as a fragment of a valid XML. Parsing document as a fragment leads to top-level PCDATA content (i.e. text that is not located inside a node) to be added to a tree, and additionally treats documents without element nodes as valid and permits multiple top-level element nodes (currently multiple top-level element nodes are also permitted when the flag is off, but that behavior should not be relied on). This flag is off by default.

Caution
Using in-place parsing (load_buffer_inplace) with parse_fragment flag may result in the loss of the last character of the buffer if it is a part of PCDATA. Since PCDATA values are null-terminated strings, the only way to resolve this is to provide a null-terminated buffer as an input to load_buffer_inplace - i.e. doc.load_buffer_inplace("test\0", 5, pugi::parse_default | pugi::parse_fragment).

These flags control the transformation of tree element contents:

  • parse_escapes determines if character and entity references are to be expanded during the parsing process. Character references have the form &#…​; or &#x…​; (…​ is Unicode numeric representation of character in either decimal (&#…​;) or hexadecimal (&#x…​;) form), entity references are &lt;, &gt;, &amp;, &apos; and &quot; (note that as pugixml does not handle DTD, the only allowed entities are predefined ones). If character/entity reference can not be expanded, it is left as is, so you can do additional processing later. Reference expansion is performed on attribute values and PCDATA content. This flag is on by default.

  • parse_eol determines if EOL handling (that is, replacing sequences \r\n by a single \n character, and replacing all standalone \r characters by \n) is to be performed on input data (that is, comment contents, PCDATA/CDATA contents and attribute values). This flag is on by default.

  • parse_wconv_attribute determines if attribute value normalization should be performed for all attributes. This means, that whitespace characters (new line, tab and space) are replaced with space (' '). New line characters are always treated as if parse_eol is set, i.e. \r\n is converted to a single space. This flag is on by default.

  • parse_wnorm_attribute determines if extended attribute value normalization should be performed for all attributes. This means, that after attribute values are normalized as if parse_wconv_attribute was set, leading and trailing space characters are removed, and all sequences of space characters are replaced by a single space character. parse_wconv_attribute has no effect if this flag is on. This flag is off by default.

Note
parse_wconv_attribute option performs transformations that are required by W3C specification for attributes that are declared as CDATA; parse_wnorm_attribute performs transformations required for NMTOKENS attributes. In the absence of document type declaration all attributes should behave as if they are declared as CDATA, thus parse_wconv_attribute is the default option.

Additionally there are three predefined option masks:

  • parse_minimal has all options turned off. This option mask means that pugixml does not add declaration nodes, document type declaration nodes, PI nodes, CDATA sections and comments to the resulting tree and does not perform any conversion for input data, so theoretically it is the fastest mode. However, as mentioned above, in practice parse_default is usually equally fast.

  • parse_default is the default set of flags, i.e. it has all options set to their default values. It includes parsing CDATA sections (comments/PIs are not parsed), performing character and entity reference expansion, replacing whitespace characters with spaces in attribute values and performing EOL handling. Note, that PCDATA sections consisting only of whitespace characters are not parsed (by default) for performance reasons.

  • parse_full is the set of flags which adds nodes of all types to the resulting tree and performs default conversions for input data. It includes parsing CDATA sections, comments, PI nodes, document declaration node and document type declaration node, performing character and entity reference expansion, replacing whitespace characters with spaces in attribute values and performing EOL handling. Note, that PCDATA sections consisting only of whitespace characters are not parsed in this mode.

This is an example of using different parsing options (samples/load_options.cpp):

const char* source = "<!--comment--><node>&lt;</node>";

// Parsing with default options; note that comment node is not added to the tree, and entity reference &lt; is expanded
doc.load_string(source);
std::cout << "First node value: [" << doc.first_child().value() << "], node child value: [" << doc.child_value("node") << "]\n";

// Parsing with additional parse_comments option; comment node is now added to the tree
doc.load_string(source, pugi::parse_default | pugi::parse_comments);
std::cout << "First node value: [" << doc.first_child().value() << "], node child value: [" << doc.child_value("node") << "]\n";

// Parsing with additional parse_comments option and without the (default) parse_escapes option; &lt; is not expanded
doc.load_string(source, (pugi::parse_default | pugi::parse_comments) & ~pugi::parse_escapes);
std::cout << "First node value: [" << doc.first_child().value() << "], node child value: [" << doc.child_value("node") << "]\n";

// Parsing with minimal option mask; comment node is not added to the tree, and &lt; is not expanded
doc.load_string(source, pugi::parse_minimal);
std::cout << "First node value: [" << doc.first_child().value() << "], node child value: [" << doc.child_value("node") << "]\n";

4.6. Encodings

pugixml supports all popular Unicode encodings (UTF-8, UTF-16 (big and little endian), UTF-32 (big and little endian); UCS-2 is naturally supported since it’s a strict subset of UTF-16) as well as some non-Unicode encodings (Latin-1) and handles all encoding conversions. Most loading functions accept the optional parameter encoding. This is a value of enumeration type xml_encoding, that can have the following values:

  • encoding_auto means that pugixml will try to guess the encoding based on source XML data. The algorithm is a modified version of the one presented in Appendix F of XML recommendation. It tries to find a Byte Order Mark of one of the supported encodings first; if that fails, it checks if the first few bytes of the input data look like a representation of < or <? in one of UTF-16 or UTF-32 variants; if that fails as well, encoding is assumed to be either UTF-8 or one of the non-Unicode encodings - to make the final decision the algorithm tries to parse the encoding attribute of the XML document declaration, ultimately falling back to UTF-8 if document declaration is not present or does not specify a supported encoding.

  • encoding_utf8 corresponds to UTF-8 encoding as defined in the Unicode standard; UTF-8 sequences with length equal to 5 or 6 are not standard and are rejected.

  • encoding_utf16_le corresponds to little-endian UTF-16 encoding as defined in the Unicode standard; surrogate pairs are supported.

  • encoding_utf16_be corresponds to big-endian UTF-16 encoding as defined in the Unicode standard; surrogate pairs are supported.

  • encoding_utf16 corresponds to UTF-16 encoding as defined in the Unicode standard; the endianness is assumed to be that of the target platform.

  • encoding_utf32_le corresponds to little-endian UTF-32 encoding as defined in the Unicode standard.

  • encoding_utf32_be corresponds to big-endian UTF-32 encoding as defined in the Unicode standard.

  • encoding_utf32 corresponds to UTF-32 encoding as defined in the Unicode standard; the endianness is assumed to be that of the target platform.

  • encoding_wchar corresponds to the encoding of wchar_t type; it has the same meaning as either encoding_utf16 or encoding_utf32, depending on wchar_t size.

  • encoding_latin1 corresponds to ISO-8859-1 encoding (also known as Latin-1).

The algorithm used for encoding_auto correctly detects any supported Unicode encoding for all well-formed XML documents (since they start with document declaration) and for all other XML documents that start with <; if your XML document does not start with < and has encoding that is different from UTF-8, use the specific encoding.

Note
The current behavior for Unicode conversion is to skip all invalid UTF sequences during conversion. This behavior should not be relied upon; moreover, in case no encoding conversion is performed, the invalid sequences are not removed, so you’ll get them as is in node/attribute contents.

4.7. Conformance to W3C specification

pugixml is not fully W3C conformant - it can load any valid XML document, but does not perform some well-formedness checks. While considerable effort is made to reject invalid XML documents, some validation is not performed because of performance reasons.

There is only one non-conformant behavior when dealing with valid XML documents: pugixml does not use information supplied in document type declaration for parsing. This means that entities declared in DOCTYPE are not expanded, and all attribute/PCDATA values are always processed in a uniform way that depends only on parsing options.

As for rejecting invalid XML documents, there are a number of incompatibilities with W3C specification, including:

  • Multiple attributes of the same node can have equal names.

  • Tag and attribute names are not fully validated for consisting of allowed characters, so some invalid tags are not rejected

  • Attribute values which contain < are not rejected.

  • Invalid entity/character references are not rejected and are instead left as is.

  • Comment values can contain --.

  • XML data is not required to begin with document declaration; additionally, document declaration can appear after comments and other nodes.

  • Invalid document type declarations are silently ignored in some cases.

  • Unicode validation is not performed so invalid UTF sequences are not rejected.

  • Document can contain multiple top-level element nodes.

5. Accessing document data

pugixml features an extensive interface for getting various types of data from the document and for traversing the document. This section provides documentation for all such functions that do not modify the tree except for XPath-related functions; see XPath for XPath reference. As discussed in C++ interface, there are two types of handles to tree data - xml_node and xml_attribute. The handles have special null (empty) values which propagate through various functions and thus are useful for writing more concise code; see this description for details. The documentation in this section will explicitly state the results of all function in case of null inputs.

5.1. Basic traversal functions

The internal representation of the document is a tree, where each node has a list of child nodes (the order of children corresponds to their order in the XML representation), and additionally element nodes have a list of attributes, which is also ordered. Several functions are provided in order to let you get from one node in the tree to the other. These functions roughly correspond to the internal representation, and thus are usually building blocks for other methods of traversing (i.e. XPath traversals are based on these functions).

xml_node xml_node::parent() const;
xml_node xml_node::first_child() const;
xml_node xml_node::last_child() const;
xml_node xml_node::next_sibling() const;
xml_node xml_node::previous_sibling() const;

xml_attribute xml_node::first_attribute() const;
xml_attribute xml_node::last_attribute() const;
xml_attribute xml_attribute::next_attribute() const;
xml_attribute xml_attribute::previous_attribute() const;

parent function returns the node’s parent; all non-null nodes except the document have non-null parent. first_child and last_child return the first and last child of the node, respectively; note that only document nodes and element nodes can have non-empty child node list. If node has no children, both functions return null nodes. next_sibling and previous_sibling return the node that’s immediately to the right/left of this node in the children list, respectively - for example, in <a/><b/><c/>, calling next_sibling for a handle that points to <b/> results in a handle pointing to <c/>, and calling previous_sibling results in handle pointing to <a/>. If node does not have next/previous sibling (this happens if it is the last/first node in the list, respectively), the functions return null nodes. first_attribute, last_attribute, next_attribute and previous_attribute functions behave similarly to the corresponding child node functions and allow to iterate through attribute list in the same way.

Note
Because of memory consumption reasons, attributes do not have a link to their parent nodes. Thus there is no xml_attribute::parent() function.

Calling any of the functions above on the null handle results in a null handle - i.e. node.first_child().next_sibling() returns the second child of node, and null handle if node is null, has no children at all or if it has only one child node.

With these functions, you can iterate through all child nodes and display all attributes like this (samples/traverse_base.cpp):

for (pugi::xml_node tool = tools.first_child(); tool; tool = tool.next_sibling())
{
    std::cout << "Tool:";

    for (pugi::xml_attribute attr = tool.first_attribute(); attr; attr = attr.next_attribute())
    {
        std::cout << " " << attr.name() << "=" << attr.value();
    }

    std::cout << std::endl;
}

5.2. Getting node data

Apart from structural information (parent, child nodes, attributes), nodes can have name and value, both of which are strings. Depending on node type, name or value may be absent. node_document nodes do not have a name or value, node_element and node_declaration nodes always have a name but never have a value, node_pcdata, node_cdata, node_comment and node_doctype nodes never have a name but always have a value (it may be empty though), node_pi nodes always have a name and a value (again, value may be empty). In order to get node’s name or value, you can use the following functions:

const char_t* xml_node::name() const;
const char_t* xml_node::value() const;

In case node does not have a name or value or if the node handle is null, both functions return empty strings - they never return null pointers.

It is common to store data as text contents of some node - i.e. <node><description>This is a node</description></node>. In this case, <description> node does not have a value, but instead has a child of type node_pcdata with value "This is a node". pugixml provides several helper functions to parse such data:

const char_t* xml_node::child_value() const;
const char_t* xml_node::child_value(const char_t* name) const;
xml_text xml_node::text() const;

child_value() returns the value of the first child with type node_pcdata or node_cdata; child_value(name) is a simple wrapper for child(name).child_value(). For the above example, calling node.child_value("description") and description.child_value() will both produce string "This is a node". If there is no child with relevant type, or if the handle is null, child_value functions return empty string.

text() returns a special object that can be used for working with PCDATA contents in more complex cases than just retrieving the value; it is described in Working with text contents sections.

There is an example of using some of these functions at the end of the next section.

5.3. Getting attribute data

All attributes have name and value, both of which are strings (value may be empty). There are two corresponding accessors, like for xml_node:

const char_t* xml_attribute::name() const;
const char_t* xml_attribute::value() const;

In case the attribute handle is null, both functions return empty strings - they never return null pointers.

If you need a non-empty string if the attribute handle is null (for example, you need to get the option value from XML attribute, but if it is not specified, you need it to default to "sorted" instead of ""), you can use as_string accessor:

const char_t* xml_attribute::as_string(const char_t* def = "") const;

It returns def argument if the attribute handle is null. If you do not specify the argument, the function is equivalent to value().

In many cases attribute values have types that are not strings - i.e. an attribute may always contain values that should be treated as integers, despite the fact that they are represented as strings in XML. pugixml provides several accessors that convert attribute value to some other type:

int xml_attribute::as_int(int def = 0) const;
unsigned int xml_attribute::as_uint(unsigned int def = 0) const;
double xml_attribute::as_double(double def = 0) const;
float xml_attribute::as_float(float def = 0) const;
bool xml_attribute::as_bool(bool def = false) const;
long long xml_attribute::as_llong(long long def = 0) const;
unsigned long long xml_attribute::as_ullong(unsigned long long def = 0) const;

as_int, as_uint, as_llong, as_ullong, as_double and as_float convert attribute values to numbers. If attribute handle is null def argument is returned (which is 0 by default). Otherwise, all leading whitespace characters are truncated, and the remaining string is parsed as an integer number in either decimal or hexadecimal form (applicable to as_int, as_uint, as_llong and as_ullong; hexadecimal format is used if the number has 0x or 0X prefix) or as a floating point number in either decimal or scientific form (as_double or as_float).

In case the input string contains a non-numeric character sequence or a number that is out of the target numeric range, the result is undefined.

Caution
Number conversion functions depend on current C locale as set with setlocale, so may return unexpected results if the locale is different from "C".

as_bool converts attribute value to boolean as follows: if attribute handle is null, def argument is returned (which is false by default). If attribute value is empty, false is returned. Otherwise, true is returned if the first character is one of '1', 't', 'T', 'y', 'Y'. This means that strings like "true" and "yes" are recognized as true, while strings like "false" and "no" are recognized as false. For more complex matching you’ll have to write your own function.

Note
as_llong and as_ullong are only available if your platform has reliable support for the long long type, including string conversions.

This is an example of using these functions, along with node data retrieval ones (samples/traverse_base.cpp):

for (pugi::xml_node tool = tools.child("Tool"); tool; tool = tool.next_sibling("Tool"))
{
    std::cout << "Tool " << tool.attribute("Filename").value();
    std::cout << ": AllowRemote " << tool.attribute("AllowRemote").as_bool();
    std::cout << ", Timeout " << tool.attribute("Timeout").as_int();
    std::cout << ", Description '" << tool.child_value("Description") << "'\n";
}

5.4. Contents-based traversal functions

Since a lot of document traversal consists of finding the node/attribute with the correct name, there are special functions for that purpose:

xml_node xml_node::child(const char_t* name) const;
xml_node xml_node::child(string_view_t name) const;
xml_attribute xml_node::attribute(const char_t* name) const;
xml_attribute xml_node::attribute(string_view_t name) const;
xml_node xml_node::next_sibling(const char_t* name) const;
xml_node xml_node::next_sibling(string_view_t name) const;
xml_node xml_node::previous_sibling(const char_t* name) const;
xml_node xml_node::previous_sibling(string_view_t name) const;

child and attribute return the first child/attribute with the specified name; next_sibling and previous_sibling return the first sibling in the corresponding direction with the specified name. All string comparisons are case-sensitive. In case the node handle is null or there is no node/attribute with the specified name, null handle is returned.

child and next_sibling functions can be used together to loop through all child nodes with the desired name like this:

for (pugi::xml_node tool = tools.child("Tool"); tool; tool = tool.next_sibling("Tool"))

attribute function needs to look for the target attribute by name. If a node has many attributes, finding each by name can be time consuming. If you have an idea of how attributes are ordered in the node, you can use a faster function:

xml_attribute xml_node::attribute(const char_t* name, xml_attribute& hint) const;
xml_attribute xml_node::attribute(string_view_t name, xml_attribute& hint) const;

The extra hint argument is used to guess where the attribute might be, and is updated to the location of the next attribute so that if you search for multiple attributes in the right order, the performance is maximized. Note that hint has to be either null or has to belong to the node, otherwise the behavior is undefined.

You can use this function as follows:

xml_attribute hint;
xml_attribute id = node.attribute("id", hint);
xml_attribute name = node.attribute("name", hint);
xml_attribute version = node.attribute("version", hint);

This code is correct regardless of the order of the attributes, but it’s faster if "id", "name" and "version" occur in that order.

Occasionally the needed node is specified not by the unique name but instead by the value of some attribute; for example, it is common to have node collections with each node having a unique id: <group><item id="1"/> <item id="2"/></group>. There are two functions for finding child nodes based on the attribute values:

xml_node xml_node::find_child_by_attribute(const char_t* name, const char_t* attr_name, const char_t* attr_value) const;
xml_node xml_node::find_child_by_attribute(const char_t* attr_name, const char_t* attr_value) const;

The three-argument function returns the first child node with the specified name which has an attribute with the specified name/value; the two-argument function skips the name test for the node, which can be useful for searching in heterogeneous collections. If the node handle is null or if no node is found, null handle is returned. All string comparisons are case-sensitive.

In all of the above functions, all arguments have to be valid strings; passing null pointers results in undefined behavior.

This is an example of using these functions (samples/traverse_base.cpp):

std::cout << "Tool for *.dae generation: " << tools.find_child_by_attribute("Tool", "OutputFileMasks", "*.dae").attribute("Filename").value() << "\n";

for (pugi::xml_node tool = tools.child("Tool"); tool; tool = tool.next_sibling("Tool"))
{
    std::cout << "Tool " << tool.attribute("Filename").value() << "\n";
}

5.5. Range-based for-loop support

If your C++ compiler supports range-based for-loop (this is a C++11 feature, at the time of writing it’s supported by Microsoft Visual Studio 2012+, GCC 4.6+ and Clang 3.0+), you can use it to enumerate nodes/attributes. Additional helpers are provided to support this; note that they are also compatible with Boost Foreach, and possibly other pre-C++11 foreach facilities.

implementation-defined-type xml_node::children() const;
implementation-defined-type xml_node::children(const char_t* name) const;
implementation-defined-type xml_node::attributes() const;

children function allows you to enumerate all child nodes; children function with name argument allows you to enumerate all child nodes with a specific name; attributes function allows you to enumerate all attributes of the node. Note that you can also use node object itself in a range-based for construct, which is equivalent to using children().

This is an example of using these functions (samples/traverse_rangefor.cpp):

for (pugi::xml_node tool: tools.children("Tool"))
{
    std::cout << "Tool:";

    for (pugi::xml_attribute attr: tool.attributes())
    {
        std::cout << " " << attr.name() << "=" << attr.value();
    }

    for (pugi::xml_node child: tool.children())
    {
        std::cout << ", child " << child.name();
    }

    std::cout << std::endl;
}

While using children() makes the intent of the code clear, note that each node can be treated as a container of child nodes, since it provides begin()/end() member functions described in the next section. Because of this, you can iterate through node’s children simply by using the node itself:

for (pugi::xml_node child: tool) ...

When using C++20, you can also use nodes as well as objects returned by children() and attributes() functions as ranges:

auto tf =
    tools.children("Tool")
    | std::views::filter([](auto node) { return node.attribute("AllowRemote").as_bool(); })
    | std::views::reverse;

for (pugi::xml_node tool: tf) ...

5.6. Traversing node/attribute lists via iterators

Child node lists and attribute lists are simply double-linked lists; while you can use previous_sibling/next_sibling and other such functions for iteration, pugixml additionally provides node and attribute iterators, so that you can treat nodes as containers of other nodes or attributes:

class xml_node_iterator;
class xml_attribute_iterator;

typedef xml_node_iterator xml_node::iterator;
iterator xml_node::begin() const;
iterator xml_node::end() const;

typedef xml_attribute_iterator xml_node::attribute_iterator;
attribute_iterator xml_node::attributes_begin() const;
attribute_iterator xml_node::attributes_end() const;

begin and attributes_begin return iterators that point to the first node/attribute, respectively; end and attributes_end return past-the-end iterator for node/attribute list, respectively - this iterator can’t be dereferenced, but decrementing it results in an iterator pointing to the last element in the list (except for empty lists, where decrementing past-the-end iterator results in undefined behavior). Past-the-end iterator is commonly used as a termination value for iteration loops (see sample below). If you want to get an iterator that points to an existing handle, you can construct the iterator with the handle as a single constructor argument, like so: xml_node_iterator(node). For xml_attribute_iterator, you’ll have to provide both an attribute and its parent node.

begin and end return equal iterators if called on null node; such iterators can’t be dereferenced. attributes_begin and attributes_end behave the same way. For correct iterator usage this means that child node/attribute collections of null nodes appear to be empty.

Both types of iterators have bidirectional iterator semantics (i.e. they can be incremented and decremented, but efficient random access is not supported) and support all usual iterator operations - comparison, dereference, etc. The iterators are invalidated if the node/attribute objects they’re pointing to are removed from the tree; adding nodes/attributes does not invalidate any iterators.

Here is an example of using iterators for document traversal (samples/traverse_iter.cpp):

for (pugi::xml_node_iterator it = tools.begin(); it != tools.end(); ++it)
{
    std::cout << "Tool:";

    for (pugi::xml_attribute_iterator ait = it->attributes_begin(); ait != it->attributes_end(); ++ait)
    {
        std::cout << " " << ait->name() << "=" << ait->value();
    }

    std::cout << std::endl;
}
Caution
Node and attribute iterators are somewhere in the middle between const and non-const iterators. While dereference operation yields a non-constant reference to the object, so that you can use it for tree modification operations, modifying this reference using assignment - i.e. passing iterators to a function like std::sort - will not give expected results, as assignment modifies local handle that’s stored in the iterator.

5.7. Recursive traversal with xml_tree_walker

The methods described above allow traversal of immediate children of some node; if you want to do a deep tree traversal, you’ll have to do it via a recursive function or some equivalent method. However, pugixml provides a helper for depth-first traversal of a subtree. In order to use it, you have to implement xml_tree_walker interface and to call traverse function:

class xml_tree_walker
{
public:
    virtual bool begin(xml_node& node);
    virtual bool for_each(xml_node& node) = 0;
    virtual bool end(xml_node& node);

    int depth() const;
};

bool xml_node::traverse(xml_tree_walker& walker);

The traversal is launched by calling traverse function on traversal root and proceeds as follows:

  • First, begin function is called with traversal root as its argument.

  • Then, for_each function is called for all nodes in the traversal subtree in depth first order, excluding the traversal root. Node is passed as an argument.

  • Finally, end function is called with traversal root as its argument.

If begin, end or any of the for_each calls return false, the traversal is terminated and false is returned as the traversal result; otherwise, the traversal results in true. Note that you don’t have to override begin or end functions; their default implementations return true.

You can get the node’s depth relative to the traversal root at any point by calling depth function. It returns -1 if called from begin/end, and returns 0-based depth if called from for_each - depth is 0 for all children of the traversal root, 1 for all grandchildren and so on.

This is an example of traversing tree hierarchy with xml_tree_walker (samples/traverse_walker.cpp):

struct simple_walker: pugi::xml_tree_walker
{
    virtual bool for_each(pugi::xml_node& node)
    {
        for (int i = 0; i < depth(); ++i) std::cout << "  "; // indentation

        std::cout << node_types[node.type()] << ": name='" << node.name() << "', value='" << node.value() << "'\n";

        return true; // continue traversal
    }
};
simple_walker walker;
doc.traverse(walker);

5.8. Searching for nodes/attributes with predicates

While there are existing functions for getting a node/attribute with known contents, they are often not sufficient for simple queries. As an alternative for manual iteration through nodes/attributes until the needed one is found, you can make a predicate and call one of find_ functions:

template <typename Predicate> xml_attribute xml_node::find_attribute(Predicate pred) const;
template <typename Predicate> xml_node xml_node::find_child(Predicate pred) const;
template <typename Predicate> xml_node xml_node::find_node(Predicate pred) const;

The predicate should be either a plain function or a function object which accepts one argument of type xml_attribute (for find_attribute) or xml_node (for find_child and find_node), and returns bool. The predicate is never called with null handle as an argument.

find_attribute function iterates through all attributes of the specified node, and returns the first attribute for which the predicate returned true. If the predicate returned false for all attributes or if there were no attributes (including the case where the node is null), null attribute is returned.

find_child function iterates through all child nodes of the specified node, and returns the first node for which the predicate returned true. If the predicate returned false for all nodes or if there were no child nodes (including the case where the node is null), null node is returned.

find_node function performs a depth-first traversal through the subtree of the specified node (excluding the node itself), and returns the first node for which the predicate returned true. If the predicate returned false for all nodes or if subtree was empty, null node is returned.

This is an example of using predicate-based functions (samples/traverse_predicate.cpp):

bool small_timeout(pugi::xml_node node)
{
    return node.attribute("Timeout").as_int() < 20;
}

struct allow_remote_predicate
{
    bool operator()(pugi::xml_attribute attr) const
    {
        return strcmp(attr.name(), "AllowRemote") == 0;
    }

    bool operator()(pugi::xml_node node) const
    {
        return node.attribute("AllowRemote").as_bool();
    }
};
// Find child via predicate (looks for direct children only)
std::cout << tools.find_child(allow_remote_predicate()).attribute("Filename").value() << std::endl;

// Find node via predicate (looks for all descendants in depth-first order)
std::cout << doc.find_node(allow_remote_predicate()).attribute("Filename").value() << std::endl;

// Find attribute via predicate
std::cout << tools.last_child().find_attribute(allow_remote_predicate()).value() << std::endl;

// We can use simple functions instead of function objects
std::cout << tools.find_child(small_timeout).attribute("Filename").value() << std::endl;

5.9. Working with text contents

It is common to store data as text contents of some node - i.e. <node><description>This is a node</description></node>. In this case, <description> node does not have a value, but instead has a child of type node_pcdata with value "This is a node". pugixml provides a special class, xml_text, to work with such data. Working with text objects to modify data is described in the documentation for modifying document data; this section describes the access interface of xml_text.

You can get the text object from a node by using text() method:

xml_text xml_node::text() const;

If the node has a type node_pcdata or node_cdata, then the node itself is used to return data; otherwise, a first child node of type node_pcdata or node_cdata is used.

You can check if the text object is bound to a valid PCDATA/CDATA node by using it as a boolean value, i.e. if (text) { …​ } or if (!text) { …​ }. Alternatively you can check it by using the empty() method:

bool xml_text::empty() const;

Given a text object, you can get the contents (i.e. the value of PCDATA/CDATA node) by using the following function:

const char_t* xml_text::get() const;

In case text object is empty, the function returns an empty string - it never returns a null pointer.

If you need a non-empty string if the text object is empty, or if the text contents is actually a number or a boolean that is stored as a string, you can use the following accessors:

const char_t* xml_text::as_string(const char_t* def = "") const;
int xml_text::as_int(int def = 0) const;
unsigned int xml_text::as_uint(unsigned int def = 0) const;
double xml_text::as_double(double def = 0) const;
float xml_text::as_float(float def = 0) const;
bool xml_text::as_bool(bool def = false) const;
long long xml_text::as_llong(long long def = 0) const;
unsigned long long xml_text::as_ullong(unsigned long long def = 0) const;

All of the above functions have the same semantics as similar xml_attribute members: they return the default argument if the text object is empty, they convert the text contents to a target type using the same rules and restrictions. You can refer to documentation for the attribute functions for details.

xml_text is essentially a helper class that operates on xml_node values. It is bound to a node of type node_pcdata or node_cdata. You can use the following function to retrieve this node:

xml_node xml_text::data() const;

Essentially, assuming text is an xml_text object, calling text.get() is equivalent to calling text.data().value().

This is an example of using xml_text object (samples/text.cpp):

std::cout << "Project name: " << project.child("name").text().get() << std::endl;
std::cout << "Project version: " << project.child("version").text().as_double() << std::endl;
std::cout << "Project visibility: " << (project.child("public").text().as_bool(/* def= */ true) ? "public" : "private") << std::endl;
std::cout << "Project description: " << project.child("description").text().get() << std::endl;

5.10. Miscellaneous functions

If you need to get the document root of some node, you can use the following function:

xml_node xml_node::root() const;

This function returns the node with type node_document, which is the root node of the document the node belongs to (unless the node is null, in which case null node is returned).

While pugixml supports complex XPath expressions, sometimes a simple path handling facility is needed. There are two functions, for getting node path and for converting path to a node:

string_t xml_node::path(char_t delimiter = '/') const;
xml_node xml_node::first_element_by_path(const char_t* path, char_t delimiter = '/') const;

Node paths consist of node names, separated with a delimiter (which is / by default); also paths can contain self (.) and parent (..) pseudo-names, so that this is a valid path: "../../foo/./bar". path returns the path to the node from the document root, first_element_by_path looks for a node represented by a given path; a path can be an absolute one (absolute paths start with the delimiter), in which case the rest of the path is treated as document root relative, and relative to the given node. For example, in the following document: <a><b><c/></b></a>, node <c/> has path "a/b/c"; calling first_element_by_path for document with path "a/b" results in node <b/>; calling first_element_by_path for node <a/> with path "../a/./b/../." results in node <a/>; calling first_element_by_path with path "/a" results in node <a/> for any node.

In case path component is ambiguous (if there are two nodes with given name), the first one is selected; paths are not guaranteed to uniquely identify nodes in a document. If any component of a path is not found, the result of first_element_by_path is null node; also first_element_by_path returns null node for null nodes, in which case the path does not matter. path returns an empty string for null nodes.

Note
path function returns the result as STL string, and thus is not available if PUGIXML_NO_STL is defined.

pugixml does not record row/column information for nodes upon parsing for efficiency reasons. However, if the node has not changed in a significant way since parsing (the name/value are not changed, and the node itself is the original one, i.e. it was not deleted from the tree and re-added later), it is possible to get the offset from the beginning of XML buffer:

ptrdiff_t xml_node::offset_debug() const;

If the offset is not available (this happens if the node is null, was not originally parsed from a stream, or has changed in a significant way), the function returns -1. Otherwise it returns the offset to node’s data from the beginning of XML buffer in pugi::char_t units. For more information on parsing offsets, see parsing error handling documentation.

6. Modifying document data

The document in pugixml is fully mutable: you can completely change the document structure and modify the data of nodes/attributes. This section provides documentation for the relevant functions. All functions take care of memory management and structural integrity themselves, so they always result in structurally valid tree - however, it is possible to create an invalid XML tree (for example, by adding two attributes with the same name or by setting attribute/node name to empty/invalid string). Tree modification is optimized for performance and for memory consumption, so if you have enough memory you can create documents from scratch with pugixml and later save them to file/stream instead of relying on error-prone manual text writing and without too much overhead.

All member functions that change node/attribute data or structure are non-constant and thus can not be called on constant handles. However, you can easily convert constant handle to non-constant one by simple assignment: void foo(const pugi::xml_node& n) { pugi::xml_node nc = n; }, so const-correctness here mainly provides additional documentation.

6.1. Setting node data

As discussed before, nodes can have name and value, both of which are strings. Depending on node type, name or value may be absent. node_document nodes do not have a name or value, node_element and node_declaration nodes always have a name but never have a value, node_pcdata, node_cdata, node_comment and node_doctype nodes never have a name but always have a value (it may be empty though), node_pi nodes always have a name and a value (again, value may be empty). In order to set node’s name or value, you can use the following functions:

bool xml_node::set_name(const char_t* rhs);
bool xml_node::set_name(const char_t* rhs, size_t sz);
bool xml_node::set_name(string_view_t rhs);
bool xml_node::set_value(const char_t* rhs);
bool xml_node::set_value(const char_t* rhs, size_t size);
bool xml_node::set_value(string_view_t rhs);

Both functions try to set the name/value to the specified string, and return the operation result. The operation fails if the node can not have name or value (for instance, when trying to call set_name on a node_pcdata node), if the node handle is null, or if there is insufficient memory to handle the request. The provided string is copied into document managed memory and can be destroyed after the function returns (for example, you can safely pass stack-allocated buffers to these functions). The name/value content is not verified, so take care to use only valid XML names, or the document may become malformed.

This is an example of setting node name and value (samples/modify_base.cpp):

pugi::xml_node node = doc.child("node");

// change node name
std::cout << node.set_name("notnode");
std::cout << ", new node name: " << node.name() << std::endl;

// change comment text
std::cout << doc.last_child().set_value("useless comment");
std::cout << ", new comment text: " << doc.last_child().value() << std::endl;

// we can't change value of the element or name of the comment
std::cout << node.set_value("1") << ", " << doc.last_child().set_name("2") << std::endl;

6.2. Setting attribute data

All attributes have name and value, both of which are strings (value may be empty). You can set them with the following functions:

bool xml_attribute::set_name(const char_t* rhs);
bool xml_attribute::set_name(const char_t* rhs, size_t sz);
bool xml_attribute::set_name(string_view_t rhs);
bool xml_attribute::set_value(const char_t* rhs);
bool xml_attribute::set_value(const char_t* rhs, size_t size);
bool xml_attribute::set_value(string_view_t rhs);

Both functions try to set the name/value to the specified string, and return the operation result. The operation fails if the attribute handle is null, or if there is insufficient memory to handle the request. The provided string is copied into document managed memory and can be destroyed after the function returns (for example, you can safely pass stack-allocated buffers to these functions). The name/value content is not verified, so take care to use only valid XML names, or the document may become malformed.

In addition to string functions, several functions are provided for handling attributes with numbers and booleans as values:

bool xml_attribute::set_value(int rhs);
bool xml_attribute::set_value(unsigned int rhs);
bool xml_attribute::set_value(long rhs);
bool xml_attribute::set_value(unsigned long rhs);
bool xml_attribute::set_value(double rhs);
bool xml_attribute::set_value(double rhs, int precision);
bool xml_attribute::set_value(float rhs);
bool xml_attribute::set_value(float rhs, int precision);
bool xml_attribute::set_value(bool rhs);
bool xml_attribute::set_value(long long rhs);
bool xml_attribute::set_value(unsigned long long rhs);

The above functions convert the argument to string and then call the base set_value function. Integers are converted to a decimal form, floating-point numbers are converted to either decimal or scientific form, depending on the number magnitude, boolean values are converted to either "true" or "false".

Caution
Number conversion functions depend on current C locale as set with setlocale, so may generate unexpected results if the locale is different from "C".
Note
set_value overloads with long long type are only available if your platform has reliable support for the type, including string conversions.

For convenience, all set_value functions have the corresponding assignment operators:

xml_attribute& xml_attribute::operator=(const char_t* rhs);
xml_attribute& xml_attribute::operator=(string_view_t rhs);
xml_attribute& xml_attribute::operator=(int rhs);
xml_attribute& xml_attribute::operator=(unsigned int rhs);
xml_attribute& xml_attribute::operator=(long rhs);
xml_attribute& xml_attribute::operator=(unsigned long rhs);
xml_attribute& xml_attribute::operator=(double rhs);
xml_attribute& xml_attribute::operator=(float rhs);
xml_attribute& xml_attribute::operator=(bool rhs);
xml_attribute& xml_attribute::operator=(long long rhs);
xml_attribute& xml_attribute::operator=(unsigned long long rhs);

These operators simply call the right set_value function and return the attribute they’re called on; the return value of set_value is ignored, so errors are ignored.

This is an example of setting attribute name and value (samples/modify_base.cpp):

pugi::xml_attribute attr = node.attribute("id");

// change attribute name/value
std::cout << attr.set_name("key") << ", " << attr.set_value("345");
std::cout << ", new attribute: " << attr.name() << "=" << attr.value() << std::endl;

// we can use numbers or booleans
attr.set_value(1.234);
std::cout << "new attribute value: " << attr.value() << std::endl;

// we can also use assignment operators for more concise code
attr = true;
std::cout << "final attribute value: " << attr.value() << std::endl;

6.3. Adding nodes/attributes

Nodes and attributes do not exist without a document tree, so you can’t create them without adding them to some document. A node or attribute can be created at the end of node/attribute list or before/after some other node:

xml_attribute xml_node::append_attribute(const char_t* name);
xml_attribute xml_node::append_attribute(string_view_t name);
xml_attribute xml_node::prepend_attribute(const char_t* name);
xml_attribute xml_node::prepend_attribute(string_view_t name);
xml_attribute xml_node::insert_attribute_after(const char_t* name, const xml_attribute& attr);
xml_attribute xml_node::insert_attribute_after(string_view_t name, const xml_attribute& attr);
xml_attribute xml_node::insert_attribute_before(const char_t* name, const xml_attribute& attr);
xml_attribute xml_node::insert_attribute_before(string_view_t name, const xml_attribute& attr);

xml_node xml_node::append_child(xml_node_type type = node_element);
xml_node xml_node::prepend_child(xml_node_type type = node_element);
xml_node xml_node::insert_child_after(xml_node_type type, const xml_node& node);
xml_node xml_node::insert_child_before(xml_node_type type, const xml_node& node);

xml_node xml_node::append_child(const char_t* name);
xml_node xml_node::append_child(string_view_t name);
xml_node xml_node::prepend_child(const char_t* name);
xml_node xml_node::prepend_child(string_view_t name);
xml_node xml_node::insert_child_after(const char_t* name, const xml_node& node);
xml_node xml_node::insert_child_after(string_view_t name, const xml_node& node);
xml_node xml_node::insert_child_before(const char_t* name, const xml_node& node);
xml_node xml_node::insert_child_before(string_view_t name, const xml_node& node);

append_attribute and append_child create a new node/attribute at the end of the corresponding list of the node the method is called on; prepend_attribute and prepend_child create a new node/attribute at the beginning of the list; insert_attribute_after, insert_attribute_before, insert_child_after and insert_attribute_before add the node/attribute before or after the specified node/attribute.

Attribute functions create an attribute with the specified name; you can specify the empty name and change the name later if you want to. Node functions with the type argument create the node with the specified type; since node type can’t be changed, you have to know the desired type beforehand. Also note that not all types can be added as children; see below for clarification. Node functions with the name argument create the element node (node_element) with the specified name.

All functions return the handle to the created object on success, and null handle on failure. There are several reasons for failure:

  • Adding fails if the target node is null;

  • Only node_element nodes can contain attributes, so attribute adding fails if node is not an element;

  • Only node_document and node_element nodes can contain children, so child node adding fails if the target node is not an element or a document;

  • node_document and node_null nodes can not be inserted as children, so passing node_document or node_null value as type results in operation failure;

  • node_declaration nodes can only be added as children of the document node; attempt to insert declaration node as a child of an element node fails;

  • Adding node/attribute results in memory allocation, which may fail;

  • Insertion functions fail if the specified node or attribute is null or is not in the target node’s children/attribute list.

Even if the operation fails, the document remains in consistent state, but the requested node/attribute is not added.

Caution
attribute() and child() functions do not add attributes or nodes to the tree, so code like node.attribute("id") = 123; will not do anything if node does not have an attribute with name "id". Make sure you’re operating with existing attributes/nodes by adding them if necessary.

This is an example of adding new attributes/nodes to the document (samples/modify_add.cpp):

// add node with some name
pugi::xml_node node = doc.append_child("node");

// add description node with text child
pugi::xml_node descr = node.append_child("description");
descr.append_child(pugi::node_pcdata).set_value("Simple node");

// add param node before the description
pugi::xml_node param = node.insert_child_before("param", descr);

// add attributes to param node
param.append_attribute("name") = "version";
param.append_attribute("value") = 1.1;
param.insert_attribute_after("type", param.attribute("name")) = "float";

6.4. Removing nodes/attributes

If you do not want your document to contain some node or attribute, you can remove it with one of the following functions:

bool xml_node::remove_attribute(const xml_attribute& a);
bool xml_node::remove_attributes();
bool xml_node::remove_child(const xml_node& n);
bool xml_node::remove_children();

remove_attribute removes the attribute from the attribute list of the node, and returns the operation result. remove_child removes the child node with the entire subtree (including all descendant nodes and attributes) from the document, and returns the operation result. remove_attributes removes all the attributes of the node, and returns the operation result. remove_children removes all the child nodes of the node, and returns the operation result. Removing fails if one of the following is true:

  • The node the function is called on is null;

  • The attribute/node to be removed is null;

  • The attribute/node to be removed is not in the node’s attribute/child list.

Removing the attribute or node invalidates all handles to the same underlying object, and also invalidates all iterators pointing to the same object. Removing node also invalidates all past-the-end iterators to its attribute or child node list. Be careful to ensure that all such handles and iterators either do not exist or are not used after the attribute/node is removed.

If you want to remove the attribute or child node by its name, two additional helper functions are available:

bool xml_node::remove_attribute(const char_t* name);
bool xml_node::remove_attribute(string_view_t name);
bool xml_node::remove_child(const char_t* name);
bool xml_node::remove_child(string_view_t name);

These functions look for the first attribute or child with the specified name, and then remove it, returning the result. If there is no attribute or child with such name, the function returns false; if there are two nodes with the given name, only the first node is deleted. If you want to delete all nodes with the specified name, you can use code like this: while (node.remove_child("tool")) ;.

This is an example of removing attributes/nodes from the document (samples/modify_remove.cpp):

// remove description node with the whole subtree
pugi::xml_node node = doc.child("node");
node.remove_child("description");

// remove id attribute
pugi::xml_node param = node.child("param");
param.remove_attribute("value");

// we can also remove nodes/attributes by handles
pugi::xml_attribute id = param.attribute("name");
param.remove_attribute(id);

6.5. Working with text contents

pugixml provides a special class, xml_text, to work with text contents stored as a value of some node, i.e. <node><description>This is a node</description></node>. Working with text objects to retrieve data is described in the documentation for accessing document data; this section describes the modification interface of xml_text.

Once you have an xml_text object, you can set the text contents using the following function:

bool xml_text::set(const char_t* rhs);
bool xml_text::set(const char_t* rhs, size_t size);
bool xml_text::set(string_view_t rhs);

This function tries to set the contents to the specified string, and returns the operation result. The operation fails if the text object was retrieved from a node that can not have a value and is not an element node (i.e. it is a node_declaration node), if the text object is empty, or if there is insufficient memory to handle the request. The provided string is copied into document managed memory and can be destroyed after the function returns (for example, you can safely pass stack-allocated buffers to this function). Note that if the text object was retrieved from an element node, this function creates the PCDATA child node if necessary (i.e. if the element node does not have a PCDATA/CDATA child already).

In addition to a string function, several functions are provided for handling text with numbers and booleans as contents:

bool xml_text::set(int rhs);
bool xml_text::set(unsigned int rhs);
bool xml_text::set(long rhs);
bool xml_text::set(unsigned long rhs);
bool xml_text::set(double rhs);
bool xml_text::set(double rhs, int precision);
bool xml_text::set(float rhs);
bool xml_text::set(float rhs, int precision);
bool xml_text::set(bool rhs);
bool xml_text::set(long long rhs);
bool xml_text::set(unsigned long long rhs);

The above functions convert the argument to string and then call the base set function. These functions have the same semantics as similar xml_attribute functions. You can refer to documentation for the attribute functions for details.

For convenience, all set functions have the corresponding assignment operators:

xml_text& xml_text::operator=(const char_t* rhs);
xml_text& xml_text::operator=(string_view_t rhs);
xml_text& xml_text::operator=(int rhs);
xml_text& xml_text::operator=(unsigned int rhs);
xml_text& xml_text::operator=(long rhs);
xml_text& xml_text::operator=(unsigned long rhs);
xml_text& xml_text::operator=(double rhs);
xml_text& xml_text::operator=(float rhs);
xml_text& xml_text::operator=(bool rhs);
xml_text& xml_text::operator=(long long rhs);
xml_text& xml_text::operator=(unsigned long long rhs);

These operators simply call the right set function and return the attribute they’re called on; the return value of set is ignored, so errors are ignored.

This is an example of using xml_text object to modify text contents (samples/text.cpp):

// change project version
project.child("version").text() = 1.2;

// add description element and set the contents
// note that we do not have to explicitly add the node_pcdata child
project.append_child("description").text().set("a test project");

6.6. Cloning nodes/attributes

With the help of previously described functions, it is possible to create trees with any contents and structure, including cloning the existing data. However since this is an often needed operation, pugixml provides built-in node/attribute cloning facilities. Since nodes and attributes do not exist without a document tree, you can’t create a standalone copy - you have to immediately insert it somewhere in the tree. For this, you can use one of the following functions:

xml_attribute xml_node::append_copy(const xml_attribute& proto);
xml_attribute xml_node::prepend_copy(const xml_attribute& proto);
xml_attribute xml_node::insert_copy_after(const xml_attribute& proto, const xml_attribute& attr);
xml_attribute xml_node::insert_copy_before(const xml_attribute& proto, const xml_attribute& attr);

xml_node xml_node::append_copy(const xml_node& proto);
xml_node xml_node::prepend_copy(const xml_node& proto);
xml_node xml_node::insert_copy_after(const xml_node& proto, const xml_node& node);
xml_node xml_node::insert_copy_before(const xml_node& proto, const xml_node& node);

These functions mirror the structure of append_child, prepend_child, insert_child_before and related functions - they take the handle to the prototype object, which is to be cloned, insert a new attribute/node at the appropriate place, and then copy the attribute data or the whole node subtree to the new object. The functions return the handle to the resulting duplicate object, or null handle on failure.

The attribute is copied along with the name and value; the node is copied along with its type, name and value; additionally attribute list and all children are recursively cloned, resulting in the deep subtree clone. The prototype object can be a part of the same document, or a part of any other document.

The failure conditions resemble those of append_child, insert_child_before and related functions, consult their documentation for more information. There are additional caveats specific to cloning functions:

  • Cloning null handles results in operation failure;

  • Node cloning starts with insertion of the node of the same type as that of the prototype; for this reason, cloning functions can not be directly used to clone entire documents, since node_document is not a valid insertion type. The example below provides a workaround.

  • It is possible to copy a subtree as a child of some node inside this subtree, i.e. node.append_copy(node.parent().parent());. This is a valid operation, and it results in a clone of the subtree in the state before cloning started, i.e. no infinite recursion takes place.

This is an example with one possible implementation of include tags in XML (samples/include.cpp). It illustrates node cloning and usage of other document modification functions:

bool load_preprocess(pugi::xml_document& doc, const char* path);

bool preprocess(pugi::xml_node node)
{
    for (pugi::xml_node child = node.first_child(); child; )
    {
        if (child.type() == pugi::node_pi && strcmp(child.name(), "include") == 0)
        {
            pugi::xml_node include = child;

            // load new preprocessed document (note: ideally this should handle relative paths)
            const char* path = include.value();

            pugi::xml_document doc;
            if (!load_preprocess(doc, path)) return false;

            // insert the comment marker above include directive
            node.insert_child_before(pugi::node_comment, include).set_value(path);

            // copy the document above the include directive (this retains the original order!)
            for (pugi::xml_node ic = doc.first_child(); ic; ic = ic.next_sibling())
            {
                node.insert_copy_before(ic, include);
            }

            // remove the include node and move to the next child
            child = child.next_sibling();

            node.remove_child(include);
        }
        else
        {
            if (!preprocess(child)) return false;

            child = child.next_sibling();
        }
    }

    return true;
}

bool load_preprocess(pugi::xml_document& doc, const char* path)
{
    pugi::xml_parse_result result = doc.load_file(path, pugi::parse_default | pugi::parse_pi); // for <?include?>

    return result ? preprocess(doc) : false;
}

6.7. Moving nodes

Sometimes instead of cloning a node you need to move an existing node to a different position in a tree. This can be accomplished by copying the node and removing the original; however, this is expensive since it results in a lot of extra operations. For moving nodes within the same document tree, you can use of the following functions instead:

xml_node xml_node::append_move(const xml_node& moved);
xml_node xml_node::prepend_move(const xml_node& moved);
xml_node xml_node::insert_move_after(const xml_node& moved, const xml_node& node);
xml_node xml_node::insert_move_before(const xml_node& moved, const xml_node& node);

These functions mirror the structure of append_copy, prepend_copy, insert_copy_before and insert_copy_after - they take the handle to the moved object and move it to the appropriate place with all attributes and/or child nodes. The functions return the handle to the resulting object (which is the same as the moved object), or null handle on failure.

The failure conditions resemble those of append_child, insert_child_before and related functions, consult their documentation for more information. There are additional caveats specific to moving functions:

  • Moving null handles results in operation failure;

  • Moving is only possible for nodes that belong to the same document; attempting to move nodes between documents will fail.

  • insert_move_after and insert_move_before functions fail if the moved node is the same as the node argument (this operation would be a no-op otherwise).

  • It is impossible to move a subtree to a child of some node inside this subtree, i.e. node.append_move(node.parent().parent()); will fail.

6.8. Assembling document from fragments

pugixml provides several ways to assemble an XML document from other XML documents. Assuming there is a set of document fragments, represented as in-memory buffers, the implementation choices are as follows:

  • Use a temporary document to parse the data from a string, then clone the nodes to a destination node. For example:

    bool append_fragment(pugi::xml_node target, const char* buffer, size_t size)
    {
        pugi::xml_document doc;
        if (!doc.load_buffer(buffer, size)) return false;
    
        for (pugi::xml_node child = doc.first_child(); child; child = child.next_sibling())
            target.append_copy(child);
    }
  • Cache the parsing step - instead of keeping in-memory buffers, keep document objects that already contain the parsed fragment:

    bool append_fragment(pugi::xml_node target, const pugi::xml_document& cached_fragment)
    {
        for (pugi::xml_node child = cached_fragment.first_child(); child; child = child.next_sibling())
            target.append_copy(child);
    }
  • Use xml_node::append_buffer directly:

    xml_parse_result xml_node::append_buffer(const void* contents, size_t size, unsigned int options = parse_default, xml_encoding encoding = encoding_auto);

The first method is more convenient, but slower than the other two. The relative performance of append_copy and append_buffer depends on the buffer format - usually append_buffer is faster if the buffer is in native encoding (UTF-8 or wchar_t, depending on PUGIXML_WCHAR_MODE). At the same time it might be less efficient in terms of memory usage - the implementation makes a copy of the provided buffer, and the copy has the same lifetime as the document - the memory used by that copy will be reclaimed after the document is destroyed, but no sooner. Even deleting all nodes in the document, including the appended ones, won’t reclaim the memory.

append_buffer behaves in the same way as xml_document::load_buffer - the input buffer is a byte buffer, with size in bytes; the buffer is not modified and can be freed after the function returns.

Since append_buffer needs to append child nodes to the current node, it only works if the current node is either document or element node. Calling append_buffer on a node with any other type results in an error with status_append_invalid_root status.

7. Saving document

Often after creating a new document or loading the existing one and processing it, it is necessary to save the result back to file. Also it is occasionally useful to output the whole document or a subtree to some stream; use cases include debug printing, serialization via network or other text-oriented medium, etc. pugixml provides several functions to output any subtree of the document to a file, stream or another generic transport interface; these functions allow to customize the output format (see Output options), and also perform necessary encoding conversions (see Encodings). This section documents the relevant functionality.

Before writing to the destination the node/attribute data is properly formatted according to the node type; all special XML symbols, such as < and &, are properly escaped (unless format_no_escapes flag is set). In order to guard against forgotten node/attribute names, empty node/attribute names are printed as ":anonymous". For well-formed output, make sure all node and attribute names are set to meaningful values.

CDATA sections with values that contain "]]>" are split into several sections as follows: section with value "pre]]>post" is written as <![CDATA[pre]]]]><![CDATA[>post]]>. While this alters the structure of the document (if you load the document after saving it, there will be two CDATA sections instead of one), this is the only way to escape CDATA contents.

7.1. Saving document to a file

If you want to save the whole document to a file, you can use one of the following functions:

bool xml_document::save_file(const char* path, const char_t* indent = "\t", unsigned int flags = format_default, xml_encoding encoding = encoding_auto) const;
bool xml_document::save_file(const wchar_t* path, const char_t* indent = "\t", unsigned int flags = format_default, xml_encoding encoding = encoding_auto) const;

These functions accept file path as its first argument, and also three optional arguments, which specify indentation and other output options (see Output options) and output data encoding (see Encodings). The path has the target operating system format, so it can be a relative or absolute one, it should have the delimiters of the target system, it should have the exact case if the target file system is case-sensitive, etc. The functions return true on success and false if the file could not be opened or written to.

File path is passed to the system file opening function as is in case of the first function (which accepts const char* path); the second function either uses a special file opening function if it is provided by the runtime library or converts the path to UTF-8 and uses the system file opening function.

save_file opens the target file for writing, outputs the requested header (by default a document declaration is output, unless the document already has one), and then saves the document contents. Calling save_file is equivalent to creating an xml_writer_file object with FILE* handle as the only constructor argument and then calling save; see Saving document via writer interface for writer interface details.

This is a simple example of saving XML document to file (samples/save_file.cpp):

// save document to file
std::cout << "Saving result: " << doc.save_file("save_file_output.xml") << std::endl;

7.2. Saving document to C++ IOstreams

To enhance interoperability pugixml provides functions for saving document to any object which implements C++ std::ostream interface. This allows you to save documents to any standard C++ stream (i.e. file stream) or any third-party compliant implementation (i.e. Boost Iostreams). Most notably, this allows for easy debug output, since you can use std::cout stream as saving target. There are two functions, one works with narrow character streams, another handles wide character ones:

void xml_document::save(std::ostream& stream, const char_t* indent = "\t", unsigned int flags = format_default, xml_encoding encoding = encoding_auto) const;
void xml_document::save(std::wostream& stream, const char_t* indent = "\t", unsigned int flags = format_default) const;

save with std::ostream argument saves the document to the stream in the same way as save_file (i.e. with requested header and with encoding conversions). On the other hand, save with std::wstream argument saves the document to the wide stream with encoding_wchar encoding. Because of this, using save with wide character streams requires careful (usually platform-specific) stream setup (i.e. using the imbue function). Generally use of wide streams is discouraged, however it provides you with the ability to save documents to non-Unicode encodings, i.e. you can save Shift-JIS encoded data if you set the correct locale.

Calling save with stream target is equivalent to creating an xml_writer_stream object with stream as the only constructor argument and then calling save; see Saving document via writer interface for writer interface details.

This is a simple example of saving XML document to standard output (samples/save_stream.cpp):

// save document to standard output
std::cout << "Document:\n";
doc.save(std::cout);

7.3. Saving document via writer interface

All of the above saving functions are implemented in terms of writer interface. This is a simple interface with a single function, which is called several times during output process with chunks of document data as input:

class xml_writer
{
public:
    virtual void write(const void* data, size_t size) = 0;
};

void xml_document::save(xml_writer& writer, const char_t* indent = "\t", unsigned int flags = format_default, xml_encoding encoding = encoding_auto) const;

In order to output the document via some custom transport, for example sockets, you should create an object which implements xml_writer interface and pass it to save function. xml_writer::write function is called with a buffer as an input, where data points to buffer start, and size is equal to the buffer size in bytes. write implementation must write the buffer to the transport; it can not save the passed buffer pointer, as the buffer contents will change after write returns. The buffer contains the chunk of document data in the desired encoding.

write function is called with relatively large blocks (size is usually several kilobytes, except for the last block that may be small), so there is often no need for additional buffering in the implementation.

This is a simple example of custom writer for saving document data to STL string (samples/save_custom_writer.cpp); read the sample code for more complex examples:

struct xml_string_writer: pugi::xml_writer
{
    std::string result;

    virtual void write(const void* data, size_t size)
    {
        result.append(static_cast<const char*>(data), size);
    }
};

7.4. Saving a single subtree

While the previously described functions save the whole document to the destination, it is easy to save a single subtree. The following functions are provided:

void xml_node::print(std::ostream& os, const char_t* indent = "\t", unsigned int flags = format_default, xml_encoding encoding = encoding_auto, unsigned int depth = 0) const;
void xml_node::print(std::wostream& os, const char_t* indent = "\t", unsigned int flags = format_default, unsigned int depth = 0) const;
void xml_node::print(xml_writer& writer, const char_t* indent = "\t", unsigned int flags = format_default, xml_encoding encoding = encoding_auto, unsigned int depth = 0) const;

These functions have the same arguments with the same meaning as the corresponding xml_document::save functions, and allow you to save the subtree to either a C++ IOstream or to any object that implements xml_writer interface.

Saving a subtree differs from saving the whole document: the process behaves as if format_write_bom is off, and format_no_declaration is on, even if actual values of the flags are different. This means that BOM is not written to the destination, and document declaration is only written if it is the node itself or is one of node’s children. Note that this also holds if you’re saving a document; this example (samples/save_subtree.cpp) illustrates the difference:

// get a test document
pugi::xml_document doc;
doc.load_string("<foo bar='baz'><call>hey</call></foo>");

// print document to standard output (prints <?xml version="1.0"?><foo bar="baz"><call>hey</call></foo>)
doc.save(std::cout, "", pugi::format_raw);
std::cout << std::endl;

// print document to standard output as a regular node (prints <foo bar="baz"><call>hey</call></foo>)
doc.print(std::cout, "", pugi::format_raw);
std::cout << std::endl;

// print a subtree to standard output (prints <call>hey</call>)
doc.child("foo").child("call").print(std::cout, "", pugi::format_raw);
std::cout << std::endl;

7.5. Output options

All saving functions accept the optional parameter flags. This is a bitmask that customizes the output format; you can select the way the document nodes are printed and select the needed additional information that is output before the document contents.

Note
You should use the usual bitwise arithmetics to manipulate the bitmask: to enable a flag, use mask | flag; to disable a flag, use mask & ~flag.

These flags control the resulting tree contents:

  • format_indent determines if all nodes should be indented with the indentation string (this is an additional parameter for all saving functions, and is "\t" by default). If this flag is on, the indentation string is printed several times before every node, where the amount of indentation depends on the node’s depth relative to the output subtree. This flag has no effect if format_raw is enabled. This flag is on by default.

  • format_indent_attributes determines if all attributes should be printed on a new line, indented with the indentation string according to the attribute’s depth. This flag implies format_indent. This flag has no effect if format_raw is enabled. This flag is off by default.

  • format_raw switches between formatted and raw output. If this flag is on, the nodes are not indented in any way, and also no newlines that are not part of document text are printed. Raw mode can be used for serialization where the result is not intended to be read by humans; also it can be useful if the document was parsed with parse_ws_pcdata flag, to preserve the original document formatting as much as possible. This flag is off by default.

  • format_no_escapes disables output escaping for attribute values and PCDATA contents. If this flag is off, special symbols (", &, <, >) and all non-printable characters (those with codepoint values less than 32) are converted to XML escape sequences (i.e. &amp;) during output. If this flag is on, no text processing is performed; therefore, output XML can be malformed if output contents contains invalid symbols (i.e. having a stray < in the PCDATA will make the output malformed). This flag is off by default.

  • format_no_empty_element_tags determines if start/end tags should be output instead of empty element tags for empty elements (that is, elements with no children). This flag is off by default.

  • format_skip_control_chars enables skipping characters belonging to range [0; 32) instead of "&#xNN;" encoding. This flag is off by default.

  • format_attribute_single_quote enables using single quotes ' instead of double quotes " for enclosing attribute values. This flag is off by default.

These flags control the additional output information:

  • format_no_declaration disables default node declaration output. By default, if the document is saved via save or save_file function, and it does not have any document declaration, a default declaration is output before the document contents. Enabling this flag disables this declaration. This flag has no effect in xml_node::print functions: they never output the default declaration. This flag is off by default.

  • format_write_bom enables Byte Order Mark (BOM) output. By default, no BOM is output, so in case of non UTF-8 encodings the resulting document’s encoding may not be recognized by some parsers and text editors, if they do not implement sophisticated encoding detection. Enabling this flag adds an encoding-specific BOM to the output. This flag has no effect in xml_node::print functions: they never output the BOM. This flag is off by default.

  • format_save_file_text changes the file mode when using save_file function. By default, file is opened in binary mode, which means that the output file will contain platform-independent newline \n (ASCII 10). If this flag is on, file is opened in text mode, which on some systems changes the newline format (i.e. on Windows you can use this flag to output XML documents with \r\n (ASCII 13 10) newlines. This flag is off by default.

Additionally, there is one predefined option mask:

  • format_default is the default set of flags, i.e. it has all options set to their default values. It sets formatted output with indentation, without BOM and with default node declaration, if necessary.

This is an example that shows the outputs of different output options (samples/save_options.cpp):

// get a test document
pugi::xml_document doc;
doc.load_string("<foo bar='baz'><call>hey</call></foo>");

// default options; prints
// <?xml version="1.0"?>
// <foo bar="baz">
//         <call>hey</call>
// </foo>
doc.save(std::cout);
std::cout << std::endl;

// default options with custom indentation string; prints
// <?xml version="1.0"?>
// <foo bar="baz">
// --<call>hey</call>
// </foo>
doc.save(std::cout, "--");
std::cout << std::endl;

// default options without indentation; prints
// <?xml version="1.0"?>
// <foo bar="baz">
// <call>hey</call>
// </foo>
doc.save(std::cout, "\t", pugi::format_default & ~pugi::format_indent); // can also pass "" instead of indentation string for the same effect
std::cout << std::endl;

// raw output; prints
// <?xml version="1.0"?><foo bar="baz"><call>hey</call></foo>
doc.save(std::cout, "\t", pugi::format_raw);
std::cout << std::endl << std::endl;

// raw output without declaration; prints
// <foo bar="baz"><call>hey</call></foo>
doc.save(std::cout, "\t", pugi::format_raw | pugi::format_no_declaration);
std::cout << std::endl;

7.6. Encodings

pugixml supports all popular Unicode encodings (UTF-8, UTF-16 (big and little endian), UTF-32 (big and little endian); UCS-2 is naturally supported since it’s a strict subset of UTF-16) and handles all encoding conversions during output. The output encoding is set via the encoding parameter of saving functions, which is of type xml_encoding. The possible values for the encoding are documented in Encodings; the only flag that has a different meaning is encoding_auto.

While all other flags set the exact encoding, encoding_auto is meant for automatic encoding detection. The automatic detection does not make sense for output encoding, since there is usually nothing to infer the actual encoding from, so here encoding_auto means UTF-8 encoding, which is the most popular encoding for XML data storage. This is also the default value of output encoding; specify another value if you do not want UTF-8 encoded output.

Also note that wide stream saving functions do not have encoding argument and always assume encoding_wchar encoding.

Note
The current behavior for Unicode conversion is to skip all invalid UTF sequences during conversion. This behavior should not be relied upon; if your node/attribute names do not contain any valid UTF sequences, they may be output as if they are empty, which will result in malformed XML document.

7.7. Customizing document declaration

When you are saving the document using xml_document::save() or xml_document::save_file(), a default XML document declaration is output, if format_no_declaration is not specified and if the document does not have a declaration node. However, the default declaration is not customizable. If you want to customize the declaration output, you need to create the declaration node yourself.

Note
By default the declaration node is not added to the document during parsing. If you just need to preserve the original declaration node, you have to add the flag parse_declaration to the parsing flags; the resulting document will contain the original declaration node, which will be output during saving.

Declaration node is a node with type node_declaration; it behaves like an element node in that it has attributes with values (but it does not have child nodes). Therefore setting custom version, encoding or standalone declaration involves adding attributes and setting attribute values.

This is an example that shows how to create a custom declaration node (samples/save_declaration.cpp):

// get a test document
pugi::xml_document doc;
doc.load_string("<foo bar='baz'><call>hey</call></foo>");

// add a custom declaration node
pugi::xml_node decl = doc.prepend_child(pugi::node_declaration);
decl.append_attribute("version") = "1.0";
decl.append_attribute("encoding") = "UTF-8";
decl.append_attribute("standalone") = "no";

// <?xml version="1.0" encoding="UTF-8" standalone="no"?>
// <foo bar="baz">
//         <call>hey</call>
// </foo>
doc.save(std::cout);
std::cout << std::endl;

8. XPath

If the task at hand is to select a subset of document nodes that match some criteria, it is possible to code a function using the existing traversal functionality for any practical criteria. However, often either a data-driven approach is desirable, in case the criteria are not predefined and come from a file, or it is inconvenient to use traversal interfaces and a higher-level DSL is required. There is a standard language for XML processing, XPath, that can be useful for these cases. pugixml implements an almost complete subset of XPath 1.0. Because of differences in document object model and some performance implications, there are minor violations of the official specifications, which can be found in Conformance to W3C specification. The rest of this section describes the interface for XPath functionality. Please note that if you wish to learn to use XPath language, you have to look for other tutorials or manuals; for example, you can read W3Schools XPath tutorial or the XPath 1.0 specification.

8.1. XPath types

Each XPath expression can have one of the following types: boolean, number, string or node set. Boolean type corresponds to bool type, number type corresponds to double type, string type corresponds to either std::string or std::wstring, depending on whether wide character interface is enabled, and node set corresponds to xpath_node_set type. There is an enumeration, xpath_value_type, which can take the values xpath_type_boolean, xpath_type_number, xpath_type_string or xpath_type_node_set, accordingly.

Because an XPath node can be either a node or an attribute, there is a special type, xpath_node, which is a discriminated union of these types. A value of this type contains two node handles, one of xml_node type, and another one of xml_attribute type; at most one of them can be non-null. The accessors to get these handles are available:

xml_node xpath_node::node() const;
xml_attribute xpath_node::attribute() const;

XPath nodes can be null, in which case both accessors return null handles.

Note that as per XPath specification, each XPath node has a parent, which can be retrieved via this function:

xml_node xpath_node::parent() const;

parent function returns the node’s parent if the XPath node corresponds to xml_node handle (equivalent to node().parent()), or the node to which the attribute belongs to, if the XPath node corresponds to xml_attribute handle. For null nodes, parent returns null handle.

Like node and attribute handles, XPath node handles can be implicitly cast to boolean-like object to check if it is a null node, and also can be compared for equality with each other.

You can also create XPath nodes with one of the three constructors: the default constructor, the constructor that takes node argument, and the constructor that takes attribute and node arguments (in which case the attribute must belong to the attribute list of the node). The constructor from xml_node is implicit, so you can usually pass xml_node to functions that expect xpath_node. Apart from that you usually don’t need to create your own XPath node objects, since they are returned to you via selection functions.

XPath expressions operate not on single nodes, but instead on node sets. A node set is a collection of nodes, which can be optionally ordered in either a forward document order or a reverse one. Document order is defined in XPath specification; an XPath node is before another node in document order if it appears before it in XML representation of the corresponding document.

Node sets are represented by xpath_node_set object, which has an interface that resembles one of sequential random-access containers. It has an iterator type along with usual begin/past-the-end iterator accessors:

typedef const xpath_node* xpath_node_set::const_iterator;
const_iterator xpath_node_set::begin() const;
const_iterator xpath_node_set::end() const;

And it also can be iterated via indices, just like std::vector:

const xpath_node& xpath_node_set::operator[](size_t index) const;
size_t xpath_node_set::size() const;
bool xpath_node_set::empty() const;

All of the above operations have the same semantics as that of std::vector: the iterators are random-access, all of the above operations are constant time, and accessing the element at index that is greater or equal than the set size results in undefined behavior. You can use both iterator-based and index-based access for iteration, however the iterator-based one can be faster.

The order of iteration depends on the order of nodes inside the set; the order can be queried via the following function:

enum xpath_node_set::type_t {type_unsorted, type_sorted, type_sorted_reverse};
type_t xpath_node_set::type() const;

type function returns the current order of nodes; type_sorted means that the nodes are in forward document order, type_sorted_reverse means that the nodes are in reverse document order, and type_unsorted means that neither order is guaranteed (nodes can accidentally be in a sorted order even if type() returns type_unsorted). If you require a specific order of iteration, you can change it via sort function:

void xpath_node_set::sort(bool reverse = false);

Calling sort sorts the nodes in either forward or reverse document order, depending on the argument; after this call type() will return type_sorted or type_sorted_reverse.

Often the actual iteration is not needed; instead, only the first element in document order is required. For this, a special accessor is provided:

xpath_node xpath_node_set::first() const;

This function returns the first node in forward document order from the set, or null node if the set is empty. Note that while the result of the node does not depend on the order of nodes in the set (i.e. on the result of type()), the complexity does - if the set is sorted, the complexity is constant, otherwise it is linear in the number of elements or worse.

While in the majority of cases the node set is returned by XPath functions, sometimes there is a need to manually construct a node set. For such cases, a constructor is provided which takes an iterator range (const_iterator is a typedef for const xpath_node*), and an optional type:

xpath_node_set::xpath_node_set(const_iterator begin, const_iterator end, type_t type = type_unsorted);

The constructor copies the specified range and sets the specified type. The objects in the range are not checked in any way; you’ll have to ensure that the range contains no duplicates, and that the objects are sorted according to the type parameter. Otherwise XPath operations with this set may produce unexpected results.

8.2. Selecting nodes via XPath expression

If you want to select nodes that match some XPath expression, you can do it with the following functions:

xpath_node xml_node::select_node(const char_t* query, xpath_variable_set* variables = 0) const;
xpath_node_set xml_node::select_nodes(const char_t* query, xpath_variable_set* variables = 0) const;

select_nodes function compiles the expression and then executes it with the node as a context node, and returns the resulting node set. select_node returns only the first node in document order from the result, and is equivalent to calling select_nodes(query).first(). If the XPath expression does not match anything, or the node handle is null, select_nodes returns an empty set, and select_node returns null XPath node.

If exception handling is not disabled, both functions throw xpath_exception if the query can not be compiled or if it returns a value with type other than node set; see Error handling for details.

While compiling expressions is fast, the compilation time can introduce a significant overhead if the same expression is used many times on small subtrees. If you’re doing many similar queries, consider compiling them into query objects (see Using query objects for further reference). Once you get a compiled query object, you can pass it to select functions instead of an expression string:

xpath_node xml_node::select_node(const xpath_query& query) const;
xpath_node_set xml_node::select_nodes(const xpath_query& query) const;

If exception handling is not disabled, both functions throw xpath_exception if the query returns a value with type other than node set.

This is an example of selecting nodes using XPath expressions (samples/xpath_select.cpp):

pugi::xpath_node_set tools = doc.select_nodes("/Profile/Tools/Tool[@AllowRemote='true' and @DeriveCaptionFrom='lastparam']");

std::cout << "Tools:\n";

for (pugi::xpath_node_set::const_iterator it = tools.begin(); it != tools.end(); ++it)
{
    pugi::xpath_node node = *it;
    std::cout << node.node().attribute("Filename").value() << "\n";
}

pugi::xpath_node build_tool = doc.select_node("//Tool[contains(Description, 'build system')]");

if (build_tool)
    std::cout << "Build tool: " << build_tool.node().attribute("Filename").value() << "\n";

8.3. Using query objects

When you call select_nodes with an expression string as an argument, a query object is created behind the scenes. A query object represents a compiled XPath expression. Query objects can be needed in the following circumstances:

  • You can precompile expressions to query objects to save compilation time if it becomes an issue;

  • You can use query objects to evaluate XPath expressions which result in booleans, numbers or strings;

  • You can get the type of expression value via query object.

Query objects correspond to xpath_query type. They are immutable and non-copyable: they are bound to the expression at creation time and can not be cloned. If you want to put query objects in a container, either allocate them on heap via new operator and store pointers to xpath_query in the container, or use a C11 compiler (query objects are movable in C11).

You can create a query object with the constructor that takes XPath expression as an argument:

explicit xpath_query::xpath_query(const char_t* query, xpath_variable_set* variables = 0);

The expression is compiled and the compiled representation is stored in the new query object. If compilation fails, xpath_exception is thrown if exception handling is not disabled (see Error handling for details). After the query is created, you can query the type of the evaluation result using the following function:

xpath_value_type xpath_query::return_type() const;

You can evaluate the query using one of the following functions:

bool xpath_query::evaluate_boolean(const xpath_node& n) const;
double xpath_query::evaluate_number(const xpath_node& n) const;
string_t xpath_query::evaluate_string(const xpath_node& n) const;
xpath_node_set xpath_query::evaluate_node_set(const xpath_node& n) const;
xpath_node xpath_query::evaluate_node(const xpath_node& n) const;

All functions take the context node as an argument, compute the expression and return the result, converted to the requested type. According to XPath specification, value of any type can be converted to boolean, number or string value, but no type other than node set can be converted to node set. Because of this, evaluate_boolean, evaluate_number and evaluate_string always return a result, but evaluate_node_set and evaluate_node result in an error if the return type is not node set (see Error handling).

Note
Calling node.select_nodes("query") is equivalent to calling xpath_query("query").evaluate_node_set(node). Calling node.select_node("query") is equivalent to calling xpath_query("query").evaluate_node(node).

Note that evaluate_string function returns the STL string; as such, it’s not available in PUGIXML_NO_STL mode and also usually allocates memory. There is another string evaluation function:

size_t xpath_query::evaluate_string(char_t* buffer, size_t capacity, const xpath_node& n) const;

This function evaluates the string, and then writes the result to buffer (but at most capacity characters); then it returns the full size of the result in characters, including the terminating zero. If capacity is not 0, the resulting buffer is always zero-terminated. You can use this function as follows:

  • First call the function with buffer = 0 and capacity = 0; then allocate the returned amount of characters, and call the function again, passing the allocated storage and the amount of characters;

  • First call the function with small buffer and buffer capacity; then, if the result is larger than the capacity, the output has been trimmed, so allocate a larger buffer and call the function again.

This is an example of using query objects (samples/xpath_query.cpp):

// Select nodes via compiled query
pugi::xpath_query query_remote_tools("/Profile/Tools/Tool[@AllowRemote='true']");

pugi::xpath_node_set tools = query_remote_tools.evaluate_node_set(doc);
std::cout << "Remote tool: ";
tools[2].node().print(std::cout);

// Evaluate numbers via compiled query
pugi::xpath_query query_timeouts("sum(//Tool/@Timeout)");
std::cout << query_timeouts.evaluate_number(doc) << std::endl;

// Evaluate strings via compiled query for different context nodes
pugi::xpath_query query_name_valid("string-length(substring-before(@Filename, '_')) > 0 and @OutputFileMasks");
pugi::xpath_query query_name("concat(substring-before(@Filename, '_'), ' produces ', @OutputFileMasks)");

for (pugi::xml_node tool = doc.first_element_by_path("Profile/Tools/Tool"); tool; tool = tool.next_sibling())
{
    std::string s = query_name.evaluate_string(tool);

    if (query_name_valid.evaluate_boolean(tool)) std::cout << s << std::endl;
}

8.4. Using variables

XPath queries may contain references to variables; this is useful if you want to use queries that depend on some dynamic parameter without manually preparing the complete query string, or if you want to reuse the same query object for similar queries.

Variable references have the form $name; in order to use them, you have to provide a variable set, which includes all variables present in the query with correct types. This set is passed to xpath_query constructor or to select_nodes/select_node functions:

explicit xpath_query::xpath_query(const char_t* query, xpath_variable_set* variables = 0);
xpath_node xml_node::select_node(const char_t* query, xpath_variable_set* variables = 0) const;
xpath_node_set xml_node::select_nodes(const char_t* query, xpath_variable_set* variables = 0) const;

If you’re using query objects, you can change the variable values before evaluate/select calls to change the query behavior.

Note
The variable set pointer is stored in the query object; you have to ensure that the lifetime of the set exceeds that of query object.

Variable sets correspond to xpath_variable_set type, which is essentially a variable container.

You can add new variables with the following function:

xpath_variable* xpath_variable_set::add(const char_t* name, xpath_value_type type);

The function tries to add a new variable with the specified name and type; if the variable with such name does not exist in the set, the function adds a new variable and returns the variable handle; if there is already a variable with the specified name, the function returns the variable handle if variable has the specified type. Otherwise the function returns null pointer; it also returns null pointer on allocation failure.

New variables are assigned the default value which depends on the type: 0 for numbers, false for booleans, empty string for strings and empty set for node sets.

You can get the existing variables with the following functions:

xpath_variable* xpath_variable_set::get(const char_t* name);
const xpath_variable* xpath_variable_set::get(const char_t* name) const;

The functions return the variable handle, or null pointer if the variable with the specified name is not found.

Additionally, there are the helper functions for setting the variable value by name; they try to add the variable with the corresponding type, if it does not exist, and to set the value. If the variable with the same name but with different type is already present, they return false; they also return false on allocation failure. Note that these functions do not perform any type conversions.

bool xpath_variable_set::set(const char_t* name, bool value);
bool xpath_variable_set::set(const char_t* name, double value);
bool xpath_variable_set::set(const char_t* name, const char_t* value);
bool xpath_variable_set::set(const char_t* name, const xpath_node_set& value);

The variable values are copied to the internal variable storage, so you can modify or destroy them after the functions return.

If setting variables by name is not efficient enough, or if you have to inspect variable information or get variable values, you can use variable handles. A variable corresponds to the xpath_variable type, and a variable handle is simply a pointer to xpath_variable.

In order to get variable information, you can use one of the following functions:

const char_t* xpath_variable::name() const;
xpath_value_type xpath_variable::type() const;

Note that each variable has a distinct type which is specified upon variable creation and can not be changed later.

In order to get variable value, you should use one of the following functions, depending on the variable type:

bool xpath_variable::get_boolean() const;
double xpath_variable::get_number() const;
const char_t* xpath_variable::get_string() const;
const xpath_node_set& xpath_variable::get_node_set() const;

These functions return the value of the variable. Note that no type conversions are performed; if the type mismatch occurs, a dummy value is returned (false for booleans, NaN for numbers, empty string for strings and empty set for node sets).

In order to set variable value, you should use one of the following functions, depending on the variable type:

bool xpath_variable::set(bool value);
bool xpath_variable::set(double value);
bool xpath_variable::set(const char_t* value);
bool xpath_variable::set(const xpath_node_set& value);

These functions modify the variable value. Note that no type conversions are performed; if the type mismatch occurs, the functions return false; they also return false on allocation failure. The variable values are copied to the internal variable storage, so you can modify or destroy them after the functions return.

This is an example of using variables in XPath queries (samples/xpath_variables.cpp):

// Select nodes via compiled query
pugi::xpath_variable_set vars;
vars.add("remote", pugi::xpath_type_boolean);

pugi::xpath_query query_remote_tools("/Profile/Tools/Tool[@AllowRemote = string($remote)]", &vars);

vars.set("remote", true);
pugi::xpath_node_set tools_remote = query_remote_tools.evaluate_node_set(doc);

vars.set("remote", false);
pugi::xpath_node_set tools_local = query_remote_tools.evaluate_node_set(doc);

std::cout << "Remote tool: ";
tools_remote[2].node().print(std::cout);

std::cout << "Local tool: ";
tools_local[0].node().print(std::cout);

// You can pass the context directly to select_nodes/select_node
pugi::xpath_node_set tools_local_imm = doc.select_nodes("/Profile/Tools/Tool[@AllowRemote = string($remote)]", &vars);

std::cout << "Local tool imm: ";
tools_local_imm[0].node().print(std::cout);

8.5. Error handling

There are two different mechanisms for error handling in XPath implementation; the mechanism used depends on whether exception support is disabled (this is controlled with PUGIXML_NO_EXCEPTIONS define).

By default, XPath functions throw xpath_exception object in case of errors; additionally, in the event any memory allocation fails, an std::bad_alloc exception is thrown. Also xpath_exception is thrown if the query is evaluated to a node set, but the return type is not node set. If the query constructor succeeds (i.e. no exception is thrown), the query object is valid. Otherwise you can get the error details via one of the following functions:

virtual const char* xpath_exception::what() const noexcept;
const xpath_parse_result& xpath_exception::result() const;

If exceptions are disabled, then in the event of parsing failure the query is initialized to invalid state; you can test if the query object is valid by using it in a boolean expression: if (query) { …​ }. Additionally, you can get parsing result via the result() accessor:

const xpath_parse_result& xpath_query::result() const;

Without exceptions, evaluating invalid query results in false, empty string, NaN or an empty node set, depending on the type; evaluating a query as a node set results in an empty node set if the return type is not node set.

The information about parsing result is returned via xpath_parse_result object. It contains parsing status and the offset of last successfully parsed character from the beginning of the source stream:

struct xpath_parse_result
{
    const char* error;
    ptrdiff_t offset;

    operator bool() const;
    const char* description() const;
};

Parsing result is represented as the error message; it is either a null pointer, in case there is no error, or the error message in the form of ASCII zero-terminated string.

description() member function can be used to get the error message; it never returns the null pointer, so you can safely use description() even if query parsing succeeded. Note that description() returns a char string even in PUGIXML_WCHAR_MODE; you’ll have to call as_wide to get the wchar_t string.

In addition to the error message, parsing result has an offset member, which contains the offset of last successfully parsed character. This offset is in units of pugi::char_t (bytes for character mode, wide characters for wide character mode).

Parsing result object can be implicitly converted to bool like this: if (result) { …​ } else { …​ }.

This is an example of XPath error handling (samples/xpath_error.cpp):

// Exception is thrown for incorrect query syntax
try
{
    doc.select_nodes("//nodes[#true()]");
}
catch (const pugi::xpath_exception& e)
{
    std::cout << "Select failed: " << e.what() << std::endl;
}

// Exception is thrown for incorrect query semantics
try
{
    doc.select_nodes("(123)/next");
}
catch (const pugi::xpath_exception& e)
{
    std::cout << "Select failed: " << e.what() << std::endl;
}

// Exception is thrown for query with incorrect return type
try
{
    doc.select_nodes("123");
}
catch (const pugi::xpath_exception& e)
{
    std::cout << "Select failed: " << e.what() << std::endl;
}

8.6. Conformance to W3C specification

Because of the differences in document object models, performance considerations and implementation complexity, pugixml does not provide a fully conformant XPath 1.0 implementation. This is the current list of incompatibilities:

  • Consecutive text nodes sharing the same parent are not merged, i.e. in <node>text1 <![CDATA[data]]> text2</node> node should have one text node child, but instead has three.

  • Since the document type declaration is not used for parsing, id() function always returns an empty node set.

  • Namespace nodes are not supported (affects namespace:: axis).

  • Name tests are performed on QNames in XML document instead of expanded names; for <foo xmlns:ns1='uri' xmlns:ns2='uri'><ns1:child/><ns2:child/></foo>, query foo/ns1:* will return only the first child, not both of them. Compliant XPath implementations can return both nodes if the user provides appropriate namespace declarations.

  • String functions consider a character to be either a single char value or a single wchar_t value, depending on the library configuration; this means that some string functions are not fully Unicode-aware. This affects substring(), string-length() and translate() functions.

9. Changelog

v1.15 2024-01-10

Maintenance release. Changes:

  • Improvements:

    1. Many xml_attribute:: and xml_node:: functions now transparently support std::string_view and std::string when C++17 support is detected.

  • CMake improvements:

    1. Improve pkg-config file generation for NixOS

    2. PUGIXML_BUILD_APPLE_FRAMEWORK CMake option can be used to build pugixml as .xcframework

    3. PUGIXML_INSTALL CMake option can be used to disable installation targets

  • Compatibility improvements:

    1. Fix clang/gcc warnings -Wzero-as-null-pointer-constant, -Wuseless-cast, -Wshorten-64-to-32

    2. Fix unreferenced function warnings in PUGIXML_NO_STL configuration

    3. Fix CMake 3.31 deprecation warnings

    4. Stop using deprecated throw() when noexcept is available

v1.14 2023-10-01

Maintenance release. Changes:

  • Improvements:

    1. xml_attribute::set_name and xml_node::set_name now have overloads that accept pointer to non-null-terminated string and size

    2. Implement parse_merge_pcdata parsing mode in which PCDATA contents is merged into a single node when original document had comments that were skipped during parsing

    3. xml_document::load_file now returns a more consistent error status when given a path to a folder

  • Bug fixes:

    1. Fix assertion in XPath number→string conversion when using non-English locales

    2. Fix PUGIXML_STATIC_CRT CMake option to correctly select static CRT when using MSVC and recent CMake

  • Compatibility improvements:

    1. Fix GCC 2.95/3.3 builds

    2. Fix CMake 3.27 deprecation warnings

    3. Fix XCode 14 sprintf deprecation warning when compiling in C++03 mode

    4. Fix clang/gcc warnings -Wweak-vtables, -Wreserved-macro-identifier

v1.13 2022-11-01

Maintenance release. Changes:

  • Improvements:

    1. xml_attribute::set_value, xml_node::set_value and xml_text::set now have overloads that accept pointer to non-null-terminated string and size

    2. Improve performance of tree traversal when using compact mode (PUGIXML_COMPACT)

  • Bug fixes:

    1. Fix error handling in xml_document::save_file that could result in the function succeeding while running out of disk space

    2. Fix memory leak during error handling of some out-of-memory conditions during xml_document::load

  • Compatibility improvements:

    1. Fix exported symbols in CMake DLL builds when using CMake

    2. Fix exported symbols in CMake shared object builds when using -fvisibility=hidden

v1.12 2022-02-09

Maintenance release. Changes:

  • Bug fixes:

    1. Fix a bug in xml_document move construction when the source of the move is empty

    2. Fix const-correctness issues with iterator objects to support C++20 ranges

  • XPath improvements:

    1. Improved detection of overly complex queries that may result in stack overflow during parsing

  • Compatibility improvements:

    1. Fix Cygwin support for DLL builds

    2. Fix Windows CE support

    3. Add NuGet builds and project files for VS2022

  • Build system changes

    1. All CMake options now have the prefix PUGIXML_. This may require changing dependent build configurations.

    2. Many build settings are now exposed via CMake settings, most notably PUGIXML_COMPACT and PUGIXML_WCHAR_MODE can be set without changing pugiconfig.hpp

v1.11 2020-11-26

Maintenance release. Changes:

  • New features:

    1. Add xml_node::remove_attributes and xml_node::remove_children

    2. Add a way to customize floating point precision via xml_attribute::set and xml_text::set overloads

  • XPath improvements:

    1. XPath parser now limits recursion depth which prevents stack overflow on malicious queries

  • Compatibility improvements:

    1. Fix Visual Studio warnings when built using clang-cl compiler

    2. Fix Wconversion warnings in gcc

    3. Fix Wzero-as-null-pointer-constant warnings in pugixml.hpp

    4. Work around several static analysis false positives

  • Build system changes

    1. The CMake package for pugixml now provides a pugixml::pugixml target rather than a pugixml target. A compatibility pugixml target is provided if at least version 1.11 is not requested.

v1.10 2019-09-15

Maintenance release. Changes:

  • Behavior changes:

    1. Tab characters (ASCII 9) in attribute values are now encoded as '&#9;' to survive roundtripping

    2. > characters are no longer escaped in attribute values

  • New features:

    1. Add Visual Studio .natvis files to improve debugging experience

    2. CMake improvements (USE_POSTFIX and BUILD_SHARED_AND_STATIC_LIBS options for building multiple versions and pkg-config tweaks)

    3. Add format_skip_control_chars formatting flag to skip non-printable ASCII characters that are invalid to use in well-formed XML files

    4. Add format_attribute_single_quote formatting flag to use single quotes for attribute values instead of default double quotes.

  • XPath improvements:

    1. XPath union now results in a stable order that doesn’t depend on memory allocations; crucially, this may require sorting the output of XPath query operation if you rely on the document-ordered traversal

    2. Improve performance of XPath union operation, making it ~2x faster

  • Compatibility improvements:

    1. Fix Visual Studio warnings when built in a DLL configuration

    2. Fix static analysis false positives in Coverity and clang

    3. Fix Wdouble-promotion warnings in gcc

    4. Add Visual Studio 2019 support for NuGet packages

v1.9 2018-04-04

Maintenance release. Changes:

  • Specification changes:

    1. xml_document::load(const char*) (deprecated in 1.5) now has deprecated attribute; use xml_document::load_string instead

    2. xml_node::select_single_node (deprecated in 1.5) now has deprecated attribute; use xml_node::select_node instead

  • New features:

    1. Add move semantics support for xml_document and improve move semantics support for other objects

    2. CMake build now exports include directories

    3. CMake build with BUILD_SHARED_LIBS=ON now uses dllexport attribute for MSVC

  • XPath improvements:

    1. Rework parser/evaluator to not rely on exceptional control flow; longjmp is no longer used when exceptions are disabled

    2. Improve error messages for certain invalid expressions such as .[1] or (1

    3. Minor performance improvements

  • Compatibility improvements:

    1. Fix Texas Instruments compiler warnings

    2. Fix compilation issues with limits.h for some versions of gcc

    3. Fix compilation issues with Clang/C2

    4. Fix implicit fallthrough warnings in gcc 7

    5. Fix unknown attribute directive warnings in gcc 8

    6. Fix cray++ compiler errors

    7. Fix unsigned integer overflow errors with -fsanitize=integer

    8. Fix undefined behavior sanitizer issues in compact mode

v1.8 2016-11-24

Maintenance release. Changes:

  • Specification changes:

    1. When printing empty elements, a space is no longer added before / in format_raw mode

  • New features:

    1. Added parse_embed_pcdata parsing mode in which PCDATA value is stored in the element node if possible (significantly reducing memory consumption for some documents)

    2. Added auto-detection support for Latin-1 (ISO-8859-1) encoding during parsing

    3. Added format_no_empty_element_tags formatting flag that outputs start/end tags instead of empty element tags for empty elements

  • Performance improvements:

    1. Minor memory allocation improvements (yielding up to 1% memory savings in some cases)

  • Compatibility improvements:

    1. Fixed compilation issues for Borland C++ 5.4

    2. Fixed compilation issues for some distributions of MinGW 3.8

    3. Fixed various Clang/GCC warnings

    4. Enabled move semantics support for XPath objects for MSVC 2010 and above

v1.7 2015-10-19

Major release, featuring performance and memory improvements along with some new features. Changes:

  • Compact mode:

    1. Introduced a new tree storage mode that takes significantly less memory (2-5x smaller DOM) at some performance cost.

    2. The mode can be enabled using PUGIXML_COMPACT define.

  • New integer parsing/formatting implementation:

    1. Functions that convert from and to integers (e.g. as_int/set_value) do not rely on CRT any more.

    2. New implementation is 3-5x faster and is always correct wrt overflow or underflow. This is a behavior change - where previously as_uint() would return UINT_MAX on a value "-1", it now returns 0.

  • New features:

    1. XPath objects (xpath_query, xpath_node_set, xpath_variable_set) are now movable if your compiler supports C++11. Additionally, xpath_variable_set is copyable.

    2. Added format_indent_attributes that makes the resulting XML friendlier to line diff/merge tools.

    3. Added a variant of xml_node::attribute function with a hint that can improve lookup performance.

    4. Custom allocation functions are now allowed (but not required) to throw instead of returning a null pointer.

  • Bug fixes:

    1. Fix Clang 3.7 crashes in out-of-memory cases (C++ DR 1748)

    2. Fix XPath crashes on SPARC64 (and other 32-bit architectures where doubles have to be aligned to 8 bytes)

    3. Fix xpath_node_set assignment to provide strong exception guarantee

    4. Fix saving for custom xml_writer implementations that can throw from write()

v1.6 2015-04-10

Maintenance release. Changes:

  • Specification changes:

    1. Attribute/text values now use more digits when printing floating point numbers to guarantee round-tripping.

    2. Text nodes no longer get extra surrounding whitespace when pretty-printing nodes with mixed contents

  • Bug fixes:

    1. Fixed translate and normalize-space XPath functions to no longer return internal NUL characters

    2. Fixed buffer overrun on malformed comments inside DOCTYPE sections

    3. DOCTYPE parsing can no longer run out of stack space on malformed inputs (XML parsing is now using bounded stack space)

    4. Adjusted processing instruction output to avoid malformed documents if the PI value contains ?>

v1.5 2014-11-27

Major release, featuring a lot of performance improvements and some new features.

  • Specification changes:

    1. xml_document::load(const char_t*) was renamed to load_string; the old method is still available and will be deprecated in a future release

    2. xml_node::select_single_node was renamed to select_node; the old method is still available and will be deprecated in a future release.

  • New features:

    1. Added xml_node::append_move and other functions for moving nodes within a document

    2. Added xpath_query::evaluate_node for evaluating queries with a single node as a result

  • Performance improvements:

    1. Optimized XML parsing (10-40% faster with clang/gcc, up to 10% faster with MSVC)

    2. Optimized memory consumption when copying nodes in the same document (string contents is now shared)

    3. Optimized node copying (10% faster for cross-document copies, 3x faster for inter-document copies; also it now consumes a constant amount of stack space)

    4. Optimized node output (60% faster; also it now consumes a constant amount of stack space)

    5. Optimized XPath allocation (query evaluation now results in fewer temporary allocations)

    6. Optimized XPath sorting (node set sorting is 2-3x faster in some cases)

    7. Optimized XPath evaluation (XPathMark suite is 100x faster; some commonly used queries are 3-4x faster)

  • Compatibility improvements:

    1. Fixed xml_node::offset_debug for corner cases

    2. Fixed undefined behavior while calling memcpy in some cases

    3. Fixed MSVC 2015 compilation warnings

    4. Fixed contrib/foreach.hpp for Boost 1.56.0

  • Bug fixes

    1. Adjusted comment output to avoid malformed documents if the comment value contains --

    2. Fix XPath sorting for documents that were constructed using append_buffer

    3. Fix load_file for wide-character paths with non-ASCII characters in MinGW with C++11 mode enabled

v1.4 2014-02-27

Major release, featuring various new features, bug fixes and compatibility improvements.

  • Specification changes:

    1. Documents without element nodes are now rejected with status_no_document_element error, unless parse_fragment option is used

  • New features:

    1. Added XML fragment parsing (parse_fragment flag)

    2. Added PCDATA whitespace trimming (parse_trim_pcdata flag)

    3. Added long long support for xml_attribute and xml_text (as_llong, as_ullong and set_value/set overloads)

    4. Added hexadecimal integer parsing support for as_int/as_uint/as_llong/as_ullong

    5. Added xml_node::append_buffer to improve performance of assembling documents from fragments

    6. xml_named_node_iterator is now bidirectional

    7. Reduced XPath stack consumption during compilation and evaluation (useful for embedded systems)

  • Compatibility improvements:

    1. Improved support for platforms without wchar_t support

    2. Fixed several false positives in clang static analysis

    3. Fixed several compilation warnings for various GCC versions

  • Bug fixes:

    1. Fixed undefined pointer arithmetic in XPath implementation

    2. Fixed non-seekable iostream support for certain stream types, i.e. Boost file_source with pipe input

    3. Fixed xpath_query::return_type for some expressions

    4. Fixed dllexport issues with xml_named_node_iterator

    5. Fixed find_child_by_attribute assertion for attributes with null name/value

v1.2 2012-05-01

Major release, featuring header-only mode, various interface enhancements (i.e. PCDATA manipulation and C++11 iteration), many other features and compatibility improvements.

  • New features:

    1. Added xml_text helper class for working with PCDATA/CDATA contents of an element node

    2. Added optional header-only mode (controlled by PUGIXML_HEADER_ONLY define)

    3. Added xml_node::children() and xml_node::attributes() for C++11 ranged for loop or BOOST_FOREACH

    4. Added support for Latin-1 (ISO-8859-1) encoding conversion during loading and saving

    5. Added custom default values for xml_attribute::as_* (they are returned if the attribute does not exist)

    6. Added parse_ws_pcdata_single flag for preserving whitespace-only PCDATA in case it’s the only child

    7. Added format_save_file_text for xml_document::save_file to open files as text instead of binary (changes newlines on Windows)

    8. Added format_no_escapes flag to disable special symbol escaping (complements ~parse_escapes)

    9. Added support for loading document from streams that do not support seeking

    10. Added PUGIXML_MEMORY_* constants for tweaking allocation behavior (useful for embedded systems)

    11. Added PUGIXML_VERSION preprocessor define

  • Compatibility improvements:

    1. Parser does not require setjmp support (improves compatibility with some embedded platforms, enables /clr:pure compilation)

    2. STL forward declarations are no longer used (fixes SunCC/RWSTL compilation, fixes clang compilation in C++11 mode)

    3. Fixed AirPlay SDK, Android, Windows Mobile (WinCE) and C++/CLI compilation

    4. Fixed several compilation warnings for various GCC versions, Intel C++ compiler and Clang

  • Bug fixes:

    1. Fixed unsafe bool conversion to avoid problems on C++/CLI

    2. Iterator dereference operator is const now (fixes Boost filter_iterator support)

    3. xml_document::save_file now checks for file I/O errors during saving

v1.0 2010-11-01

Major release, featuring many XPath enhancements, wide character filename support, miscellaneous performance improvements, bug fixes and more.

  • XPath:

    1. XPath implementation is moved to pugixml.cpp (which is the only source file now); use PUGIXML_NO_XPATH if you want to disable XPath to reduce code size

    2. XPath is now supported without exceptions (PUGIXML_NO_EXCEPTIONS); the error handling mechanism depends on the presence of exception support

    3. XPath is now supported without STL (PUGIXML_NO_STL)

    4. Introduced variable support

    5. Introduced new xpath_query::evaluate_string, which works without STL

    6. Introduced new xpath_node_set constructor (from an iterator range)

    7. Evaluation function now accept attribute context nodes

    8. All internal allocations use custom allocation functions

    9. Improved error reporting; now a last parsed offset is returned together with the parsing error

  • Bug fixes:

    1. Fixed memory leak for loading from streams with stream exceptions turned on

    2. Fixed custom deallocation function calling with null pointer in one case

    3. Fixed missing attributes for iterator category functions; all functions/classes can now be DLL-exported

    4. Worked around Digital Mars compiler bug, which lead to minor read overfetches in several functions

    5. load_file now works with 2+ Gb files in MSVC/MinGW

    6. XPath: fixed memory leaks for incorrect queries

    7. XPath: fixed xpath_node() attribute constructor with empty attribute argument

    8. XPath: fixed lang() function for non-ASCII arguments

  • Specification changes:

    1. CDATA nodes containing ]]> are printed as several nodes; while this changes the internal structure, this is the only way to escape CDATA contents

    2. Memory allocation errors during parsing now preserve last parsed offset (to give an idea about parsing progress)

    3. If an element node has the only child, and it is of CDATA type, then the extra indentation is omitted (previously this behavior only held for PCDATA children)

  • Additional functionality:

    1. Added xml_parse_result default constructor

    2. Added xml_document::load_file and xml_document::save_file with wide character paths

    3. Added as_utf8 and as_wide overloads for std::wstring/std::string arguments

    4. Added DOCTYPE node type (node_doctype) and a special parse flag, parse_doctype, to add such nodes to the document during parsing

    5. Added parse_full parse flag mask, which extends parse_default with all node type parsing flags except parse_ws_pcdata

    6. Added xml_node::hash_value() and xml_attribute::hash_value() functions for use in hash-based containers

    7. Added internal_object() and additional constructor for both xml_node and xml_attribute for easier marshalling (useful for language bindings)

    8. Added xml_document::document_element() function

    9. Added xml_node::prepend_attribute, xml_node::prepend_child and xml_node::prepend_copy functions

    10. Added xml_node::append_child, xml_node::prepend_child, xml_node::insert_child_before and xml_node::insert_child_after overloads for element nodes (with name instead of type)

    11. Added xml_document::reset() function

  • Performance improvements:

    1. xml_node::root() and xml_node::offset_debug() are now O(1) instead of O(logN)

    2. Minor parsing optimizations

    3. Minor memory optimization for strings in DOM tree (set_name/set_value)

    4. Memory optimization for string memory reclaiming in DOM tree (set_name/set_value now reallocate the buffer if memory waste is too big)

    5. XPath: optimized document order sorting

    6. XPath: optimized child/attribute axis step

    7. XPath: optimized number-to-string conversions in MSVC

    8. XPath: optimized concat for many arguments

    9. XPath: optimized evaluation allocation mechanism: constant and document strings are not heap-allocated

    10. XPath: optimized evaluation allocation mechanism: all temporaries' allocations use fast stack-like allocator

  • Compatibility:

    1. Removed wildcard functions (xml_node::child_w, xml_node::attribute_w, etc.)

    2. Removed xml_node::all_elements_by_name

    3. Removed xpath_type_t enumeration; use xpath_value_type instead

    4. Removed format_write_bom_utf8 enumeration; use format_write_bom instead

    5. Removed xml_document::precompute_document_order, xml_attribute::document_order and xml_node::document_order functions; document order sort optimization is now automatic

    6. Removed xml_document::parse functions and transfer_ownership struct; use xml_document::load_buffer_inplace and xml_document::load_buffer_inplace_own instead

    7. Removed as_utf16 function; use as_wide instead

v0.9 2010-07-01

Major release, featuring extended and improved Unicode support, miscellaneous performance improvements, bug fixes and more.

  • Major Unicode improvements:

    1. Introduced encoding support (automatic/manual encoding detection on load, manual encoding selection on save, conversion from/to UTF8, UTF16 LE/BE, UTF32 LE/BE)

    2. Introduced wchar_t mode (you can set PUGIXML_WCHAR_MODE define to switch pugixml internal encoding from UTF8 to wchar_t; all functions are switched to their Unicode variants)

    3. Load/save functions now support wide streams

  • Bug fixes:

    1. Fixed document corruption on failed parsing bug

    2. XPath string/number conversion improvements (increased precision, fixed crash for huge numbers)

    3. Improved DOCTYPE parsing: now parser recognizes all well-formed DOCTYPE declarations

    4. Fixed xml_attribute::as_uint() for large numbers (i.e. 232-1)

    5. Fixed xml_node::first_element_by_path for path components that are prefixes of node names, but are not exactly equal to them.

  • Specification changes:

    1. parse() API changed to load_buffer/load_buffer_inplace/load_buffer_inplace_own; load_buffer APIs do not require zero-terminated strings.

    2. Renamed as_utf16 to as_wide

    3. Changed xml_node::offset_debug return type and xml_parse_result::offset type to ptrdiff_t

    4. Nodes/attributes with empty names are now printed as :anonymous

  • Performance improvements:

    1. Optimized document parsing and saving

    2. Changed internal memory management: internal allocator is used for both metadata and name/value data; allocated pages are deleted if all allocations from them are deleted

    3. Optimized memory consumption: sizeof(xml_node_struct) reduced from 40 bytes to 32 bytes on x86

    4. Optimized debug mode parsing/saving by order of magnitude

  • Miscellaneous:

    1. All STL includes except <exception> in pugixml.hpp are replaced with forward declarations

    2. xml_node::remove_child and xml_node::remove_attribute now return the operation result

  • Compatibility:

    1. parse() and as_utf16 are left for compatibility (these functions are deprecated and will be removed in version 1.0)

    2. Wildcard functions, document_order/precompute_document_order functions, all_elements_by_name function and format_write_bom_utf8 flag are deprecated and will be removed in version 1.0

    3. xpath_type_t enumeration was renamed to xpath_value_type; xpath_type_t is deprecated and will be removed in version 1.0

v0.5 2009-11-08

Major bugfix release. Changes:

  • XPath bugfixes:

    1. Fixed translate(), lang() and concat() functions (infinite loops/crashes)

    2. Fixed compilation of queries with empty literal strings ("")

    3. Fixed axis tests: they never add empty nodes/attributes to the resulting node set now

    4. Fixed string-value evaluation for node-set (the result excluded some text descendants)

    5. Fixed self:: axis (it behaved like ancestor-or-self::)

    6. Fixed following:: and preceding:: axes (they included descendent and ancestor nodes, respectively)

    7. Minor fix for namespace-uri() function (namespace declaration scope includes the parent element of namespace declaration attribute)

    8. Some incorrect queries are no longer parsed now (i.e. foo: *)

    9. Fixed text()/etc. node test parsing bug (i.e. foo[text()] failed to compile)

    10. Fixed root step (/) - it now selects empty node set if query is evaluated on empty node

    11. Fixed string to number conversion ("123 " converted to NaN, "123 .456" converted to 123.456 - now the results are 123 and NaN, respectively)

    12. Node set copying now preserves sorted type; leads to better performance on some queries

  • Miscellaneous bugfixes:

    1. Fixed xml_node::offset_debug for PI nodes

    2. Added empty attribute checks to xml_node::remove_attribute

    3. Fixed node_pi and node_declaration copying

    4. Const-correctness fixes

  • Specification changes:

    1. xpath_node::select_nodes() and related functions now throw exception if expression return type is not node set (instead of assertion)

    2. xml_node::traverse() now sets depth to -1 for both begin() and end() callbacks (was 0 at begin() and -1 at end())

    3. In case of non-raw node printing a newline is output after PCDATA inside nodes if the PCDATA has siblings

    4. UTF8 → wchar_t conversion now considers 5-byte UTF8-like sequences as invalid

  • New features:

    1. Added xpath_node_set::operator[] for index-based iteration

    2. Added xpath_query::return_type()

    3. Added getter accessors for memory-management functions

v0.42 2009-09-17

Maintenance release. Changes:

  • Bug fixes:

    1. Fixed deallocation in case of custom allocation functions or if delete[] / free are incompatible

    2. XPath parser fixed for incorrect queries (i.e. incorrect XPath queries should now always fail to compile)

    3. Const-correctness fixes for find_child_by_attribute

    4. Improved compatibility (miscellaneous warning fixes, fixed <cstring> include dependency for GCC)

    5. Fixed iterator begin/end and print function to work correctly for empty nodes

  • New features:

    1. Added PUGIXML_API/PUGIXML_CLASS/PUGIXML_FUNCTION configuration macros to control class/function attributes

    2. Added xml_attribute::set_value overloads for different types

v0.41 2009-02-08

Maintenance release. Changes:

  • Bug fixes:

    1. Fixed bug with node printing (occasionally some content was not written to output stream)

v0.4 2009-01-18

Changes:

  • Bug fixes:

    1. Documentation fix in samples for parse() with manual lifetime control

    2. Fixed document order sorting in XPath (it caused wrong order of nodes after xpath_node_set::sort and wrong results of some XPath queries)

  • Node printing changes:

    1. Single quotes are no longer escaped when printing nodes

    2. Symbols in second half of ASCII table are no longer escaped when printing nodes; because of this, format_utf8 flag is deleted as it’s no longer needed and format_write_bom is renamed to format_write_bom_utf8.

    3. Reworked node printing - now it works via xml_writer interface; implementations for FILE* and std::ostream are available. As a side-effect, xml_document::save_file now works without STL.

  • New features:

    1. Added unsigned integer support for attributes (xml_attribute::as_uint, xml_attribute::operator=)

    2. Now document declaration (<?xml …​?>) is parsed as node with type node_declaration when parse_declaration flag is specified (access to encoding/version is performed as if they were attributes, i.e. doc.child("xml").attribute("version").as_float()); corresponding flags for node printing were also added

    3. Added support for custom memory management (see set_memory_management_functions for details)

    4. Implemented node/attribute copying (see xml_node::insert_copy_* and xml_node::append_copy for details)

    5. Added find_child_by_attribute and find_child_by_attribute_w to simplify parsing code in some cases (i.e. COLLADA files)

    6. Added file offset information querying for debugging purposes (now you’re able to determine exact location of any xml_node in parsed file, see xml_node::offset_debug for details)

    7. Improved error handling for parsing - now load(), load_file() and parse() return xml_parse_result, which contains error code and last parsed offset; this does not break old interface as xml_parse_result can be implicitly casted to bool.

v0.34 2007-10-31

Maintenance release. Changes:

  • Bug fixes:

    1. Fixed bug with loading from text-mode iostreams

    2. Fixed leak when transfer_ownership is true and parsing is failing

    3. Fixed bug in saving (\r and \n are now escaped in attribute values)

    4. Renamed free() to destroy() - some macro conflicts were reported

  • New features:

    1. Improved compatibility (supported Digital Mars C++, MSVC 6, CodeWarrior 8, PGI C++, Comeau, supported PS3 and XBox360)

    2. PUGIXML_NO_EXCEPTION flag for platforms without exception handling

v0.3 2007-02-21

Refactored, reworked and improved version. Changes:

  • Interface:

    1. Added XPath

    2. Added tree modification functions

    3. Added no STL compilation mode

    4. Added saving document to file

    5. Refactored parsing flags

    6. Removed xml_parser class in favor of xml_document

    7. Added transfer ownership parsing mode

    8. Modified the way xml_tree_walker works

    9. Iterators are now non-constant

  • Implementation:

    1. Support of several compilers and platforms

    2. Refactored and sped up parsing core

    3. Improved standard compliancy

    4. Added XPath implementation

    5. Fixed several bugs

v0.2 2006-11-06

First public release. Changes:

  • Bug fixes:

    1. Fixed child_value() (for empty nodes)

    2. Fixed xml_parser_impl warning at W4

  • New features:

    1. Introduced child_value(name) and child_value_w(name)

    2. parse_eol_pcdata and parse_eol_attribute flags + parse_minimal optimizations

    3. Optimizations of strconv_t

v0.1 2006-07-15

First private release for testing purposes

10. API Reference

This is the reference for all macros, types, enumerations, classes and functions in pugixml. Each symbol is a link that leads to the relevant section of the manual.

10.2. Types

typedef configuration-defined-type char_t;
typedef configuration-defined-type string_t;
typedef configuration-defined-type string_view_t;
typedef void* (*allocation_function)(size_t size);
typedef void (*deallocation_function)(void* ptr);

10.4. Constants

// Formatting options bit flags:
const unsigned int format_attribute_single_quote
const unsigned int format_default
const unsigned int format_indent
const unsigned int format_indent_attributes
const unsigned int format_no_declaration
const unsigned int format_no_empty_element_tags
const unsigned int format_no_escapes
const unsigned int format_raw
const unsigned int format_save_file_text
const unsigned int format_skip_control_chars
const unsigned int format_write_bom

// Parsing options bit flags:
const unsigned int parse_cdata
const unsigned int parse_comments
const unsigned int parse_declaration
const unsigned int parse_default
const unsigned int parse_doctype
const unsigned int parse_eol
const unsigned int parse_escapes
const unsigned int parse_fragment
const unsigned int parse_full
const unsigned int parse_minimal
const unsigned int parse_pi
const unsigned int parse_trim_pcdata
const unsigned int parse_ws_pcdata
const unsigned int parse_ws_pcdata_single
const unsigned int parse_embed_pcdata
const unsigned int parse_merge_pcdata
const unsigned int parse_wconv_attribute
const unsigned int parse_wnorm_attribute

10.5. Classes

class xml_attribute
    xml_attribute();

    bool empty() const;
    operator unspecified_bool_type() const;

    bool operator==(const xml_attribute& r) const;
    bool operator!=(const xml_attribute& r) const;
    bool operator<(const xml_attribute& r) const;
    bool operator>(const xml_attribute& r) const;
    bool operator<=(const xml_attribute& r) const;
    bool operator>=(const xml_attribute& r) const;

    size_t hash_value() const;

    xml_attribute next_attribute() const;
    xml_attribute previous_attribute() const;

    const char_t* name() const;
    const char_t* value() const;

    const char_t* as_string(const char_t* def = "") const;
    int as_int(int def = 0) const;
    unsigned int as_uint(unsigned int def = 0) const;
    double as_double(double def = 0) const;
    float as_float(float def = 0) const;
    bool as_bool(bool def = false) const;
    long long as_llong(long long def = 0) const;
    unsigned long long as_ullong(unsigned long long def = 0) const;

    bool set_name(const char_t* rhs);
    bool set_name(const char_t* rhs, size_t size);
    bool set_name(string_view_t rhs);
    bool set_value(const char_t* rhs);
    bool set_value(const char_t* rhs, size_t size);
    bool set_value(string_view_t rhs);
    bool set_value(int rhs);
    bool set_value(unsigned int rhs);
    bool set_value(long rhs);
    bool set_value(unsigned long rhs);
    bool set_value(double rhs);
    bool set_value(float rhs);
    bool set_value(bool rhs);
    bool set_value(long long rhs);
    bool set_value(unsigned long long rhs);

    xml_attribute& operator=(const char_t* rhs);
    xml_attribute& operator=(string_view_t rhs);
    xml_attribute& operator=(int rhs);
    xml_attribute& operator=(unsigned int rhs);
    xml_attribute& operator=(long rhs);
    xml_attribute& operator=(unsigned long rhs);
    xml_attribute& operator=(double rhs);
    xml_attribute& operator=(float rhs);
    xml_attribute& operator=(bool rhs);
    xml_attribute& operator=(long long rhs);
    xml_attribute& operator=(unsnigned long long rhs);

class xml_node
    xml_node();

    bool empty() const;
    operator unspecified_bool_type() const;

    bool operator==(const xml_node& r) const;
    bool operator!=(const xml_node& r) const;
    bool operator<(const xml_node& r) const;
    bool operator>(const xml_node& r) const;
    bool operator<=(const xml_node& r) const;
    bool operator>=(const xml_node& r) const;

    size_t hash_value() const;

    xml_node_type type() const;

    const char_t* name() const;
    const char_t* value() const;

    xml_node parent() const;
    xml_node first_child() const;
    xml_node last_child() const;
    xml_node next_sibling() const;
    xml_node previous_sibling() const;

    xml_attribute first_attribute() const;
    xml_attribute last_attribute() const;

    implementation-defined-type children() const;
    implementation-defined-type children(const char_t* name) const;
    implementation-defined-type attributes() const;

    xml_node child(const char_t* name) const;
    xml_node child(string_view_t name) const;
    xml_attribute attribute(const char_t* name) const;
    xml_attribute attribute(string_view_t name) const;
    xml_node next_sibling(const char_t* name) const;
    xml_node next_sibling(string_view_t name) const;
    xml_node previous_sibling(const char_t* name) const;
    xml_node previous_sibling(string_view_t name) const;

    xml_attribute attribute(const char_t* name, xml_attribute& hint) const;
    xml_attribute attribute(string_view_t name, xml_attribute& hint) const;

    xml_node find_child_by_attribute(const char_t* name, const char_t* attr_name, const char_t* attr_value) const;
    xml_node find_child_by_attribute(const char_t* attr_name, const char_t* attr_value) const;

    const char_t* child_value() const;
    const char_t* child_value(const char_t* name) const;
    xml_text text() const;

    typedef xml_node_iterator iterator;
    iterator begin() const;
    iterator end() const;

    typedef xml_attribute_iterator attribute_iterator;
    attribute_iterator attributes_begin() const;
    attribute_iterator attributes_end() const;

    bool traverse(xml_tree_walker& walker);

    template <typename Predicate> xml_attribute find_attribute(Predicate pred) const;
    template <typename Predicate> xml_node find_child(Predicate pred) const;
    template <typename Predicate> xml_node find_node(Predicate pred) const;

    string_t path(char_t delimiter = '/') const;
    xml_node xml_node::first_element_by_path(const char_t* path, char_t delimiter = '/') const;
    xml_node root() const;
    ptrdiff_t offset_debug() const;

    bool set_name(const char_t* rhs);
    bool set_name(const char_t* rhs, size_t size);
    bool set_name(string_view_t rhs);
    bool set_value(const char_t* rhs);
    bool set_value(const char_t* rhs, size_t size);
    bool set_value(string_view_t rhs);

    xml_attribute append_attribute(const char_t* name);
    xml_attribute append_attribute(string_view_t name);
    xml_attribute prepend_attribute(const char_t* name);
    xml_attribute prepend_attribute(string_view_t name);
    xml_attribute insert_attribute_after(const char_t* name, const xml_attribute& attr);
    xml_attribute insert_attribute_after(string_view_t name, const xml_attribute& attr);
    xml_attribute insert_attribute_before(const char_t* name, const xml_attribute& attr);
    xml_attribute insert_attribute_before(string_view_t name, const xml_attribute& attr);

    xml_node append_child(xml_node_type type = node_element);
    xml_node prepend_child(xml_node_type type = node_element);
    xml_node insert_child_after(xml_node_type type, const xml_node& node);
    xml_node insert_child_before(xml_node_type type, const xml_node& node);

    xml_node append_child(const char_t* name);
    xml_node append_child(string_view_t name);
    xml_node prepend_child(const char_t* name);
    xml_node prepend_child(string_view_t name);
    xml_node insert_child_after(const char_t* name, const xml_node& node);
    xml_node insert_child_after(string_view_t name, const xml_node& node);
    xml_node insert_child_before(const char_t* name, const xml_node& node);
    xml_node insert_child_before(string_view_t name, const xml_node& node);

    xml_attribute append_copy(const xml_attribute& proto);
    xml_attribute prepend_copy(const xml_attribute& proto);
    xml_attribute insert_copy_after(const xml_attribute& proto, const xml_attribute& attr);
    xml_attribute insert_copy_before(const xml_attribute& proto, const xml_attribute& attr);

    xml_node append_copy(const xml_node& proto);
    xml_node prepend_copy(const xml_node& proto);
    xml_node insert_copy_after(const xml_node& proto, const xml_node& node);
    xml_node insert_copy_before(const xml_node& proto, const xml_node& node);

    xml_node append_move(const xml_node& moved);
    xml_node prepend_move(const xml_node& moved);
    xml_node insert_move_after(const xml_node& moved, const xml_node& node);
    xml_node insert_move_before(const xml_node& moved, const xml_node& node);

    bool remove_attribute(const xml_attribute& a);
    bool remove_attribute(const char_t* name);
    bool remove_attribute(string_view_t name);
    bool remove_attributes();
    bool remove_child(const xml_node& n);
    bool remove_child(const char_t* name);
    bool remove_child(string_view_t name);
    bool remove_children();

    xml_parse_result append_buffer(const void* contents, size_t size, unsigned int options = parse_default, xml_encoding encoding = encoding_auto);

    void print(xml_writer& writer, const char_t* indent = "\t", unsigned int flags = format_default, xml_encoding encoding = encoding_auto, unsigned int depth = 0) const;
    void print(std::ostream& os, const char_t* indent = "\t", unsigned int flags = format_default, xml_encoding encoding = encoding_auto, unsigned int depth = 0) const;
    void print(std::wostream& os, const char_t* indent = "\t", unsigned int flags = format_default, unsigned int depth = 0) const;

    xpath_node select_node(const char_t* query, xpath_variable_set* variables = 0) const;
    xpath_node select_node(const xpath_query& query) const;
    xpath_node_set select_nodes(const char_t* query, xpath_variable_set* variables = 0) const;
    xpath_node_set select_nodes(const xpath_query& query) const;

class xml_document
    xml_document();
    ~xml_document();

    void reset();
    void reset(const xml_document& proto);

    xml_parse_result load(std::istream& stream, unsigned int options = parse_default, xml_encoding encoding = encoding_auto);
    xml_parse_result load(std::wistream& stream, unsigned int options = parse_default);

    xml_parse_result load_string(const char_t* contents, unsigned int options = parse_default);

    xml_parse_result load_file(const char* path, unsigned int options = parse_default, xml_encoding encoding = encoding_auto);
    xml_parse_result load_file(const wchar_t* path, unsigned int options = parse_default, xml_encoding encoding = encoding_auto);

    xml_parse_result load_buffer(const void* contents, size_t size, unsigned int options = parse_default, xml_encoding encoding = encoding_auto);
    xml_parse_result load_buffer_inplace(void* contents, size_t size, unsigned int options = parse_default, xml_encoding encoding = encoding_auto);
    xml_parse_result load_buffer_inplace_own(void* contents, size_t size, unsigned int options = parse_default, xml_encoding encoding = encoding_auto);

    bool save_file(const char* path, const char_t* indent = "\t", unsigned int flags = format_default, xml_encoding encoding = encoding_auto) const;
    bool save_file(const wchar_t* path, const char_t* indent = "\t", unsigned int flags = format_default, xml_encoding encoding = encoding_auto) const;

    void save(std::ostream& stream, const char_t* indent = "\t", unsigned int flags = format_default, xml_encoding encoding = encoding_auto) const;
    void save(std::wostream& stream, const char_t* indent = "\t", unsigned int flags = format_default) const;

    void save(xml_writer& writer, const char_t* indent = "\t", unsigned int flags = format_default, xml_encoding encoding = encoding_auto) const;

    xml_node document_element() const;

struct xml_parse_result
    xml_parse_status status;
    ptrdiff_t offset;
    xml_encoding encoding;

    operator bool() const;
    const char* description() const;

class xml_node_iterator
class xml_attribute_iterator

class xml_tree_walker
    virtual bool begin(xml_node& node);
    virtual bool for_each(xml_node& node) = 0;
    virtual bool end(xml_node& node);

    int depth() const;

class xml_text
    bool empty() const;
    operator xml_text::unspecified_bool_type() const;

    const char_t* xml_text::get() const;

    const char_t* as_string(const char_t* def = "") const;
    int as_int(int def = 0) const;
    unsigned int as_uint(unsigned int def = 0) const;
    double as_double(double def = 0) const;
    float as_float(float def = 0) const;
    bool as_bool(bool def = false) const;
    long long as_llong(long long def = 0) const;
    unsigned long long as_ullong(unsigned long long def = 0) const;

    bool set(const char_t* rhs);
    bool set(const char_t* rhs, size_t size);
    bool set(string_view_t rhs);

    bool set(int rhs);
    bool set(unsigned int rhs);
    bool set(long rhs);
    bool set(unsigned long rhs);
    bool set(double rhs);
    bool set(float rhs);
    bool set(bool rhs);
    bool set(long long rhs);
    bool set(unsigned long long rhs);

    xml_text& operator=(const char_t* rhs);
    xml_text& operator=(string_view_t rhs);
    xml_text& operator=(int rhs);
    xml_text& operator=(unsigned int rhs);
    xml_text& operator=(long rhs);
    xml_text& operator=(unsigned long rhs);
    xml_text& operator=(double rhs);
    xml_text& operator=(float rhs);
    xml_text& operator=(bool rhs);
    xml_text& operator=(long long rhs);
    xml_text& operator=(unsigned long long rhs);

    xml_node data() const;

class xml_writer
    virtual void write(const void* data, size_t size) = 0;

class xml_writer_file: public xml_writer
    xml_writer_file(void* file);

class xml_writer_stream: public xml_writer
    xml_writer_stream(std::ostream& stream);
    xml_writer_stream(std::wostream& stream);

struct xpath_parse_result
    const char* error;
    ptrdiff_t offset;

    operator bool() const;
    const char* description() const;

class xpath_query
    explicit xpath_query(const char_t* query, xpath_variable_set* variables = 0);

    bool evaluate_boolean(const xpath_node& n) const;
    double evaluate_number(const xpath_node& n) const;
    string_t evaluate_string(const xpath_node& n) const;
    size_t evaluate_string(char_t* buffer, size_t capacity, const xpath_node& n) const;
    xpath_node_set evaluate_node_set(const xpath_node& n) const;
    xpath_node evaluate_node(const xpath_node& n) const;

    xpath_value_type return_type() const;

    const xpath_parse_result& result() const;
    operator unspecified_bool_type() const;

class xpath_exception: public std::exception
    virtual const char* what() const noexcept;

    const xpath_parse_result& result() const;

class xpath_node
    xpath_node();
    xpath_node(const xml_node& node);
    xpath_node(const xml_attribute& attribute, const xml_node& parent);

    xml_node node() const;
    xml_attribute attribute() const;
    xml_node parent() const;

    operator unspecified_bool_type() const;
    bool operator==(const xpath_node& n) const;
    bool operator!=(const xpath_node& n) const;

class xpath_node_set
    xpath_node_set();
    xpath_node_set(const_iterator begin, const_iterator end, type_t type = type_unsorted);

    typedef const xpath_node* const_iterator;
    const_iterator begin() const;
    const_iterator end() const;

    const xpath_node& operator[](size_t index) const;
    size_t size() const;
    bool empty() const;

    xpath_node first() const;

    enum type_t {type_unsorted, type_sorted, type_sorted_reverse};
    type_t type() const;
    void sort(bool reverse = false);

class xpath_variable
    const char_t* name() const;
    xpath_value_type type() const;

    bool get_boolean() const;
    double get_number() const;
    const char_t* get_string() const;
    const xpath_node_set& get_node_set() const;

    bool set(bool value);
    bool set(double value);
    bool set(const char_t* value);
    bool set(const xpath_node_set& value);

class xpath_variable_set
    xpath_variable* add(const char_t* name, xpath_value_type type);

    bool set(const char_t* name, bool value);
    bool set(const char_t* name, double value);
    bool set(const char_t* name, const char_t* value);
    bool set(const char_t* name, const xpath_node_set& value);

    xpath_variable* get(const char_t* name);
    const xpath_variable* get(const char_t* name) const;

10.6. Functions

std::string as_utf8(const wchar_t* str);
std::string as_utf8(const std::wstring& str);
std::wstring as_wide(const char* str);
std::wstring as_wide(const std::string& str);
void set_memory_management_functions(allocation_function allocate, deallocation_function deallocate);
allocation_function get_memory_allocation_function();
deallocation_function get_memory_deallocation_function();

1. All trademarks used are properties of their respective owners.
================================================ FILE: external/pugixml/docs/quickstart.html ================================================ pugixml 1.14 quick start guide

Introduction

pugixml is a light-weight C++ XML processing library. It consists of a DOM-like interface with rich traversal/modification capabilities, an extremely fast XML parser which constructs the DOM tree from an XML file/buffer, and an XPath 1.0 implementation for complex data-driven tree queries. Full Unicode support is also available, with two Unicode interface variants and conversions between different Unicode encodings (which happen automatically during parsing/saving). The library is extremely portable and easy to integrate and use. pugixml is developed and maintained since 2006 and has many users. All code is distributed under the MIT license, making it completely free to use in both open-source and proprietary applications.

pugixml enables very fast, convenient and memory-efficient XML document processing. However, since pugixml has a DOM parser, it can’t process XML documents that do not fit in memory; also the parser is a non-validating one, so if you need DTD/Schema validation, the library is not for you.

This is the quick start guide for pugixml, which purpose is to enable you to start using the library quickly. Many important library features are either not described at all or only mentioned briefly; for more complete information you should read the complete manual.

Note
No documentation is perfect; neither is this one. If you find errors or omissions, please don’t hesitate to submit an issue or open a pull request with a fix.

Installation

You can download the latest source distribution as an archive:

pugixml-1.14.zip (Windows line endings) / pugixml-1.14.tar.gz (Unix line endings)

The distribution contains library source, documentation (the guide you’re reading now and the manual) and some code examples. After downloading the distribution, install pugixml by extracting all files from the compressed archive.

The complete pugixml source consists of three files - one source file, pugixml.cpp, and two header files, pugixml.hpp and pugiconfig.hpp. pugixml.hpp is the primary header which you need to include in order to use pugixml classes/functions. The rest of this guide assumes that pugixml.hpp is either in the current directory or in one of include directories of your projects, so that #include "pugixml.hpp" can find the header; however you can also use relative path (i.e. #include "../libs/pugixml/src/pugixml.hpp") or include directory-relative path (i.e. #include <xml/thirdparty/pugixml/src/pugixml.hpp>).

The easiest way to build pugixml is to compile the source file, pugixml.cpp, along with the existing library/executable. This process depends on the method of building your application; for example, if you’re using Microsoft Visual Studio [1], Apple Xcode, Code::Blocks or any other IDE, just add pugixml.cpp to one of your projects. There are other building methods available, including building pugixml as a standalone static/shared library; read the manual for further information.

Document object model

pugixml stores XML data in DOM-like way: the entire XML document (both document structure and element data) is stored in memory as a tree. The tree can be loaded from character stream (file, string, C++ I/O stream), then traversed via special API or XPath expressions. The whole tree is mutable: both node structure and node/attribute data can be changed at any time. Finally, the result of document transformations can be saved to a character stream (file, C++ I/O stream or custom transport).

The root of the tree is the document itself, which corresponds to C++ type xml_document. Document has one or more child nodes, which correspond to C++ type xml_node. Nodes have different types; depending on a type, a node can have a collection of child nodes, a collection of attributes, which correspond to C++ type xml_attribute, and some additional data (i.e. name).

The most common node types are:

  • Document node (node_document) - this is the root of the tree, which consists of several child nodes. This node corresponds to xml_document class; note that xml_document is a sub-class of xml_node, so the entire node interface is also available.

  • Element/tag node (node_element) - this is the most common type of node, which represents XML elements. Element nodes have a name, a collection of attributes and a collection of child nodes (both of which may be empty). The attribute is a simple name/value pair.

  • Plain character data nodes (node_pcdata) represent plain text in XML. PCDATA nodes have a value, but do not have name or children/attributes. Note that plain character data is not a part of the element node but instead has its own node; for example, an element node can have several child PCDATA nodes.

Despite the fact that there are several node types, there are only three C++ types representing the tree (xml_document, xml_node, xml_attribute); some operations on xml_node are only valid for certain node types. They are described below.

Note
All pugixml classes and functions are located in pugi namespace; you have to either use explicit name qualification (i.e. pugi::xml_node), or to gain access to relevant symbols via using directive (i.e. using pugi::xml_node; or using namespace pugi;).

xml_document is the owner of the entire document structure; destroying the document destroys the whole tree. The interface of xml_document consists of loading functions, saving functions and the entire interface of xml_node, which allows for document inspection and/or modification. Note that while xml_document is a sub-class of xml_node, xml_node is not a polymorphic type; the inheritance is present only to simplify usage.

xml_node is the handle to document node; it can point to any node in the document, including document itself. There is a common interface for nodes of all types. Note that xml_node is only a handle to the actual node, not the node itself - you can have several xml_node handles pointing to the same underlying object. Destroying xml_node handle does not destroy the node and does not remove it from the tree.

There is a special value of xml_node type, known as null node or empty node. It does not correspond to any node in any document, and thus resembles null pointer. However, all operations are defined on empty nodes; generally the operations don’t do anything and return empty nodes/attributes or empty strings as their result. This is useful for chaining calls; i.e. you can get the grandparent of a node like so: node.parent().parent(); if a node is a null node or it does not have a parent, the first parent() call returns null node; the second parent() call then also returns null node, so you don’t have to check for errors twice. You can test if a handle is null via implicit boolean cast: if (node) { …​ } or if (!node) { …​ }.

xml_attribute is the handle to an XML attribute; it has the same semantics as xml_node, i.e. there can be several xml_attribute handles pointing to the same underlying object and there is a special null attribute value, which propagates to function results.

There are two choices of interface and internal representation when configuring pugixml: you can either choose the UTF-8 (also called char) interface or UTF-16/32 (also called wchar_t) one. The choice is controlled via PUGIXML_WCHAR_MODE define; you can set it via pugiconfig.hpp or via preprocessor options. All tree functions that work with strings work with either C-style null terminated strings or STL strings of the selected character type. Read the manual for additional information on Unicode interface.

Loading document

pugixml provides several functions for loading XML data from various places - files, C++ iostreams, memory buffers. All functions use an extremely fast non-validating parser. This parser is not fully W3C conformant - it can load any valid XML document, but does not perform some well-formedness checks. While considerable effort is made to reject invalid XML documents, some validation is not performed because of performance reasons. XML data is always converted to internal character format before parsing. pugixml supports all popular Unicode encodings (UTF-8, UTF-16 (big and little endian), UTF-32 (big and little endian); UCS-2 is naturally supported since it’s a strict subset of UTF-16) and handles all encoding conversions automatically.

The most common source of XML data is files; pugixml provides a separate function for loading XML document from file. This function accepts file path as its first argument, and also two optional arguments, which specify parsing options and input data encoding, which are described in the manual.

This is an example of loading XML document from file (samples/load_file.cpp):

pugi::xml_document doc;

pugi::xml_parse_result result = doc.load_file("tree.xml");

std::cout << "Load result: " << result.description() << ", mesh name: " << doc.child("mesh").attribute("name").value() << std::endl;

load_file, as well as other loading functions, destroys the existing document tree and then tries to load the new tree from the specified file. The result of the operation is returned in an xml_parse_result object; this object contains the operation status, and the related information (i.e. last successfully parsed position in the input file, if parsing fails).

Parsing result object can be implicitly converted to bool; if you do not want to handle parsing errors thoroughly, you can just check the return value of load functions as if it was a bool: if (doc.load_file("file.xml")) { …​ } else { …​ }. Otherwise you can use the status member to get parsing status, or the description() member function to get the status in a string form.

This is an example of handling loading errors (samples/load_error_handling.cpp):

pugi::xml_document doc;
pugi::xml_parse_result result = doc.load_string(source);

if (result)
{
    std::cout << "XML [" << source << "] parsed without errors, attr value: [" << doc.child("node").attribute("attr").value() << "]\n\n";
}
else
{
    std::cout << "XML [" << source << "] parsed with errors, attr value: [" << doc.child("node").attribute("attr").value() << "]\n";
    std::cout << "Error description: " << result.description() << "\n";
    std::cout << "Error offset: " << result.offset << " (error at [..." << (source + result.offset) << "]\n\n";
}

Sometimes XML data should be loaded from some other source than file, i.e. HTTP URL; also you may want to load XML data from file using non-standard functions, i.e. to use your virtual file system facilities or to load XML from gzip-compressed files. These scenarios either require loading document from memory, in which case you should prepare a contiguous memory block with all XML data and to pass it to one of buffer loading functions, or loading document from C++ IOstream, in which case you should provide an object which implements std::istream or std::wistream interface.

There are different functions for loading document from memory; they treat the passed buffer as either an immutable one (load_buffer), a mutable buffer which is owned by the caller (load_buffer_inplace), or a mutable buffer which ownership belongs to pugixml (load_buffer_inplace_own). There is also a simple helper function, xml_document::load, for cases when you want to load the XML document from null-terminated character string.

This is an example of loading XML document from memory using one of these functions (samples/load_memory.cpp); read the sample code for more examples:

const char source[] = "<mesh name='sphere'><bounds>0 0 1 1</bounds></mesh>";
size_t size = sizeof(source);
// You can use load_buffer_inplace to load document from mutable memory block; the block's lifetime must exceed that of document
char* buffer = new char[size];
memcpy(buffer, source, size);

// The block can be allocated by any method; the block is modified during parsing
pugi::xml_parse_result result = doc.load_buffer_inplace(buffer, size);

// You have to destroy the block yourself after the document is no longer used
delete[] buffer;

This is a simple example of loading XML document from file using streams (samples/load_stream.cpp); read the sample code for more complex examples involving wide streams and locales:

std::ifstream stream("weekly-utf-8.xml");
pugi::xml_parse_result result = doc.load(stream);

Accessing document data

pugixml features an extensive interface for getting various types of data from the document and for traversing the document. You can use various accessors to get node/attribute data, you can traverse the child node/attribute lists via accessors or iterators, you can do depth-first traversals with xml_tree_walker objects, and you can use XPath for complex data-driven queries.

You can get node or attribute name via name() accessor, and value via value() accessor. Note that both functions never return null pointers - they either return a string with the relevant content, or an empty string if name/value is absent or if the handle is null. Also there are two notable things for reading values:

  • It is common to store data as text contents of some node - i.e. <node><description>This is a node</description></node>. In this case, <description> node does not have a value, but instead has a child of type node_pcdata with value "This is a node". pugixml provides child_value() and text() helper functions to parse such data.

  • In many cases attribute values have types that are not strings - i.e. an attribute may always contain values that should be treated as integers, despite the fact that they are represented as strings in XML. pugixml provides several accessors that convert attribute value to some other type.

This is an example of using these functions (samples/traverse_base.cpp):

for (pugi::xml_node tool = tools.child("Tool"); tool; tool = tool.next_sibling("Tool"))
{
    std::cout << "Tool " << tool.attribute("Filename").value();
    std::cout << ": AllowRemote " << tool.attribute("AllowRemote").as_bool();
    std::cout << ", Timeout " << tool.attribute("Timeout").as_int();
    std::cout << ", Description '" << tool.child_value("Description") << "'\n";
}

Since a lot of document traversal consists of finding the node/attribute with the correct name, there are special functions for that purpose. For example, child("Tool") returns the first node which has the name "Tool", or null handle if there is no such node. This is an example of using such functions (samples/traverse_base.cpp):

std::cout << "Tool for *.dae generation: " << tools.find_child_by_attribute("Tool", "OutputFileMasks", "*.dae").attribute("Filename").value() << "\n";

for (pugi::xml_node tool = tools.child("Tool"); tool; tool = tool.next_sibling("Tool"))
{
    std::cout << "Tool " << tool.attribute("Filename").value() << "\n";
}

Child node lists and attribute lists are simply double-linked lists; while you can use previous_sibling/next_sibling and other such functions for iteration, pugixml additionally provides node and attribute iterators, so that you can treat nodes as containers of other nodes or attributes. All iterators are bidirectional and support all usual iterator operations. The iterators are invalidated if the node/attribute objects they’re pointing to are removed from the tree; adding nodes/attributes does not invalidate any iterators.

Here is an example of using iterators for document traversal (samples/traverse_iter.cpp):

for (pugi::xml_node_iterator it = tools.begin(); it != tools.end(); ++it)
{
    std::cout << "Tool:";

    for (pugi::xml_attribute_iterator ait = it->attributes_begin(); ait != it->attributes_end(); ++ait)
    {
        std::cout << " " << ait->name() << "=" << ait->value();
    }

    std::cout << std::endl;
}

If your C++ compiler supports range-based for-loop (this is a C++11 feature, at the time of writing it’s supported by Microsoft Visual Studio 11 Beta, GCC 4.6 and Clang 3.0), you can use it to enumerate nodes/attributes. Additional helpers are provided to support this; note that they are also compatible with Boost Foreach, and possibly other pre-C++11 foreach facilities.

Here is an example of using C++11 range-based for loop for document traversal (samples/traverse_rangefor.cpp):

for (pugi::xml_node tool: tools.children("Tool"))
{
    std::cout << "Tool:";

    for (pugi::xml_attribute attr: tool.attributes())
    {
        std::cout << " " << attr.name() << "=" << attr.value();
    }

    for (pugi::xml_node child: tool.children())
    {
        std::cout << ", child " << child.name();
    }

    std::cout << std::endl;
}

The methods described above allow traversal of immediate children of some node; if you want to do a deep tree traversal, you’ll have to do it via a recursive function or some equivalent method. However, pugixml provides a helper for depth-first traversal of a subtree. In order to use it, you have to implement xml_tree_walker interface and to call traverse function.

This is an example of traversing tree hierarchy with xml_tree_walker (samples/traverse_walker.cpp):

struct simple_walker: pugi::xml_tree_walker
{
    virtual bool for_each(pugi::xml_node& node)
    {
        for (int i = 0; i < depth(); ++i) std::cout << "  "; // indentation

        std::cout << node_types[node.type()] << ": name='" << node.name() << "', value='" << node.value() << "'\n";

        return true; // continue traversal
    }
};
simple_walker walker;
doc.traverse(walker);

Finally, for complex queries often a higher-level DSL is needed. pugixml provides an implementation of XPath 1.0 language for such queries. The complete description of XPath usage can be found in the manual, but here are some examples:

pugi::xpath_node_set tools = doc.select_nodes("/Profile/Tools/Tool[@AllowRemote='true' and @DeriveCaptionFrom='lastparam']");

std::cout << "Tools:\n";

for (pugi::xpath_node_set::const_iterator it = tools.begin(); it != tools.end(); ++it)
{
    pugi::xpath_node node = *it;
    std::cout << node.node().attribute("Filename").value() << "\n";
}

pugi::xpath_node build_tool = doc.select_node("//Tool[contains(Description, 'build system')]");

if (build_tool)
    std::cout << "Build tool: " << build_tool.node().attribute("Filename").value() << "\n";
Caution
XPath functions throw xpath_exception objects on error; the sample above does not catch these exceptions.

Modifying document data

The document in pugixml is fully mutable: you can completely change the document structure and modify the data of nodes/attributes. All functions take care of memory management and structural integrity themselves, so they always result in structurally valid tree - however, it is possible to create an invalid XML tree (for example, by adding two attributes with the same name or by setting attribute/node name to empty/invalid string). Tree modification is optimized for performance and for memory consumption, so if you have enough memory you can create documents from scratch with pugixml and later save them to file/stream instead of relying on error-prone manual text writing and without too much overhead.

All member functions that change node/attribute data or structure are non-constant and thus can not be called on constant handles. However, you can easily convert constant handle to non-constant one by simple assignment: void foo(const pugi::xml_node& n) { pugi::xml_node nc = n; }, so const-correctness here mainly provides additional documentation.

As discussed before, nodes can have name and value, both of which are strings. Depending on node type, name or value may be absent. You can use set_name and set_value member functions to set them. Similar functions are available for attributes; however, the set_value function is overloaded for some other types except strings, like floating-point numbers. Also, attribute value can be set using an assignment operator. This is an example of setting node/attribute name and value (samples/modify_base.cpp):

pugi::xml_node node = doc.child("node");

// change node name
std::cout << node.set_name("notnode");
std::cout << ", new node name: " << node.name() << std::endl;

// change comment text
std::cout << doc.last_child().set_value("useless comment");
std::cout << ", new comment text: " << doc.last_child().value() << std::endl;

// we can't change value of the element or name of the comment
std::cout << node.set_value("1") << ", " << doc.last_child().set_name("2") << std::endl;
pugi::xml_attribute attr = node.attribute("id");

// change attribute name/value
std::cout << attr.set_name("key") << ", " << attr.set_value("345");
std::cout << ", new attribute: " << attr.name() << "=" << attr.value() << std::endl;

// we can use numbers or booleans
attr.set_value(1.234);
std::cout << "new attribute value: " << attr.value() << std::endl;

// we can also use assignment operators for more concise code
attr = true;
std::cout << "final attribute value: " << attr.value() << std::endl;

Nodes and attributes do not exist without a document tree, so you can’t create them without adding them to some document. A node or attribute can be created at the end of node/attribute list or before/after some other node. All insertion functions return the handle to newly created object on success, and null handle on failure. Even if the operation fails (for example, if you’re trying to add a child node to PCDATA node), the document remains in consistent state, but the requested node/attribute is not added.

Caution
attribute() and child() functions do not add attributes or nodes to the tree, so code like node.attribute("id") = 123; will not do anything if node does not have an attribute with name "id". Make sure you’re operating with existing attributes/nodes by adding them if necessary.

This is an example of adding new attributes/nodes to the document (samples/modify_add.cpp):

// add node with some name
pugi::xml_node node = doc.append_child("node");

// add description node with text child
pugi::xml_node descr = node.append_child("description");
descr.append_child(pugi::node_pcdata).set_value("Simple node");

// add param node before the description
pugi::xml_node param = node.insert_child_before("param", descr);

// add attributes to param node
param.append_attribute("name") = "version";
param.append_attribute("value") = 1.1;
param.insert_attribute_after("type", param.attribute("name")) = "float";

If you do not want your document to contain some node or attribute, you can remove it with remove_attribute and remove_child functions. Removing the attribute or node invalidates all handles to the same underlying object, and also invalidates all iterators pointing to the same object. Removing node also invalidates all past-the-end iterators to its attribute or child node list. Be careful to ensure that all such handles and iterators either do not exist or are not used after the attribute/node is removed.

This is an example of removing attributes/nodes from the document (samples/modify_remove.cpp):

// remove description node with the whole subtree
pugi::xml_node node = doc.child("node");
node.remove_child("description");

// remove id attribute
pugi::xml_node param = node.child("param");
param.remove_attribute("value");

// we can also remove nodes/attributes by handles
pugi::xml_attribute id = param.attribute("name");
param.remove_attribute(id);

Saving document

Often after creating a new document or loading the existing one and processing it, it is necessary to save the result back to file. Also it is occasionally useful to output the whole document or a subtree to some stream; use cases include debug printing, serialization via network or other text-oriented medium, etc. pugixml provides several functions to output any subtree of the document to a file, stream or another generic transport interface; these functions allow to customize the output format, and also perform necessary encoding conversions.

Before writing to the destination the node/attribute data is properly formatted according to the node type; all special XML symbols, such as < and &, are properly escaped. In order to guard against forgotten node/attribute names, empty node/attribute names are printed as ":anonymous". For well-formed output, make sure all node and attribute names are set to meaningful values.

If you want to save the whole document to a file, you can use the save_file function, which returns true on success. This is a simple example of saving XML document to file (samples/save_file.cpp):

// save document to file
std::cout << "Saving result: " << doc.save_file("save_file_output.xml") << std::endl;

To enhance interoperability pugixml provides functions for saving document to any object which implements C++ std::ostream interface. This allows you to save documents to any standard C++ stream (i.e. file stream) or any third-party compliant implementation (i.e. Boost Iostreams). Most notably, this allows for easy debug output, since you can use std::cout stream as saving target. There are two functions, one works with narrow character streams, another handles wide character ones.

This is a simple example of saving XML document to standard output (samples/save_stream.cpp):

// save document to standard output
std::cout << "Document:\n";
doc.save(std::cout);

All of the above saving functions are implemented in terms of writer interface. This is a simple interface with a single function, which is called several times during output process with chunks of document data as input. In order to output the document via some custom transport, for example sockets, you should create an object which implements xml_writer_file interface and pass it to xml_document::save function.

This is a simple example of custom writer for saving document data to STL string (samples/save_custom_writer.cpp); read the sample code for more complex examples:

struct xml_string_writer: pugi::xml_writer
{
    std::string result;

    virtual void write(const void* data, size_t size)
    {
        result.append(static_cast<const char*>(data), size);
    }
};

While the previously described functions save the whole document to the destination, it is easy to save a single subtree. Instead of calling xml_document::save, just call xml_node::print function on the target node. You can save node contents to C++ IOstream object or custom writer in this way. Saving a subtree slightly differs from saving the whole document; read the manual for more information.

Feedback

If you believe you’ve found a bug in pugixml, please file an issue via issue submission form. Be sure to include the relevant information so that the bug can be reproduced: the version of pugixml, compiler version and target architecture, the code that uses pugixml and exhibits the bug, etc. Feature requests and contributions can be filed as issues, too.

If filing an issue is not possible due to privacy or other concerns, you can contact pugixml author by e-mail directly: arseny.kapoulkine@gmail.com.

License

The pugixml library is distributed under the MIT license:

Copyright (c) 2006-2025 Arseny Kapoulkine

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

This means that you can freely use pugixml in your applications, both open-source and proprietary. If you use pugixml in a product, it is sufficient to add an acknowledgment like this to the product distribution:

This software is based on pugixml library (https://pugixml.org).
pugixml is Copyright (C) 2006-2025 Arseny Kapoulkine.

1. All trademarks used are properties of their respective owners.
================================================ FILE: external/pugixml/docs/samples/character.xml ================================================ ================================================ FILE: external/pugixml/docs/samples/custom_memory_management.cpp ================================================ #include "pugixml.hpp" #include // tag::decl[] void* custom_allocate(size_t size) { return new (std::nothrow) char[size]; } void custom_deallocate(void* ptr) { delete[] static_cast(ptr); } // end::decl[] int main() { // tag::call[] pugi::set_memory_management_functions(custom_allocate, custom_deallocate); // end::call[] pugi::xml_document doc; doc.load_string(""); } // vim:et ================================================ FILE: external/pugixml/docs/samples/include.cpp ================================================ #include "pugixml.hpp" #include #include // tag::code[] bool load_preprocess(pugi::xml_document& doc, const char* path); bool preprocess(pugi::xml_node node) { for (pugi::xml_node child = node.first_child(); child; ) { if (child.type() == pugi::node_pi && strcmp(child.name(), "include") == 0) { pugi::xml_node include = child; // load new preprocessed document (note: ideally this should handle relative paths) const char* path = include.value(); pugi::xml_document doc; if (!load_preprocess(doc, path)) return false; // insert the comment marker above include directive node.insert_child_before(pugi::node_comment, include).set_value(path); // copy the document above the include directive (this retains the original order!) for (pugi::xml_node ic = doc.first_child(); ic; ic = ic.next_sibling()) { node.insert_copy_before(ic, include); } // remove the include node and move to the next child child = child.next_sibling(); node.remove_child(include); } else { if (!preprocess(child)) return false; child = child.next_sibling(); } } return true; } bool load_preprocess(pugi::xml_document& doc, const char* path) { pugi::xml_parse_result result = doc.load_file(path, pugi::parse_default | pugi::parse_pi); // for return result ? preprocess(doc) : false; } // end::code[] int main() { pugi::xml_document doc; if (!load_preprocess(doc, "character.xml")) return -1; doc.print(std::cout); } // vim:et ================================================ FILE: external/pugixml/docs/samples/load_error_handling.cpp ================================================ #include "pugixml.hpp" #include void check_xml(const char* source) { // tag::code[] pugi::xml_document doc; pugi::xml_parse_result result = doc.load_string(source); if (result) { std::cout << "XML [" << source << "] parsed without errors, attr value: [" << doc.child("node").attribute("attr").value() << "]\n\n"; } else { std::cout << "XML [" << source << "] parsed with errors, attr value: [" << doc.child("node").attribute("attr").value() << "]\n"; std::cout << "Error description: " << result.description() << "\n"; std::cout << "Error offset: " << result.offset << " (error at [..." << (source + result.offset) << "]\n\n"; } // end::code[] } int main() { check_xml("text"); check_xml("text"); check_xml("text"); check_xml("<#tag />"); } // vim:et ================================================ FILE: external/pugixml/docs/samples/load_file.cpp ================================================ #include "pugixml.hpp" #include int main() { // tag::code[] pugi::xml_document doc; pugi::xml_parse_result result = doc.load_file("tree.xml"); std::cout << "Load result: " << result.description() << ", mesh name: " << doc.child("mesh").attribute("name").value() << std::endl; // end::code[] } // vim:et ================================================ FILE: external/pugixml/docs/samples/load_memory.cpp ================================================ #include "pugixml.hpp" #include #include int main() { // tag::decl[] const char source[] = "0 0 1 1"; size_t size = sizeof(source); // end::decl[] pugi::xml_document doc; { // tag::load_buffer[] // You can use load_buffer to load document from immutable memory block: pugi::xml_parse_result result = doc.load_buffer(source, size); // end::load_buffer[] std::cout << "Load result: " << result.description() << ", mesh name: " << doc.child("mesh").attribute("name").value() << std::endl; } { // tag::load_buffer_inplace_begin[] // You can use load_buffer_inplace to load document from mutable memory block; the block's lifetime must exceed that of document char* buffer = new char[size]; memcpy(buffer, source, size); // The block can be allocated by any method; the block is modified during parsing pugi::xml_parse_result result = doc.load_buffer_inplace(buffer, size); // end::load_buffer_inplace_begin[] std::cout << "Load result: " << result.description() << ", mesh name: " << doc.child("mesh").attribute("name").value() << std::endl; // tag::load_buffer_inplace_end[] // You have to destroy the block yourself after the document is no longer used delete[] buffer; // end::load_buffer_inplace_end[] } { // tag::load_buffer_inplace_own[] // You can use load_buffer_inplace_own to load document from mutable memory block and to pass the ownership of this block // The block has to be allocated via pugixml allocation function - using i.e. operator new here is incorrect char* buffer = static_cast(pugi::get_memory_allocation_function()(size)); memcpy(buffer, source, size); // The block will be deleted by the document pugi::xml_parse_result result = doc.load_buffer_inplace_own(buffer, size); // end::load_buffer_inplace_own[] std::cout << "Load result: " << result.description() << ", mesh name: " << doc.child("mesh").attribute("name").value() << std::endl; } { // tag::load_string[] // You can use load to load document from null-terminated strings, for example literals: pugi::xml_parse_result result = doc.load_string("0 0 1 1"); // end::load_string[] std::cout << "Load result: " << result.description() << ", mesh name: " << doc.child("mesh").attribute("name").value() << std::endl; } } // vim:et ================================================ FILE: external/pugixml/docs/samples/load_options.cpp ================================================ #include "pugixml.hpp" #include int main() { pugi::xml_document doc; // tag::code[] const char* source = "<"; // Parsing with default options; note that comment node is not added to the tree, and entity reference < is expanded doc.load_string(source); std::cout << "First node value: [" << doc.first_child().value() << "], node child value: [" << doc.child_value("node") << "]\n"; // Parsing with additional parse_comments option; comment node is now added to the tree doc.load_string(source, pugi::parse_default | pugi::parse_comments); std::cout << "First node value: [" << doc.first_child().value() << "], node child value: [" << doc.child_value("node") << "]\n"; // Parsing with additional parse_comments option and without the (default) parse_escapes option; < is not expanded doc.load_string(source, (pugi::parse_default | pugi::parse_comments) & ~pugi::parse_escapes); std::cout << "First node value: [" << doc.first_child().value() << "], node child value: [" << doc.child_value("node") << "]\n"; // Parsing with minimal option mask; comment node is not added to the tree, and < is not expanded doc.load_string(source, pugi::parse_minimal); std::cout << "First node value: [" << doc.first_child().value() << "], node child value: [" << doc.child_value("node") << "]\n"; // end::code[] } // vim:et ================================================ FILE: external/pugixml/docs/samples/load_stream.cpp ================================================ #include "pugixml.hpp" #include #include #include void print_doc(const char* message, const pugi::xml_document& doc, const pugi::xml_parse_result& result) { std::cout << message << "\t: load result '" << result.description() << "'" << ", first character of root name: U+" << std::hex << std::uppercase << std::setw(4) << std::setfill('0') << pugi::as_wide(doc.first_child().name())[0] << ", year: " << doc.first_child().first_child().first_child().child_value() << std::endl; } bool try_imbue(std::wistream& stream, const char* name) { try { stream.imbue(std::locale(name)); return true; } catch (const std::exception&) { return false; } } int main() { pugi::xml_document doc; { // tag::code[] std::ifstream stream("weekly-utf-8.xml"); pugi::xml_parse_result result = doc.load(stream); // end::code[] // first character of root name: U+9031, year: 1997 print_doc("UTF8 file from narrow stream", doc, result); } { std::ifstream stream("weekly-utf-16.xml"); pugi::xml_parse_result result = doc.load(stream); // first character of root name: U+9031, year: 1997 print_doc("UTF16 file from narrow stream", doc, result); } { // Since wide streams are treated as UTF-16/32 ones, you can't load the UTF-8 file from a wide stream // directly if you have localized characters; you'll have to provide a UTF8 locale (there is no // standard one; you can use utf8_codecvt_facet from Boost or codecvt_utf8 from C++0x) std::wifstream stream("weekly-utf-8.xml"); if (try_imbue(stream, "en_US.UTF-8")) // try Linux encoding { pugi::xml_parse_result result = doc.load(stream); // first character of root name: U+00E9, year: 1997 print_doc("UTF8 file from wide stream", doc, result); } else { std::cout << "UTF-8 locale is not available\n"; } } { // Since wide streams are treated as UTF-16/32 ones, you can't load the UTF-16 file from a wide stream without // using custom codecvt; you can use codecvt_utf16 from C++0x } { // Since encoding names are non-standard, you can't load the Shift-JIS (or any other non-ASCII) file // from a wide stream portably std::wifstream stream("weekly-shift_jis.xml"); if (try_imbue(stream, ".932") || // try Microsoft encoding try_imbue(stream, "ja_JP.SJIS")) // try Linux encoding; run "localedef -i ja_JP -c -f SHIFT_JIS /usr/lib/locale/ja_JP.SJIS" to get it { pugi::xml_parse_result result = doc.load(stream); // first character of root name: U+9031, year: 1997 print_doc("Shift-JIS file from wide stream", doc, result); } else { std::cout << "Shift-JIS locale is not available\n"; } } } // vim:et ================================================ FILE: external/pugixml/docs/samples/modify_add.cpp ================================================ #include "pugixml.hpp" #include int main() { pugi::xml_document doc; // tag::code[] // add node with some name pugi::xml_node node = doc.append_child("node"); // add description node with text child pugi::xml_node descr = node.append_child("description"); descr.append_child(pugi::node_pcdata).set_value("Simple node"); // add param node before the description pugi::xml_node param = node.insert_child_before("param", descr); // add attributes to param node param.append_attribute("name") = "version"; param.append_attribute("value") = 1.1; param.insert_attribute_after("type", param.attribute("name")) = "float"; // end::code[] doc.print(std::cout); } // vim:et ================================================ FILE: external/pugixml/docs/samples/modify_base.cpp ================================================ #include "pugixml.hpp" #include #include int main() { pugi::xml_document doc; if (!doc.load_string("text", pugi::parse_default | pugi::parse_comments)) return -1; // tag::node[] pugi::xml_node node = doc.child("node"); // change node name std::cout << node.set_name("notnode"); std::cout << ", new node name: " << node.name() << std::endl; // change comment text std::cout << doc.last_child().set_value("useless comment"); std::cout << ", new comment text: " << doc.last_child().value() << std::endl; // we can't change value of the element or name of the comment std::cout << node.set_value("1") << ", " << doc.last_child().set_name("2") << std::endl; // end::node[] // tag::attr[] pugi::xml_attribute attr = node.attribute("id"); // change attribute name/value std::cout << attr.set_name("key") << ", " << attr.set_value("345"); std::cout << ", new attribute: " << attr.name() << "=" << attr.value() << std::endl; // we can use numbers or booleans attr.set_value(1.234); std::cout << "new attribute value: " << attr.value() << std::endl; // we can also use assignment operators for more concise code attr = true; std::cout << "final attribute value: " << attr.value() << std::endl; // end::attr[] } // vim:et ================================================ FILE: external/pugixml/docs/samples/modify_remove.cpp ================================================ #include "pugixml.hpp" #include int main() { pugi::xml_document doc; if (!doc.load_string("Simple node")) return -1; // tag::code[] // remove description node with the whole subtree pugi::xml_node node = doc.child("node"); node.remove_child("description"); // remove id attribute pugi::xml_node param = node.child("param"); param.remove_attribute("value"); // we can also remove nodes/attributes by handles pugi::xml_attribute id = param.attribute("name"); param.remove_attribute(id); // end::code[] doc.print(std::cout); } // vim:et ================================================ FILE: external/pugixml/docs/samples/save_custom_writer.cpp ================================================ #include "pugixml.hpp" #include #include #include // tag::code[] struct xml_string_writer: pugi::xml_writer { std::string result; virtual void write(const void* data, size_t size) { result.append(static_cast(data), size); } }; // end::code[] struct xml_memory_writer: pugi::xml_writer { char* buffer; size_t capacity; size_t result; xml_memory_writer(): buffer(0), capacity(0), result(0) { } xml_memory_writer(char* buffer, size_t capacity): buffer(buffer), capacity(capacity), result(0) { } size_t written_size() const { return result < capacity ? result : capacity; } virtual void write(const void* data, size_t size) { if (result < capacity) { size_t chunk = (capacity - result < size) ? capacity - result : size; memcpy(buffer + result, data, chunk); } result += size; } }; std::string node_to_string(pugi::xml_node node) { xml_string_writer writer; node.print(writer); return writer.result; } char* node_to_buffer(pugi::xml_node node, char* buffer, size_t size) { if (size == 0) return buffer; // leave one character for null terminator xml_memory_writer writer(buffer, size - 1); node.print(writer); // null terminate buffer[writer.written_size()] = 0; return buffer; } char* node_to_buffer_heap(pugi::xml_node node) { // first pass: get required memory size xml_memory_writer counter; node.print(counter); // allocate necessary size (+1 for null termination) char* buffer = new char[counter.result + 1]; // second pass: actual printing xml_memory_writer writer(buffer, counter.result); node.print(writer); // null terminate buffer[writer.written_size()] = 0; return buffer; } int main() { // get a test document pugi::xml_document doc; doc.load_string("hey"); // get contents as std::string (single pass) std::cout << "contents: [" << node_to_string(doc) << "]\n"; // get contents into fixed-size buffer (single pass) char large_buf[128]; std::cout << "contents: [" << node_to_buffer(doc, large_buf, sizeof(large_buf)) << "]\n"; // get contents into fixed-size buffer (single pass, shows truncating behavior) char small_buf[22]; std::cout << "contents: [" << node_to_buffer(doc, small_buf, sizeof(small_buf)) << "]\n"; // get contents into heap-allocated buffer (two passes) char* heap_buf = node_to_buffer_heap(doc); std::cout << "contents: [" << heap_buf << "]\n"; delete[] heap_buf; } // vim:et ================================================ FILE: external/pugixml/docs/samples/save_declaration.cpp ================================================ #include "pugixml.hpp" #include int main() { // tag::code[] // get a test document pugi::xml_document doc; doc.load_string("hey"); // add a custom declaration node pugi::xml_node decl = doc.prepend_child(pugi::node_declaration); decl.append_attribute("version") = "1.0"; decl.append_attribute("encoding") = "UTF-8"; decl.append_attribute("standalone") = "no"; // // // hey // doc.save(std::cout); std::cout << std::endl; // end::code[] } // vim:et ================================================ FILE: external/pugixml/docs/samples/save_file.cpp ================================================ #include "pugixml.hpp" #include int main() { // get a test document pugi::xml_document doc; doc.load_string("hey"); // tag::code[] // save document to file std::cout << "Saving result: " << doc.save_file("save_file_output.xml") << std::endl; // end::code[] } // vim:et ================================================ FILE: external/pugixml/docs/samples/save_options.cpp ================================================ #include "pugixml.hpp" #include int main() { // tag::code[] // get a test document pugi::xml_document doc; doc.load_string("hey"); // default options; prints // // // hey // doc.save(std::cout); std::cout << std::endl; // default options with custom indentation string; prints // // // --hey // doc.save(std::cout, "--"); std::cout << std::endl; // default options without indentation; prints // // // hey // doc.save(std::cout, "\t", pugi::format_default & ~pugi::format_indent); // can also pass "" instead of indentation string for the same effect std::cout << std::endl; // raw output; prints // hey doc.save(std::cout, "\t", pugi::format_raw); std::cout << std::endl << std::endl; // raw output without declaration; prints // hey doc.save(std::cout, "\t", pugi::format_raw | pugi::format_no_declaration); std::cout << std::endl; // end::code[] } // vim:et ================================================ FILE: external/pugixml/docs/samples/save_stream.cpp ================================================ #include "pugixml.hpp" #include int main() { // get a test document pugi::xml_document doc; doc.load_string("hey"); // tag::code[] // save document to standard output std::cout << "Document:\n"; doc.save(std::cout); // end::code[] } // vim:et ================================================ FILE: external/pugixml/docs/samples/save_subtree.cpp ================================================ #include "pugixml.hpp" #include int main() { // tag::code[] // get a test document pugi::xml_document doc; doc.load_string("hey"); // print document to standard output (prints hey) doc.save(std::cout, "", pugi::format_raw); std::cout << std::endl; // print document to standard output as a regular node (prints hey) doc.print(std::cout, "", pugi::format_raw); std::cout << std::endl; // print a subtree to standard output (prints hey) doc.child("foo").child("call").print(std::cout, "", pugi::format_raw); std::cout << std::endl; // end::code[] } // vim:et ================================================ FILE: external/pugixml/docs/samples/text.cpp ================================================ #include "pugixml.hpp" #include int main() { pugi::xml_document doc; // get a test document doc.load_string("test1.1yes"); pugi::xml_node project = doc.child("project"); // tag::access[] std::cout << "Project name: " << project.child("name").text().get() << std::endl; std::cout << "Project version: " << project.child("version").text().as_double() << std::endl; std::cout << "Project visibility: " << (project.child("public").text().as_bool(/* def= */ true) ? "public" : "private") << std::endl; std::cout << "Project description: " << project.child("description").text().get() << std::endl; // end::access[] std::cout << std::endl; // tag::modify[] // change project version project.child("version").text() = 1.2; // add description element and set the contents // note that we do not have to explicitly add the node_pcdata child project.append_child("description").text().set("a test project"); // end::modify[] doc.save(std::cout); } // vim:et ================================================ FILE: external/pugixml/docs/samples/transitions.xml ================================================ ================================================ FILE: external/pugixml/docs/samples/traverse_base.cpp ================================================ #include "pugixml.hpp" #include #include int main() { pugi::xml_document doc; if (!doc.load_file("xgconsole.xml")) return -1; pugi::xml_node tools = doc.child("Profile").child("Tools"); // tag::basic[] for (pugi::xml_node tool = tools.first_child(); tool; tool = tool.next_sibling()) { std::cout << "Tool:"; for (pugi::xml_attribute attr = tool.first_attribute(); attr; attr = attr.next_attribute()) { std::cout << " " << attr.name() << "=" << attr.value(); } std::cout << std::endl; } // end::basic[] std::cout << std::endl; // tag::data[] for (pugi::xml_node tool = tools.child("Tool"); tool; tool = tool.next_sibling("Tool")) { std::cout << "Tool " << tool.attribute("Filename").value(); std::cout << ": AllowRemote " << tool.attribute("AllowRemote").as_bool(); std::cout << ", Timeout " << tool.attribute("Timeout").as_int(); std::cout << ", Description '" << tool.child_value("Description") << "'\n"; } // end::data[] std::cout << std::endl; // tag::contents[] std::cout << "Tool for *.dae generation: " << tools.find_child_by_attribute("Tool", "OutputFileMasks", "*.dae").attribute("Filename").value() << "\n"; for (pugi::xml_node tool = tools.child("Tool"); tool; tool = tool.next_sibling("Tool")) { std::cout << "Tool " << tool.attribute("Filename").value() << "\n"; } // end::contents[] } // vim:et ================================================ FILE: external/pugixml/docs/samples/traverse_iter.cpp ================================================ #include "pugixml.hpp" #include int main() { pugi::xml_document doc; if (!doc.load_file("xgconsole.xml")) return -1; pugi::xml_node tools = doc.child("Profile").child("Tools"); // tag::code[] for (pugi::xml_node_iterator it = tools.begin(); it != tools.end(); ++it) { std::cout << "Tool:"; for (pugi::xml_attribute_iterator ait = it->attributes_begin(); ait != it->attributes_end(); ++ait) { std::cout << " " << ait->name() << "=" << ait->value(); } std::cout << std::endl; } // end::code[] } // vim:et ================================================ FILE: external/pugixml/docs/samples/traverse_predicate.cpp ================================================ #include "pugixml.hpp" #include #include // tag::decl[] bool small_timeout(pugi::xml_node node) { return node.attribute("Timeout").as_int() < 20; } struct allow_remote_predicate { bool operator()(pugi::xml_attribute attr) const { return strcmp(attr.name(), "AllowRemote") == 0; } bool operator()(pugi::xml_node node) const { return node.attribute("AllowRemote").as_bool(); } }; // end::decl[] int main() { pugi::xml_document doc; if (!doc.load_file("xgconsole.xml")) return -1; pugi::xml_node tools = doc.child("Profile").child("Tools"); // tag::find[] // Find child via predicate (looks for direct children only) std::cout << tools.find_child(allow_remote_predicate()).attribute("Filename").value() << std::endl; // Find node via predicate (looks for all descendants in depth-first order) std::cout << doc.find_node(allow_remote_predicate()).attribute("Filename").value() << std::endl; // Find attribute via predicate std::cout << tools.last_child().find_attribute(allow_remote_predicate()).value() << std::endl; // We can use simple functions instead of function objects std::cout << tools.find_child(small_timeout).attribute("Filename").value() << std::endl; // end::find[] } // vim:et ================================================ FILE: external/pugixml/docs/samples/traverse_rangefor.cpp ================================================ #include "pugixml.hpp" #include int main() { pugi::xml_document doc; if (!doc.load_file("xgconsole.xml")) return -1; pugi::xml_node tools = doc.child("Profile").child("Tools"); // tag::code[] for (pugi::xml_node tool: tools.children("Tool")) { std::cout << "Tool:"; for (pugi::xml_attribute attr: tool.attributes()) { std::cout << " " << attr.name() << "=" << attr.value(); } for (pugi::xml_node child: tool.children()) { std::cout << ", child " << child.name(); } std::cout << std::endl; } // end::code[] } // vim:et ================================================ FILE: external/pugixml/docs/samples/traverse_walker.cpp ================================================ #include "pugixml.hpp" #include const char* node_types[] = { "null", "document", "element", "pcdata", "cdata", "comment", "pi", "declaration" }; // tag::impl[] struct simple_walker: pugi::xml_tree_walker { virtual bool for_each(pugi::xml_node& node) { for (int i = 0; i < depth(); ++i) std::cout << " "; // indentation std::cout << node_types[node.type()] << ": name='" << node.name() << "', value='" << node.value() << "'\n"; return true; // continue traversal } }; // end::impl[] int main() { pugi::xml_document doc; if (!doc.load_file("tree.xml")) return -1; // tag::traverse[] simple_walker walker; doc.traverse(walker); // end::traverse[] } // vim:et ================================================ FILE: external/pugixml/docs/samples/tree.xml ================================================ some text some more text ================================================ FILE: external/pugixml/docs/samples/weekly-shift_jis.xml ================================================ 1997 1 1 <> <>Rc <>Y <Ɩ񍐃Xg> <Ɩ> <Ɩ>XMLGfB^[̍쐬 <ƖR[h>X3355-23 <ςH>1600 <эH>320 <ςH>160 <эH>24 <\荀ڃXg> <\荀>

XMLGfB^[̊{dl̍쐬

<{Xg> <{>

XMLGfB^[̊{dl̍쐬

<{>

Аi̋@\

<㒷ւ̗vXg> <㒷ւ̗v>

ɂȂ

<_΍>

XMLƂ͉킩ȂB

<Ɩ> <Ɩ>GW̊J <ƖR[h>S8821-76 <ςH>120 <эH>6 <ςH>32 <эH>2 <\荀ڃXg> <\荀>

goő@\𒲂ׂĂ݂

<{Xg> <{>

XɁAǂGW邩

<㒷ւ̗vXg> <㒷ւ̗v>

Ĵ͂߂ǂȂ̂ŁAYahoo!𔃎ĉB

<_΍>

GWŎԂ𑖂点邱ƂłȂBivj

================================================ FILE: external/pugixml/docs/samples/weekly-utf-8.xml ================================================ <週報> <年月週> <年度>1997 <月度>1 <週>1 <氏名> <氏>山田 <名>太郎 <業務報告リスト> <業務報告> <業務名>XMLエディターの作成 <業務コード>X3355-23 <工数管理> <見積もり工数>1600 <実績工数>320 <当月見積もり工数>160 <当月実績工数>24 <予定項目リスト> <予定項目>

XMLエディターの基本仕様の作成

<実施事項リスト> <実施事項>

XMLエディターの基本仕様の作成

<実施事項>

競合他社製品の機能調査

<上長への要請事項リスト> <上長への要請事項>

特になし

<問題点対策>

XMLとは何かわからない。

<業務報告> <業務名>検索エンジンの開発 <業務コード>S8821-76 <工数管理> <見積もり工数>120 <実績工数>6 <当月見積もり工数>32 <当月実績工数>2 <予定項目リスト> <予定項目>

gooの機能を調べてみる

<実施事項リスト> <実施事項>

更に、どういう検索エンジンがあるか調査する

<上長への要請事項リスト> <上長への要請事項>

開発をするのはめんどうなので、Yahoo!を買収して下さい。

<問題点対策>

検索エンジンで車を走らせることができない。(要調査)

================================================ FILE: external/pugixml/docs/samples/xgconsole.xml ================================================ Jamplus build system ================================================ FILE: external/pugixml/docs/samples/xpath_error.cpp ================================================ #include "pugixml.hpp" #include int main() { pugi::xml_document doc; if (!doc.load_file("xgconsole.xml")) return -1; // tag::code[] // Exception is thrown for incorrect query syntax try { doc.select_nodes("//nodes[#true()]"); } catch (const pugi::xpath_exception& e) { std::cout << "Select failed: " << e.what() << std::endl; } // Exception is thrown for incorrect query semantics try { doc.select_nodes("(123)/next"); } catch (const pugi::xpath_exception& e) { std::cout << "Select failed: " << e.what() << std::endl; } // Exception is thrown for query with incorrect return type try { doc.select_nodes("123"); } catch (const pugi::xpath_exception& e) { std::cout << "Select failed: " << e.what() << std::endl; } // end::code[] } // vim:et ================================================ FILE: external/pugixml/docs/samples/xpath_query.cpp ================================================ #include "pugixml.hpp" #include #include int main() { pugi::xml_document doc; if (!doc.load_file("xgconsole.xml")) return -1; // tag::code[] // Select nodes via compiled query pugi::xpath_query query_remote_tools("/Profile/Tools/Tool[@AllowRemote='true']"); pugi::xpath_node_set tools = query_remote_tools.evaluate_node_set(doc); std::cout << "Remote tool: "; tools[2].node().print(std::cout); // Evaluate numbers via compiled query pugi::xpath_query query_timeouts("sum(//Tool/@Timeout)"); std::cout << query_timeouts.evaluate_number(doc) << std::endl; // Evaluate strings via compiled query for different context nodes pugi::xpath_query query_name_valid("string-length(substring-before(@Filename, '_')) > 0 and @OutputFileMasks"); pugi::xpath_query query_name("concat(substring-before(@Filename, '_'), ' produces ', @OutputFileMasks)"); for (pugi::xml_node tool = doc.first_element_by_path("Profile/Tools/Tool"); tool; tool = tool.next_sibling()) { std::string s = query_name.evaluate_string(tool); if (query_name_valid.evaluate_boolean(tool)) std::cout << s << std::endl; } // end::code[] } // vim:et ================================================ FILE: external/pugixml/docs/samples/xpath_select.cpp ================================================ #include "pugixml.hpp" #include int main() { pugi::xml_document doc; if (!doc.load_file("xgconsole.xml")) return -1; // tag::code[] pugi::xpath_node_set tools = doc.select_nodes("/Profile/Tools/Tool[@AllowRemote='true' and @DeriveCaptionFrom='lastparam']"); std::cout << "Tools:\n"; for (pugi::xpath_node_set::const_iterator it = tools.begin(); it != tools.end(); ++it) { pugi::xpath_node node = *it; std::cout << node.node().attribute("Filename").value() << "\n"; } pugi::xpath_node build_tool = doc.select_node("//Tool[contains(Description, 'build system')]"); if (build_tool) std::cout << "Build tool: " << build_tool.node().attribute("Filename").value() << "\n"; // end::code[] } // vim:et ================================================ FILE: external/pugixml/docs/samples/xpath_variables.cpp ================================================ #include "pugixml.hpp" #include #include int main() { pugi::xml_document doc; if (!doc.load_file("xgconsole.xml")) return -1; // tag::code[] // Select nodes via compiled query pugi::xpath_variable_set vars; vars.add("remote", pugi::xpath_type_boolean); pugi::xpath_query query_remote_tools("/Profile/Tools/Tool[@AllowRemote = string($remote)]", &vars); vars.set("remote", true); pugi::xpath_node_set tools_remote = query_remote_tools.evaluate_node_set(doc); vars.set("remote", false); pugi::xpath_node_set tools_local = query_remote_tools.evaluate_node_set(doc); std::cout << "Remote tool: "; tools_remote[2].node().print(std::cout); std::cout << "Local tool: "; tools_local[0].node().print(std::cout); // You can pass the context directly to select_nodes/select_node pugi::xpath_node_set tools_local_imm = doc.select_nodes("/Profile/Tools/Tool[@AllowRemote = string($remote)]", &vars); std::cout << "Local tool imm: "; tools_local_imm[0].node().print(std::cout); // end::code[] } // vim:et ================================================ FILE: external/pugixml/readme.txt ================================================ pugixml 1.15 - an XML processing library Copyright (C) 2006-2025, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) Report bugs and download new versions at https://pugixml.org/ This is the distribution of pugixml, which is a C++ XML processing library, which consists of a DOM-like interface with rich traversal/modification capabilities, an extremely fast XML parser which constructs the DOM tree from an XML file/buffer, and an XPath 1.0 implementation for complex data-driven tree queries. Full Unicode support is also available, with Unicode interface variants and conversions between different Unicode encodings (which happen automatically during parsing/saving). The distribution contains the following folders: docs/ - documentation docs/samples - pugixml usage examples docs/quickstart.html - quick start guide docs/manual.html - complete manual scripts/ - project files for IDE/build systems src/ - header and source files readme.txt - this file. This library is distributed under the MIT License: Copyright (c) 2006-2025 Arseny Kapoulkine Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: external/pugixml/scripts/cocoapods_push.sh ================================================ #!/bin/bash #Push to igagis repo for now pod repo push igagis pugixml.podspec --use-libraries --verbose ================================================ FILE: external/pugixml/scripts/natvis/pugixml.natvis ================================================ {_root} none _root {(pugi::xml_node_type)(header & 0xf),en} name={name,na} value={value,na} {(pugi::xml_node_type)(header & 0xf),en} name={name,na} {(pugi::xml_node_type)(header & 0xf),en} value={value,na} {(pugi::xml_node_type)(header & 0xf),en} value,na curr,view(child)na curr = curr->next_attribute first_child next_sibling this,na {_attr} none _attr {name,na} = {value,na} {value,na} name,na value,na {_node,na} "{_attribute._attr->name,na}"="{_attribute._attr->value,na}" {_node,na} {_attribute} empty _node _attribute _node,na _attribute,na _type _end - _begin _begin ================================================ FILE: external/pugixml/scripts/natvis/pugixml_compact.natvis ================================================ {_root} none _root {_attr} none _attr (pugi::xml_node_type)(header._flags & 15) name,na value,na ... h = h ^ (h >> 16) h = h * (0x85ebca6bu) h = h ^ (h >> 13) h = h * (0xc2b2ae35u) h = h ^ (h >> 16) bucket = h & hashmod probe_item = (size_t*)_items + bucket * 2 attribute_real = *(pugi::xml_attribute_struct**)(probe_item + 1) bucket = (bucket + probe + 1) & hashmod probe++ attribute_data_copy = attribute_data *attribute_real,view(child) attribute_this = (size_t)&(*attribute_real).next_attribute attribute_data = (*attribute_real).next_attribute._data *attribute_short,view(child) attribute_this = (size_t)&(*attribute_short).next_attribute attribute_data = (*attribute_short).next_attribute._data attribute_T1 = 7 attribute_T2 = 0 h = (unsigned)attribute_this bucket = 0 probe = 0 probe_item = (size_t*)0 attribute_real = (pugi::xml_attribute_struct*)0 attribute_short = (pugi::xml_attribute_struct*)(((size_t)attribute_this & ~(compact_alignment - 1)) + (attribute_data - 1 + attribute_T2) * compact_alignment) number++ h = h ^ (h >> 16) h = h * (0x85ebca6bu) h = h ^ (h >> 13) h = h * (0xc2b2ae35u) h = h ^ (h >> 16) bucket = h & hashmod probe_item = (size_t*)_items + bucket * 2 child_real = *(pugi::xml_node_struct**)(probe_item + 1) bucket = (bucket + probe + 1) & hashmod probe++ child_data_copy = child_data *child_real,view(child) child_this = (size_t)&(*child_real).next_sibling child_data = (*child_real).next_sibling._data *child_short,view(child) child_this = (size_t)&(*child_short).next_sibling child_data = (*child_short).next_sibling._data child_T1 = 10 child_T2 = 0 h = (unsigned)child_this bucket = 0 probe = 0 probe_item = (size_t*)0 child_real = (pugi::xml_node_struct*)0 child_short = (pugi::xml_node_struct*)(((size_t)child_this & ~(compact_alignment - 1)) + (child_data - 1 + child_T2) * compact_alignment) number++ next_sibling name,na value,na h = h ^ (h >> 16) h = h * (0x85ebca6bu) h = h ^ (h >> 13) h = h * (0xc2b2ae35u) h = h ^ (h >> 16) bucket = h & hashmod probe_item = (size_t*)_items + bucket * 2 attribute_real = *(pugi::xml_attribute_struct**)(probe_item + 1) bucket = (bucket + probe + 1) & hashmod probe++ *attribute_real *attribute_short (pugi::char_t*)(compact_string_base + offset * sizeof(pugi::char_t)),na h = h ^ (h >> 16) h = h * (0x85ebca6bu) h = h ^ (h >> 13) h = h * (0xc2b2ae35u) h = h ^ (h >> 16) bucket = h & hashmod probe_item = (size_t*)_items + bucket * 2 *(pugi::char_t**)(probe_item + 1) bucket = (bucket + probe + 1) & hashmod probe++ nullptr ... *(pugi::xml_node_struct*)(((size_t)this & ~(compact_alignment - 1)) + (_data - 1 + $T2) * compact_alignment) h = h ^ (h >> 16) h = h * (0x85ebca6bu) h = h ^ (h >> 13) h = h * (0xc2b2ae35u) h = h ^ (h >> 16) bucket = h & hashmod probe_item = (size_t*)_items + bucket * 2 **(pugi::xml_node_struct**)(probe_item + 1) bucket = (bucket + probe + 1) & hashmod probe++ nullptr ... *(pugi::xml_attribute_struct*)(((size_t)this & ~(compact_alignment - 1)) + (_data - 1 + $T2) * compact_alignment) h = h ^ (h >> 16) h = h * (0x85ebca6bu) h = h ^ (h >> 13) h = h * (0xc2b2ae35u) h = h ^ (h >> 16) bucket = h & hashmod probe_item = (size_t*)_items + bucket * 2 **(pugi::xml_attribute_struct**)(probe_item + 1) bucket = (bucket + probe + 1) & hashmod probe++ {_node,na} {_attribute,na} {_node,na} {_attribute} empty _node _attribute _node,na _attribute,na _type _end - _begin _begin ================================================ FILE: external/pugixml/scripts/nuget/pugixml.nuspec ================================================  pugixml 1.15.0 pugixml Arseny Kapoulkine Arseny Kapoulkine false MIT https://pugixml.org/ pugixml is a C++ XML processing library, which consists of a DOM-like interface with rich traversal/modification capabilities, an extremely fast XML parser which constructs the DOM tree from an XML file/buffer, and an XPath 1.0 implementation for complex data-driven tree queries. Full Unicode support is also available, with Unicode interface variants and conversions between different Unicode encodings (which happen automatically during parsing/saving). pugixml is used by a lot of projects, both open-source and proprietary, for performance and easy-to-use interface. This package contains builds for VS2013, VS2015, VS2017, VS2019 and VS2022, for both statically linked and DLL CRT; you can switch the CRT linkage in Project -> Properties -> Referenced Packages -> pugixml. Light-weight, simple and fast XML parser for C++ with XPath support https://pugixml.org/docs/manual.html#changes Copyright (c) 2006-2025 Arseny Kapoulkine native nativepackage ================================================ FILE: external/pugixml/scripts/nuget_build.ps1 ================================================ function Run-Command([string]$cmd) { Invoke-Expression $cmd if ($LastExitCode) { exit $LastExitCode } } function Force-Copy([string]$from, [string]$to) { Write-Host $from "->" $to New-Item -Force $to | Out-Null Copy-Item -Force $from $to if (! $?) { exit 1 } } function Build-Version([string]$vs, [string]$toolset, [string]$linkage) { $prjsuffix = if ($linkage -eq "static") { "_static" } else { "" } $cfgsuffix = if ($linkage -eq "static") { "Static" } else { "" } foreach ($configuration in "Debug","Release") { Run-Command "msbuild pugixml_$vs$prjsuffix.vcxproj /t:Rebuild /p:Configuration=$configuration /p:Platform=x86 /v:minimal /nologo" Run-Command "msbuild pugixml_$vs$prjsuffix.vcxproj /t:Rebuild /p:Configuration=$configuration /p:Platform=x64 /v:minimal /nologo" Force-Copy "$vs/Win32_$configuration$cfgsuffix/pugixml.lib" "nuget/build/native/lib/Win32/$toolset/$linkage/$configuration/pugixml.lib" Force-Copy "$vs/x64_$configuration$cfgsuffix/pugixml.lib" "nuget/build/native/lib/x64/$toolset/$linkage/$configuration/pugixml.lib" } } Push-Location $scriptdir = Split-Path $MyInvocation.MyCommand.Path cd $scriptdir Force-Copy "../src/pugiconfig.hpp" "nuget/build/native/include/pugiconfig.hpp" Force-Copy "../src/pugixml.hpp" "nuget/build/native/include/pugixml.hpp" Force-Copy "../src/pugixml.cpp" "nuget/build/native/include/pugixml.cpp" if ($args[0] -eq 2022){ Build-Version "vs2022" "v143" "dynamic" Build-Version "vs2022" "v143" "static" } elseif ($args[0] -eq 2019){ Build-Version "vs2019" "v142" "dynamic" Build-Version "vs2019" "v142" "static" } elseif ($args[0] -eq 2017){ Build-Version "vs2017" "v141" "dynamic" Build-Version "vs2017" "v141" "static" Build-Version "vs2015" "v140" "dynamic" Build-Version "vs2015" "v140" "static" Build-Version "vs2013" "v120" "dynamic" Build-Version "vs2013" "v120" "static" } elseif($args[0] -eq 2015){ Build-Version "vs2015" "v140" "dynamic" Build-Version "vs2015" "v140" "static" Build-Version "vs2013" "v120" "dynamic" Build-Version "vs2013" "v120" "static" } elseif($args[0] -eq 2013){ Build-Version "vs2013" "v120" "dynamic" Build-Version "vs2013" "v120" "static" } Run-Command "nuget pack nuget" Pop-Location ================================================ FILE: external/pugixml/scripts/premake4.lua ================================================ -- Reset RNG seed to get consistent results across runs (i.e. XCode) math.randomseed(12345) local static = _ARGS[1] == 'static' local action = premake.action.current() if string.startswith(_ACTION, "vs") then if action then -- Disable solution generation function action.onsolution(sln) sln.vstudio_configs = premake.vstudio_buildconfigs(sln) end -- Rename output file function action.onproject(prj) local name = "%%_" .. _ACTION .. (static and "_static" or "") if static then for k, v in pairs(prj.project.__configs) do v.objectsdir = v.objectsdir .. "Static" end end if _ACTION == "vs2010" then premake.generate(prj, name .. ".vcxproj", premake.vs2010_vcxproj) else premake.generate(prj, name .. ".vcproj", premake.vs200x_vcproj) end end end elseif _ACTION == "codeblocks" then action.onsolution = nil function action.onproject(prj) premake.generate(prj, "%%_" .. _ACTION .. ".cbp", premake.codeblocks_cbp) end elseif _ACTION == "codelite" then action.onsolution = nil function action.onproject(prj) premake.generate(prj, "%%_" .. _ACTION .. ".project", premake.codelite_project) end end solution "pugixml" objdir(_ACTION) targetdir(_ACTION) if string.startswith(_ACTION, "vs") then if _ACTION ~= "vs2002" and _ACTION ~= "vs2003" then platforms { "x32", "x64" } configuration "x32" targetdir(_ACTION .. "/x32") configuration "x64" targetdir(_ACTION .. "/x64") end configurations { "Debug", "Release" } if static then configuration "Debug" targetsuffix "sd" configuration "Release" targetsuffix "s" else configuration "Debug" targetsuffix "d" end else if _ACTION == "xcode3" then platforms "universal" end configurations { "Debug", "Release" } configuration "Debug" targetsuffix "d" end project "pugixml" kind "StaticLib" language "C++" files { "../src/pugixml.hpp", "../src/pugiconfig.hpp", "../src/pugixml.cpp" } flags { "NoPCH", "NoMinimalRebuild", "NoEditAndContinue", "Symbols" } uuid "89A1E353-E2DC-495C-B403-742BE206ACED" configuration "Debug" defines { "_DEBUG" } configuration "Release" defines { "NDEBUG" } flags { "Optimize" } if static then configuration "*" flags { "StaticRuntime" } end ================================================ FILE: external/pugixml/scripts/pugixml-config.cmake.in ================================================ @PACKAGE_INIT@ include("${CMAKE_CURRENT_LIST_DIR}/pugixml-targets.cmake") # If the user is not requiring 1.11 (either by explicitly requesting an older # version or not requesting one at all), provide the old imported target name # for compatibility. if (NOT TARGET pugixml AND (NOT DEFINED PACKAGE_FIND_VERSION OR PACKAGE_FIND_VERSION VERSION_LESS "1.11")) add_library(pugixml INTERFACE IMPORTED) # Equivalent to target_link_libraries INTERFACE, but compatible with CMake 3.10 set_target_properties(pugixml PROPERTIES INTERFACE_LINK_LIBRARIES pugixml::pugixml) endif () ================================================ FILE: external/pugixml/scripts/pugixml.pc.in ================================================ prefix=@CMAKE_INSTALL_PREFIX@ exec_prefix=${prefix} includedir=@PUGIXML_PC_INCLUDEDIR@ libdir=@PUGIXML_PC_LIBDIR@ Name: pugixml Description: Light-weight, simple and fast XML parser for C++ with XPath support. URL: https://pugixml.org/ Version: @pugixml_VERSION@ Cflags: -I${includedir} Libs: -L${libdir} -lpugixml@LIB_POSTFIX@ ================================================ FILE: external/pugixml/scripts/pugixml.podspec ================================================ Pod::Spec.new do |s| s.name = "pugixml" s.version = "1.15" s.summary = "C++ XML parser library." s.homepage = "https://pugixml.org" s.license = "MIT" s.author = { "Arseny Kapoulkine" => "arseny.kapoulkine@gmail.com" } s.platform = :ios, "7.0" s.source = { :git => "https://github.com/zeux/pugixml.git", :tag => "v" + s.version.to_s } s.source_files = "src/**/*.{hpp,cpp}" s.header_mappings_dir = "src" end ================================================ FILE: external/pugixml/scripts/pugixml.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 45; objects = { /* Begin PBXBuildFile section */ 0424128F67AB5C730232235E /* pugixml.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 47481C4F0E03673E0E780637 /* pugixml.cpp */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ 0B66463C5F896E6449051D38 /* pugiconfig.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = "pugiconfig.hpp"; path = "pugiconfig.hpp"; sourceTree = ""; }; 47481C4F0E03673E0E780637 /* pugixml.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "pugixml.cpp"; path = "pugixml.cpp"; sourceTree = ""; }; 6C911F0460FC44CD3B1B5624 /* pugixml.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = "pugixml.hpp"; path = "pugixml.hpp"; sourceTree = ""; }; 1DA04ADC64C3566D16C45B6D /* libpugixmld.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; name = "libpugixmld.a"; path = "libpugixmld.a"; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 2BA00212518037166623673F /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 19E0517F3CF26ED63AE23641 /* pugixml */ = { isa = PBXGroup; children = ( 578963B4309E714F05E01D71 /* src */, 219F66186DDF392149043810 /* Products */, ); name = "pugixml"; sourceTree = ""; }; 578963B4309E714F05E01D71 /* src */ = { isa = PBXGroup; children = ( 0B66463C5F896E6449051D38 /* pugiconfig.hpp */, 47481C4F0E03673E0E780637 /* pugixml.cpp */, 6C911F0460FC44CD3B1B5624 /* pugixml.hpp */, ); name = "src"; path = ../src; sourceTree = ""; }; 219F66186DDF392149043810 /* Products */ = { isa = PBXGroup; children = ( 1DA04ADC64C3566D16C45B6D /* libpugixmld.a */, ); name = "Products"; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ 6B55152571905B6C3A6F39D0 /* pugixml */ = { isa = PBXNativeTarget; buildConfigurationList = 73BF376C14AA1ECC0AC517ED /* Build configuration list for PBXNativeTarget "pugixml" */; buildPhases = ( 6CA66B9B6252229A36E8733C /* Resources */, 287808486FBF545206A47CC1 /* Sources */, 2BA00212518037166623673F /* Frameworks */, ); buildRules = ( ); dependencies = ( ); name = "pugixml"; productName = "pugixml"; productReference = 1DA04ADC64C3566D16C45B6D /* libpugixmld.a */; productType = "com.apple.product-type.library.static"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 08FB7793FE84155DC02AAC07 /* Project object */ = { isa = PBXProject; buildConfigurationList = 1DEB928908733DD80010E9CD /* Build configuration list for PBXProject "pugixml" */; compatibilityVersion = "Xcode 3.1"; hasScannedForEncodings = 1; mainGroup = 19E0517F3CF26ED63AE23641 /* pugixml */; projectDirPath = ""; projectRoot = ""; targets = ( 6B55152571905B6C3A6F39D0 /* libpugixmld.a */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 6CA66B9B6252229A36E8733C /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ 287808486FBF545206A47CC1 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 0424128F67AB5C730232235E /* pugixml.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXVariantGroup section */ /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ 4FDB54E4253E36FC55CE27E8 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CONFIGURATION_BUILD_DIR = xcode3; GCC_DYNAMIC_NO_PIC = NO; GCC_MODEL_TUNING = G5; INSTALL_PATH = /usr/local/lib; PRODUCT_NAME = "pugixmld"; }; name = "Debug"; }; 0A4C28F553990E0405306C15 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CONFIGURATION_BUILD_DIR = xcode3; GCC_DYNAMIC_NO_PIC = NO; GCC_MODEL_TUNING = G5; INSTALL_PATH = /usr/local/lib; PRODUCT_NAME = "pugixml"; }; name = "Release"; }; 65DB0F6D27EA20852B6E3BB4 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; CONFIGURATION_BUILD_DIR = "$(SYMROOT)"; CONFIGURATION_TEMP_DIR = "$(OBJROOT)"; COPY_PHASE_STRIP = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "_DEBUG", ); GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNUSED_VARIABLE = YES; OBJROOT = "xcode3/Universal/Debug"; ONLY_ACTIVE_ARCH = NO; PREBINDING = NO; SYMROOT = "xcode3"; }; name = "Debug"; }; 5314084032B57C1A11945858 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; CONFIGURATION_BUILD_DIR = "$(SYMROOT)"; CONFIGURATION_TEMP_DIR = "$(OBJROOT)"; COPY_PHASE_STRIP = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_OPTIMIZATION_LEVEL = s; GCC_PREPROCESSOR_DEFINITIONS = ( "NDEBUG", ); GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNUSED_VARIABLE = YES; OBJROOT = "xcode3/Universal/Release"; ONLY_ACTIVE_ARCH = NO; PREBINDING = NO; SYMROOT = "xcode3"; }; name = "Release"; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 73BF376C14AA1ECC0AC517ED /* Build configuration list for PBXNativeTarget "libpugixmld.a" */ = { isa = XCConfigurationList; buildConfigurations = ( 4FDB54E4253E36FC55CE27E8 /* Debug */, 0A4C28F553990E0405306C15 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = "Debug"; }; 1DEB928908733DD80010E9CD /* Build configuration list for PBXProject "pugixml" */ = { isa = XCConfigurationList; buildConfigurations = ( 65DB0F6D27EA20852B6E3BB4 /* Debug */, 5314084032B57C1A11945858 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = "Debug"; }; /* End XCConfigurationList section */ }; rootObject = 08FB7793FE84155DC02AAC07 /* Project object */; } ================================================ FILE: external/pugixml/scripts/pugixml_airplay.mkf ================================================ includepaths { "../src" } files { ("../src") pugiconfig.hpp pugixml.cpp pugixml.hpp } ================================================ FILE: external/pugixml/scripts/pugixml_codeblocks.cbp ================================================ ================================================ FILE: external/pugixml/scripts/pugixml_codelite.project ================================================ None None ================================================ FILE: external/pugixml/scripts/pugixml_dll.rc ================================================ #include #define PUGIXML_VERSION_MAJOR 1 #define PUGIXML_VERSION_MINOR 15 #define PUGIXML_VERSION_PATCH 0 #define PUGIXML_VERSION_NUMBER "1.15.0\0" #if defined(GCC_WINDRES) || defined(__MINGW32__) || defined(__CYGWIN__) VS_VERSION_INFO VERSIONINFO #else VS_VERSION_INFO VERSIONINFO MOVEABLE IMPURE LOADONCALL DISCARDABLE #endif FILEVERSION PUGIXML_VERSION_MAJOR,PUGIXML_VERSION_MINOR,PUGIXML_VERSION_PATCH,0 PRODUCTVERSION PUGIXML_VERSION_MAJOR,PUGIXML_VERSION_MINOR,PUGIXML_VERSION_PATCH,0 FILEFLAGSMASK VS_FFI_FILEFLAGSMASK #ifdef _DEBUG FILEFLAGS 1 #else FILEFLAGS 0 #endif FILEOS VOS__WINDOWS32 FILETYPE VFT_DLL FILESUBTYPE 0 // not used BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904E4" //language ID = U.S. English, char set = Windows, Multilingual BEGIN VALUE "CompanyName", "zeux/pugixml\0" VALUE "FileDescription", "pugixml library\0" VALUE "FileVersion", PUGIXML_VERSION_NUMBER VALUE "InternalName", "pugixml.dll\0" VALUE "LegalCopyright", "Copyright (C) 2006-2025, by Arseny Kapoulkine\0" VALUE "OriginalFilename", "pugixml.dll\0" VALUE "ProductName", "pugixml\0" VALUE "ProductVersion", PUGIXML_VERSION_NUMBER VALUE "Comments", "For more information visit https://github.com/zeux/pugixml/\0" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x0409, 1252 END END ================================================ FILE: external/pugixml/scripts/pugixml_vs2005.vcproj ================================================ ================================================ FILE: external/pugixml/scripts/pugixml_vs2005_static.vcproj ================================================ ================================================ FILE: external/pugixml/scripts/pugixml_vs2008.vcproj ================================================ ================================================ FILE: external/pugixml/scripts/pugixml_vs2008_static.vcproj ================================================ ================================================ FILE: external/pugixml/scripts/pugixml_vs2010.vcxproj ================================================ Debug Win32 Debug x64 Release Win32 Release x64 {89A1E353-E2DC-495C-B403-742BE206ACED} pugixml Win32Proj StaticLibrary MultiByte true StaticLibrary MultiByte true StaticLibrary MultiByte true false StaticLibrary MultiByte true false <_ProjectFileVersion>10.0.30319.1 vs2010\Win32_Debug\ vs2010\Win32_Debug\ pugixml vs2010\x64_Debug\ vs2010\x64_Debug\ pugixml vs2010\Win32_Release\ vs2010\Win32_Release\ pugixml vs2010\x64_Release\ vs2010\x64_Release\ pugixml Disabled _DEBUG;%(PreprocessorDefinitions) false EnableFastChecks MultiThreadedDebugDLL true Level3 ProgramDatabase _DEBUG;%(PreprocessorDefinitions) $(OutDir)pugixml.lib Windows true $(OutDir)pugixml.pdb Disabled _DEBUG;%(PreprocessorDefinitions) false EnableFastChecks MultiThreadedDebugDLL true Level3 ProgramDatabase _DEBUG;%(PreprocessorDefinitions) $(OutDir)pugixml.lib Windows true $(OutDir)pugixml.pdb Full NDEBUG;%(PreprocessorDefinitions) false true MultiThreadedDLL true Level3 ProgramDatabase NDEBUG;%(PreprocessorDefinitions) $(OutDir)pugixml.lib Windows true true true $(OutDir)pugixml.pdb Full NDEBUG;%(PreprocessorDefinitions) false true MultiThreadedDLL true Level3 ProgramDatabase NDEBUG;%(PreprocessorDefinitions) $(OutDir)pugixml.lib Windows true true true $(OutDir)pugixml.pdb ================================================ FILE: external/pugixml/scripts/pugixml_vs2010_static.vcxproj ================================================ Debug Win32 Debug x64 Release Win32 Release x64 {89A1E353-E2DC-495C-B403-742BE206ACED} pugixml Win32Proj StaticLibrary MultiByte true StaticLibrary MultiByte true StaticLibrary MultiByte true false StaticLibrary MultiByte true false <_ProjectFileVersion>10.0.30319.1 vs2010\Win32_DebugStatic\ vs2010\Win32_DebugStatic\ pugixml vs2010\x64_DebugStatic\ vs2010\x64_DebugStatic\ pugixml vs2010\Win32_ReleaseStatic\ vs2010\Win32_ReleaseStatic\ pugixml vs2010\x64_ReleaseStatic\ vs2010\x64_ReleaseStatic\ pugixml Disabled _DEBUG;%(PreprocessorDefinitions) false EnableFastChecks MultiThreadedDebug true Level3 ProgramDatabase _DEBUG;%(PreprocessorDefinitions) $(OutDir)pugixml.lib Windows true $(OutDir)pugixml.pdb Disabled _DEBUG;%(PreprocessorDefinitions) false EnableFastChecks MultiThreadedDebug true Level3 ProgramDatabase _DEBUG;%(PreprocessorDefinitions) $(OutDir)pugixml.lib Windows true $(OutDir)pugixml.pdb Full NDEBUG;%(PreprocessorDefinitions) false true MultiThreaded true Level3 ProgramDatabase NDEBUG;%(PreprocessorDefinitions) $(OutDir)pugixml.lib Windows true true true $(OutDir)pugixml.pdb Full NDEBUG;%(PreprocessorDefinitions) false true MultiThreaded true Level3 ProgramDatabase NDEBUG;%(PreprocessorDefinitions) $(OutDir)pugixml.lib Windows true true true $(OutDir)pugixml.pdb ================================================ FILE: external/pugixml/scripts/pugixml_vs2013.vcxproj ================================================  Debug Win32 Debug x64 Release Win32 Release x64 {89A1E353-E2DC-495C-B403-742BE206ACED} pugixml Win32Proj StaticLibrary MultiByte true v120 StaticLibrary MultiByte true v120 StaticLibrary MultiByte true false v120 StaticLibrary MultiByte true false v120 <_ProjectFileVersion>10.0.30319.1 vs2013\Win32_Debug\ vs2013\Win32_Debug\ pugixml vs2013\x64_Debug\ vs2013\x64_Debug\ pugixml vs2013\Win32_Release\ vs2013\Win32_Release\ pugixml vs2013\x64_Release\ vs2013\x64_Release\ pugixml Disabled _DEBUG;%(PreprocessorDefinitions) false EnableFastChecks MultiThreadedDebugDLL true Level3 OldStyle _DEBUG;%(PreprocessorDefinitions) $(OutDir)pugixml.lib Windows true $(OutDir)pugixml.pdb Disabled _DEBUG;%(PreprocessorDefinitions) false EnableFastChecks MultiThreadedDebugDLL true Level3 OldStyle _DEBUG;%(PreprocessorDefinitions) $(OutDir)pugixml.lib Windows true $(OutDir)pugixml.pdb Full NDEBUG;%(PreprocessorDefinitions) false true MultiThreadedDLL true Level3 OldStyle NDEBUG;%(PreprocessorDefinitions) $(OutDir)pugixml.lib Windows true true true $(OutDir)pugixml.pdb Full NDEBUG;%(PreprocessorDefinitions) false true MultiThreadedDLL true Level3 OldStyle NDEBUG;%(PreprocessorDefinitions) $(OutDir)pugixml.lib Windows true true true $(OutDir)pugixml.pdb ================================================ FILE: external/pugixml/scripts/pugixml_vs2013_static.vcxproj ================================================  Debug Win32 Debug x64 Release Win32 Release x64 {89A1E353-E2DC-495C-B403-742BE206ACED} pugixml Win32Proj StaticLibrary MultiByte true v120 StaticLibrary MultiByte true v120 StaticLibrary MultiByte true false v120 StaticLibrary MultiByte true false v120 <_ProjectFileVersion>10.0.30319.1 vs2013\Win32_DebugStatic\ vs2013\Win32_DebugStatic\ pugixml vs2013\x64_DebugStatic\ vs2013\x64_DebugStatic\ pugixml vs2013\Win32_ReleaseStatic\ vs2013\Win32_ReleaseStatic\ pugixml vs2013\x64_ReleaseStatic\ vs2013\x64_ReleaseStatic\ pugixml Disabled _DEBUG;%(PreprocessorDefinitions) false EnableFastChecks MultiThreadedDebug true Level3 OldStyle _DEBUG;%(PreprocessorDefinitions) $(OutDir)pugixml.lib Windows true $(OutDir)pugixml.pdb Disabled _DEBUG;%(PreprocessorDefinitions) false EnableFastChecks MultiThreadedDebug true Level3 OldStyle _DEBUG;%(PreprocessorDefinitions) $(OutDir)pugixml.lib Windows true $(OutDir)pugixml.pdb Full NDEBUG;%(PreprocessorDefinitions) false true MultiThreaded true Level3 OldStyle NDEBUG;%(PreprocessorDefinitions) $(OutDir)pugixml.lib Windows true true true $(OutDir)pugixml.pdb Full NDEBUG;%(PreprocessorDefinitions) false true MultiThreaded true Level3 OldStyle NDEBUG;%(PreprocessorDefinitions) $(OutDir)pugixml.lib Windows true true true $(OutDir)pugixml.pdb ================================================ FILE: external/pugixml/scripts/pugixml_vs2015.vcxproj ================================================  Debug Win32 Release Win32 Debug x64 Release x64 {07CF01C0-B887-499D-AD9C-799CB6A9FE64} Win32Proj pugixml 8.1 StaticLibrary true v140 Unicode StaticLibrary false v140 true Unicode StaticLibrary true v140 Unicode StaticLibrary false v140 true Unicode vs2015\$(Platform)_$(Configuration)\ vs2015\$(Platform)_$(Configuration)\ pugixml vs2015\$(Platform)_$(Configuration)\ vs2015\$(Platform)_$(Configuration)\ pugixml vs2015\$(Platform)_$(Configuration)\ vs2015\$(Platform)_$(Configuration)\ pugixml vs2015\$(Platform)_$(Configuration)\ vs2015\$(Platform)_$(Configuration)\ pugixml Level3 Disabled WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) $(IntDir)$(TargetName).pdb OldStyle false Windows true Level3 Disabled _DEBUG;_LIB;%(PreprocessorDefinitions) $(IntDir)$(TargetName).pdb OldStyle false Windows true Level3 MaxSpeed true true WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) $(IntDir)$(TargetName).pdb OldStyle Windows true true true Level3 MaxSpeed true true NDEBUG;_LIB;%(PreprocessorDefinitions) $(IntDir)$(TargetName).pdb OldStyle Windows true true true ================================================ FILE: external/pugixml/scripts/pugixml_vs2015_static.vcxproj ================================================  Debug Win32 Release Win32 Debug x64 Release x64 {07CF01C0-B887-499D-AD9C-799CB6A9FE64} Win32Proj pugixml 8.1 StaticLibrary true v140 Unicode StaticLibrary false v140 true Unicode StaticLibrary true v140 Unicode StaticLibrary false v140 true Unicode vs2015\$(Platform)_$(Configuration)Static\ vs2015\$(Platform)_$(Configuration)Static\ pugixml vs2015\$(Platform)_$(Configuration)Static\ vs2015\$(Platform)_$(Configuration)Static\ pugixml vs2015\$(Platform)_$(Configuration)Static\ vs2015\$(Platform)_$(Configuration)Static\ pugixml vs2015\$(Platform)_$(Configuration)Static\ vs2015\$(Platform)_$(Configuration)Static\ pugixml Level3 Disabled WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) $(IntDir)$(TargetName).pdb OldStyle false MultiThreadedDebug Windows true Level3 Disabled _DEBUG;_LIB;%(PreprocessorDefinitions) $(IntDir)$(TargetName).pdb OldStyle false MultiThreadedDebug Windows true Level3 MaxSpeed true true WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) $(IntDir)$(TargetName).pdb OldStyle MultiThreaded Windows true true true Level3 MaxSpeed true true NDEBUG;_LIB;%(PreprocessorDefinitions) $(IntDir)$(TargetName).pdb OldStyle MultiThreaded Windows true true true ================================================ FILE: external/pugixml/scripts/pugixml_vs2017.vcxproj ================================================  Debug Win32 Release Win32 Debug x64 Release x64 {07CF01C0-B887-499D-AD9C-799CB6A9FE64} Win32Proj pugixml 8.1 StaticLibrary true v141 Unicode StaticLibrary false v141 false Unicode StaticLibrary true v141 Unicode StaticLibrary false v141 false Unicode vs2017\$(Platform)_$(Configuration)\ vs2017\$(Platform)_$(Configuration)\ pugixml vs2017\$(Platform)_$(Configuration)\ vs2017\$(Platform)_$(Configuration)\ pugixml vs2017\$(Platform)_$(Configuration)\ vs2017\$(Platform)_$(Configuration)\ pugixml vs2017\$(Platform)_$(Configuration)\ vs2017\$(Platform)_$(Configuration)\ pugixml Level3 Disabled WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) $(IntDir)$(TargetName).pdb OldStyle false Windows true Level3 Disabled _DEBUG;_LIB;%(PreprocessorDefinitions) $(IntDir)$(TargetName).pdb OldStyle false Windows true Level3 MaxSpeed true true WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) $(IntDir)$(TargetName).pdb OldStyle Windows true true true Level3 MaxSpeed true true NDEBUG;_LIB;%(PreprocessorDefinitions) $(IntDir)$(TargetName).pdb OldStyle Windows true true true ================================================ FILE: external/pugixml/scripts/pugixml_vs2017_static.vcxproj ================================================  Debug Win32 Release Win32 Debug x64 Release x64 {07CF01C0-B887-499D-AD9C-799CB6A9FE64} Win32Proj pugixml 8.1 StaticLibrary true v141 Unicode StaticLibrary false v141 false Unicode StaticLibrary true v141 Unicode StaticLibrary false v141 false Unicode vs2017\$(Platform)_$(Configuration)Static\ vs2017\$(Platform)_$(Configuration)Static\ pugixml vs2017\$(Platform)_$(Configuration)Static\ vs2017\$(Platform)_$(Configuration)Static\ pugixml vs2017\$(Platform)_$(Configuration)Static\ vs2017\$(Platform)_$(Configuration)Static\ pugixml vs2017\$(Platform)_$(Configuration)Static\ vs2017\$(Platform)_$(Configuration)Static\ pugixml Level3 Disabled WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) $(IntDir)$(TargetName).pdb OldStyle false MultiThreadedDebug Windows true Level3 Disabled _DEBUG;_LIB;%(PreprocessorDefinitions) $(IntDir)$(TargetName).pdb OldStyle false MultiThreadedDebug Windows true Level3 MaxSpeed true true WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) $(IntDir)$(TargetName).pdb OldStyle MultiThreaded Windows true true true Level3 MaxSpeed true true NDEBUG;_LIB;%(PreprocessorDefinitions) $(IntDir)$(TargetName).pdb OldStyle MultiThreaded Windows true true true ================================================ FILE: external/pugixml/scripts/pugixml_vs2019.vcxproj ================================================  Debug Win32 Release Win32 Debug x64 Release x64 {07CF01C0-B887-499D-AD9C-799CB6A9FE64} Win32Proj pugixml 10.0 StaticLibrary true v142 Unicode StaticLibrary false v142 false Unicode StaticLibrary true v142 Unicode StaticLibrary false v142 false Unicode vs2019\$(Platform)_$(Configuration)\ vs2019\$(Platform)_$(Configuration)\ pugixml vs2019\$(Platform)_$(Configuration)\ vs2019\$(Platform)_$(Configuration)\ pugixml vs2019\$(Platform)_$(Configuration)\ vs2019\$(Platform)_$(Configuration)\ pugixml vs2019\$(Platform)_$(Configuration)\ vs2019\$(Platform)_$(Configuration)\ pugixml Level3 Disabled WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) $(IntDir)$(TargetName).pdb OldStyle false stdcpp17 Windows true Level3 Disabled _DEBUG;_LIB;%(PreprocessorDefinitions) $(IntDir)$(TargetName).pdb OldStyle false stdcpp17 Windows true Level3 MaxSpeed true true WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) $(IntDir)$(TargetName).pdb OldStyle stdcpp17 Windows true true true Level3 MaxSpeed true true NDEBUG;_LIB;%(PreprocessorDefinitions) $(IntDir)$(TargetName).pdb OldStyle stdcpp17 Windows true true true ================================================ FILE: external/pugixml/scripts/pugixml_vs2019_static.vcxproj ================================================  Debug Win32 Release Win32 Debug x64 Release x64 {07CF01C0-B887-499D-AD9C-799CB6A9FE64} Win32Proj pugixml 10.0 StaticLibrary true v142 Unicode StaticLibrary false v142 false Unicode StaticLibrary true v142 Unicode StaticLibrary false v142 false Unicode vs2019\$(Platform)_$(Configuration)Static\ vs2019\$(Platform)_$(Configuration)Static\ pugixml vs2019\$(Platform)_$(Configuration)Static\ vs2019\$(Platform)_$(Configuration)Static\ pugixml vs2019\$(Platform)_$(Configuration)Static\ vs2019\$(Platform)_$(Configuration)Static\ pugixml vs2019\$(Platform)_$(Configuration)Static\ vs2019\$(Platform)_$(Configuration)Static\ pugixml Level3 Disabled WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) $(IntDir)$(TargetName).pdb OldStyle false MultiThreadedDebug stdcpp17 Windows true Level3 Disabled _DEBUG;_LIB;%(PreprocessorDefinitions) $(IntDir)$(TargetName).pdb OldStyle false MultiThreadedDebug stdcpp17 Windows true Level3 MaxSpeed true true WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) $(IntDir)$(TargetName).pdb OldStyle MultiThreaded stdcpp17 Windows true true true Level3 MaxSpeed true true NDEBUG;_LIB;%(PreprocessorDefinitions) $(IntDir)$(TargetName).pdb OldStyle MultiThreaded stdcpp17 Windows true true true ================================================ FILE: external/pugixml/scripts/pugixml_vs2022.vcxproj ================================================  Debug Win32 Release Win32 Debug x64 Release x64 {07CF01C0-B887-499D-AD9C-799CB6A9FE64} Win32Proj pugixml 10.0 StaticLibrary true v143 Unicode StaticLibrary false v143 false Unicode StaticLibrary true v143 Unicode StaticLibrary false v143 false Unicode vs2022\$(Platform)_$(Configuration)\ vs2022\$(Platform)_$(Configuration)\ pugixml vs2022\$(Platform)_$(Configuration)\ vs2022\$(Platform)_$(Configuration)\ pugixml vs2022\$(Platform)_$(Configuration)\ vs2022\$(Platform)_$(Configuration)\ pugixml vs2022\$(Platform)_$(Configuration)\ vs2022\$(Platform)_$(Configuration)\ pugixml Level3 Disabled WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) $(IntDir)$(TargetName).pdb OldStyle false stdcpp17 Windows true Level3 Disabled _DEBUG;_LIB;%(PreprocessorDefinitions) $(IntDir)$(TargetName).pdb OldStyle false stdcpp17 Windows true Level3 MaxSpeed true true WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) $(IntDir)$(TargetName).pdb OldStyle stdcpp17 Windows true true true Level3 MaxSpeed true true NDEBUG;_LIB;%(PreprocessorDefinitions) $(IntDir)$(TargetName).pdb OldStyle stdcpp17 Windows true true true ================================================ FILE: external/pugixml/scripts/pugixml_vs2022_static.vcxproj ================================================  Debug Win32 Release Win32 Debug x64 Release x64 {07CF01C0-B887-499D-AD9C-799CB6A9FE64} Win32Proj pugixml 10.0 StaticLibrary true v143 Unicode StaticLibrary false v143 false Unicode StaticLibrary true v143 Unicode StaticLibrary false v143 false Unicode vs2022\$(Platform)_$(Configuration)Static\ vs2022\$(Platform)_$(Configuration)Static\ pugixml vs2022\$(Platform)_$(Configuration)Static\ vs2022\$(Platform)_$(Configuration)Static\ pugixml vs2022\$(Platform)_$(Configuration)Static\ vs2022\$(Platform)_$(Configuration)Static\ pugixml vs2022\$(Platform)_$(Configuration)Static\ vs2022\$(Platform)_$(Configuration)Static\ pugixml Level3 Disabled WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) $(IntDir)$(TargetName).pdb OldStyle false MultiThreadedDebug stdcpp17 Windows true Level3 Disabled _DEBUG;_LIB;%(PreprocessorDefinitions) $(IntDir)$(TargetName).pdb OldStyle false MultiThreadedDebug stdcpp17 Windows true Level3 MaxSpeed true true WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) $(IntDir)$(TargetName).pdb OldStyle MultiThreaded stdcpp17 Windows true true true Level3 MaxSpeed true true NDEBUG;_LIB;%(PreprocessorDefinitions) $(IntDir)$(TargetName).pdb OldStyle MultiThreaded stdcpp17 Windows true true true ================================================ FILE: external/pugixml/scripts/sbom.cdx.json ================================================ { "bomFormat": "CycloneDX", "specVersion": "1.6", "version": 1, "metadata": { "authors": [ { "name": "@VCS_SBOM_AUTHORS@" } ] }, "components": [ { "type": "library", "bom-ref": "pkg:github/zeux/pugixml@@VCS_TAG@", "cpe": "cpe:2.3:a:pugixml_project:pugixml:@VCS_TAG@:*:*:*:*:*:*:*", "name": "pugixml", "version": "@VCS_VERSION@", "description": "C++ XML processing library", "supplier": { "name": "pugixml developers" }, "authors": [ { "name": "@VCS_AUTHORS@" } ], "licenses": [ { "license": { "id": "MIT" } } ], "externalReferences": [ { "type": "website", "url": "https://pugixml.org/" }, { "type": "vcs", "url": "https://github.com/zeux/pugixml" } ] } ] } ================================================ FILE: external/pugixml/src/pugiconfig.hpp ================================================ /** * pugixml parser - version 1.15 * -------------------------------------------------------- * Copyright (C) 2006-2025, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) * Report bugs and download new versions at https://pugixml.org/ * * This library is distributed under the MIT License. See notice at the end * of this file. * * This work is based on the pugxml parser, which is: * Copyright (C) 2003, by Kristen Wegner (kristen@tima.net) */ #ifndef HEADER_PUGICONFIG_HPP #define HEADER_PUGICONFIG_HPP // Uncomment this to enable wchar_t mode // #define PUGIXML_WCHAR_MODE // Uncomment this to enable compact mode // #define PUGIXML_COMPACT // Uncomment this to disable XPath // #define PUGIXML_NO_XPATH // Uncomment this to disable STL // #define PUGIXML_NO_STL // Uncomment this to disable exceptions // #define PUGIXML_NO_EXCEPTIONS // Set this to control attributes for public classes/functions, i.e.: // #define PUGIXML_API __declspec(dllexport) // to export all public symbols from DLL // #define PUGIXML_CLASS __declspec(dllimport) // to import all classes from DLL // #define PUGIXML_FUNCTION __fastcall // to set calling conventions to all public functions to fastcall // In absence of PUGIXML_CLASS/PUGIXML_FUNCTION definitions PUGIXML_API is used instead // Tune these constants to adjust memory-related behavior // #define PUGIXML_MEMORY_PAGE_SIZE 32768 // #define PUGIXML_MEMORY_OUTPUT_STACK 10240 // #define PUGIXML_MEMORY_XPATH_PAGE_SIZE 4096 // Tune this constant to adjust max nesting for XPath queries // #define PUGIXML_XPATH_DEPTH_LIMIT 1024 // Uncomment this to switch to header-only version // #define PUGIXML_HEADER_ONLY // Uncomment this to enable long long support (usually enabled automatically) // #define PUGIXML_HAS_LONG_LONG // Uncomment this to enable support for std::string_view (usually enabled automatically) // #define PUGIXML_HAS_STRING_VIEW #endif /** * Copyright (c) 2006-2025 Arseny Kapoulkine * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ ================================================ FILE: external/pugixml/src/pugixml.cpp ================================================ /** * pugixml parser - version 1.15 * -------------------------------------------------------- * Copyright (C) 2006-2025, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) * Report bugs and download new versions at https://pugixml.org/ * * This library is distributed under the MIT License. See notice at the end * of this file. * * This work is based on the pugxml parser, which is: * Copyright (C) 2003, by Kristen Wegner (kristen@tima.net) */ #ifndef SOURCE_PUGIXML_CPP #define SOURCE_PUGIXML_CPP #include "pugixml.hpp" #include #include #include #include #include #ifdef PUGIXML_WCHAR_MODE # include #endif #ifndef PUGIXML_NO_XPATH # include # include #endif #ifndef PUGIXML_NO_STL # include # include # include #endif // For placement new #include // For load_file #if defined(__linux__) || defined(__APPLE__) #include #endif #ifdef _MSC_VER # pragma warning(push) # pragma warning(disable: 4127) // conditional expression is constant # pragma warning(disable: 4324) // structure was padded due to __declspec(align()) # pragma warning(disable: 4702) // unreachable code # pragma warning(disable: 4996) // this function or variable may be unsafe #endif #if defined(__clang__) # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // NULL as null pointer constant #endif #if defined(_MSC_VER) && defined(__c2__) # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wdeprecated" // this function or variable may be unsafe #endif #ifdef __INTEL_COMPILER # pragma warning(disable: 177) // function was declared but never referenced # pragma warning(disable: 279) // controlling expression is constant # pragma warning(disable: 1478 1786) // function was declared "deprecated" # pragma warning(disable: 1684) // conversion from pointer to same-sized integral type #endif #if defined(__BORLANDC__) && defined(PUGIXML_HEADER_ONLY) # pragma warn -8080 // symbol is declared but never used; disabling this inside push/pop bracket does not make the warning go away #endif #ifdef __BORLANDC__ # pragma option push # pragma warn -8008 // condition is always false # pragma warn -8066 // unreachable code #endif #ifdef __SNC__ // Using diag_push/diag_pop does not disable the warnings inside templates due to a compiler bug # pragma diag_suppress=178 // function was declared but never referenced # pragma diag_suppress=237 // controlling expression is constant #endif #ifdef __TI_COMPILER_VERSION__ # pragma diag_suppress 179 // function was declared but never referenced #endif // Inlining controls #if defined(_MSC_VER) && _MSC_VER >= 1300 # define PUGI_IMPL_NO_INLINE __declspec(noinline) #elif defined(__GNUC__) # define PUGI_IMPL_NO_INLINE __attribute__((noinline)) #else # define PUGI_IMPL_NO_INLINE #endif // Branch weight controls #if defined(__GNUC__) && !defined(__c2__) # define PUGI_IMPL_UNLIKELY(cond) __builtin_expect(cond, 0) #else # define PUGI_IMPL_UNLIKELY(cond) (cond) #endif // Simple static assertion #define PUGI_IMPL_STATIC_ASSERT(cond) { static const char condition_failed[(cond) ? 1 : -1] = {0}; (void)condition_failed[0]; } // Digital Mars C++ bug workaround for passing char loaded from memory via stack #ifdef __DMC__ # define PUGI_IMPL_DMC_VOLATILE volatile #else # define PUGI_IMPL_DMC_VOLATILE #endif // Integer sanitizer workaround; we only apply this for clang since gcc8 has no_sanitize but not unsigned-integer-overflow and produces "attribute directive ignored" warnings #if defined(__clang__) && defined(__has_attribute) # if __has_attribute(no_sanitize) # define PUGI_IMPL_UNSIGNED_OVERFLOW __attribute__((no_sanitize("unsigned-integer-overflow"))) # else # define PUGI_IMPL_UNSIGNED_OVERFLOW # endif #else # define PUGI_IMPL_UNSIGNED_OVERFLOW #endif // Borland C++ bug workaround for not defining ::memcpy depending on header include order (can't always use std::memcpy because some compilers don't have it at all) #if defined(__BORLANDC__) && !defined(__MEM_H_USING_LIST) using std::memcpy; using std::memmove; using std::memset; #endif // Old versions of GCC do not define ::malloc and ::free depending on header include order #if defined(__GNUC__) && (__GNUC__ < 3 || (__GNUC__ == 3 && __GNUC_MINOR__ < 4)) using std::malloc; using std::free; #endif // Some MinGW/GCC versions have headers that erroneously omit LLONG_MIN/LLONG_MAX/ULLONG_MAX definitions from limits.h in some configurations #if defined(PUGIXML_HAS_LONG_LONG) && defined(__GNUC__) && !defined(LLONG_MAX) && !defined(LLONG_MIN) && !defined(ULLONG_MAX) # define LLONG_MIN (-LLONG_MAX - 1LL) # define LLONG_MAX __LONG_LONG_MAX__ # define ULLONG_MAX (LLONG_MAX * 2ULL + 1ULL) #endif // In some environments MSVC is a compiler but the CRT lacks certain MSVC-specific features #if defined(_MSC_VER) && !defined(__S3E__) && !defined(_WIN32_WCE) # define PUGI_IMPL_MSVC_CRT_VERSION _MSC_VER #elif defined(_WIN32_WCE) # define PUGI_IMPL_MSVC_CRT_VERSION 1310 // MSVC7.1 #endif // Not all platforms have snprintf; we define a wrapper that uses snprintf if possible. This only works with buffers with a known size. #if __cplusplus >= 201103 # define PUGI_IMPL_SNPRINTF(buf, ...) snprintf(buf, sizeof(buf), __VA_ARGS__) #elif defined(PUGI_IMPL_MSVC_CRT_VERSION) && PUGI_IMPL_MSVC_CRT_VERSION >= 1400 # define PUGI_IMPL_SNPRINTF(buf, ...) _snprintf_s(buf, _countof(buf), _TRUNCATE, __VA_ARGS__) #elif defined(__APPLE__) && __clang_major__ >= 14 // Xcode 14 marks sprintf as deprecated while still using C++98 by default # define PUGI_IMPL_SNPRINTF(buf, fmt, arg1, arg2) snprintf(buf, sizeof(buf), fmt, arg1, arg2) #else # define PUGI_IMPL_SNPRINTF sprintf #endif // We put implementation details into an anonymous namespace in source mode, but have to keep it in non-anonymous namespace in header-only mode to prevent binary bloat. #ifdef PUGIXML_HEADER_ONLY # define PUGI_IMPL_NS_BEGIN namespace pugi { namespace impl { # define PUGI_IMPL_NS_END } } # define PUGI_IMPL_FN inline # define PUGI_IMPL_FN_NO_INLINE inline #else # if defined(_MSC_VER) && _MSC_VER < 1300 // MSVC6 seems to have an amusing bug with anonymous namespaces inside namespaces # define PUGI_IMPL_NS_BEGIN namespace pugi { namespace impl { # define PUGI_IMPL_NS_END } } # else # define PUGI_IMPL_NS_BEGIN namespace pugi { namespace impl { namespace { # define PUGI_IMPL_NS_END } } } # endif # define PUGI_IMPL_FN # define PUGI_IMPL_FN_NO_INLINE PUGI_IMPL_NO_INLINE #endif // uintptr_t #if (defined(_MSC_VER) && _MSC_VER < 1600) || (defined(__BORLANDC__) && __BORLANDC__ < 0x561) namespace pugi { # ifndef _UINTPTR_T_DEFINED typedef size_t uintptr_t; # endif typedef unsigned __int8 uint8_t; typedef unsigned __int16 uint16_t; typedef unsigned __int32 uint32_t; } #else # include #endif // Memory allocation PUGI_IMPL_NS_BEGIN PUGI_IMPL_FN void* default_allocate(size_t size) { return malloc(size); } PUGI_IMPL_FN void default_deallocate(void* ptr) { free(ptr); } template struct xml_memory_management_function_storage { static allocation_function allocate; static deallocation_function deallocate; }; // Global allocation functions are stored in class statics so that in header mode linker deduplicates them // Without a template<> we'll get multiple definitions of the same static template allocation_function xml_memory_management_function_storage::allocate = default_allocate; template deallocation_function xml_memory_management_function_storage::deallocate = default_deallocate; typedef xml_memory_management_function_storage xml_memory; PUGI_IMPL_NS_END // String utilities PUGI_IMPL_NS_BEGIN // Get string length PUGI_IMPL_FN size_t strlength(const char_t* s) { assert(s); #ifdef PUGIXML_WCHAR_MODE return wcslen(s); #else return strlen(s); #endif } // Compare two strings PUGI_IMPL_FN bool strequal(const char_t* src, const char_t* dst) { assert(src && dst); #ifdef PUGIXML_WCHAR_MODE return wcscmp(src, dst) == 0; #else return strcmp(src, dst) == 0; #endif } #ifdef PUGIXML_HAS_STRING_VIEW // Check if the null-terminated dst string is equal to the entire contents of srcview PUGI_IMPL_FN bool stringview_equal(string_view_t srcview, const char_t* dst) { // std::basic_string_view::compare(const char*) has the right behavior, but it performs an // extra traversal of dst to compute its length. assert(dst); const char_t* src = srcview.data(); size_t srclen = srcview.size(); while (srclen && *dst && *src == *dst) { --srclen; ++dst; ++src; } return srclen == 0 && *dst == 0; } #endif // Compare lhs with [rhs_begin, rhs_end) PUGI_IMPL_FN bool strequalrange(const char_t* lhs, const char_t* rhs, size_t count) { for (size_t i = 0; i < count; ++i) if (lhs[i] != rhs[i]) return false; return lhs[count] == 0; } // Get length of wide string, even if CRT lacks wide character support PUGI_IMPL_FN size_t strlength_wide(const wchar_t* s) { assert(s); #ifdef PUGIXML_WCHAR_MODE return wcslen(s); #else const wchar_t* end = s; while (*end) end++; return static_cast(end - s); #endif } PUGI_IMPL_NS_END // auto_ptr-like object for exception recovery PUGI_IMPL_NS_BEGIN template struct auto_deleter { typedef void (*D)(T*); T* data; D deleter; auto_deleter(T* data_, D deleter_): data(data_), deleter(deleter_) { } ~auto_deleter() { if (data) deleter(data); } T* release() { T* result = data; data = NULL; return result; } }; PUGI_IMPL_NS_END #ifdef PUGIXML_COMPACT PUGI_IMPL_NS_BEGIN class compact_hash_table { public: compact_hash_table(): _items(NULL), _capacity(0), _count(0) { } void clear() { if (_items) { xml_memory::deallocate(_items); _items = NULL; _capacity = 0; _count = 0; } } void* find(const void* key) { if (_capacity == 0) return NULL; item_t* item = get_item(key); assert(item); assert(item->key == key || (item->key == NULL && item->value == NULL)); return item->value; } void insert(const void* key, void* value) { assert(_capacity != 0 && _count < _capacity - _capacity / 4); item_t* item = get_item(key); assert(item); if (item->key == NULL) { _count++; item->key = key; } item->value = value; } bool reserve(size_t extra = 16) { if (_count + extra >= _capacity - _capacity / 4) return rehash(_count + extra); return true; } private: struct item_t { const void* key; void* value; }; item_t* _items; size_t _capacity; size_t _count; bool rehash(size_t count); item_t* get_item(const void* key) { assert(key); assert(_capacity > 0); size_t hashmod = _capacity - 1; size_t bucket = hash(key) & hashmod; for (size_t probe = 0; probe <= hashmod; ++probe) { item_t& probe_item = _items[bucket]; if (probe_item.key == key || probe_item.key == NULL) return &probe_item; // hash collision, quadratic probing bucket = (bucket + probe + 1) & hashmod; } assert(false && "Hash table is full"); // unreachable return NULL; } static PUGI_IMPL_UNSIGNED_OVERFLOW unsigned int hash(const void* key) { unsigned int h = static_cast(reinterpret_cast(key) & 0xffffffff); // MurmurHash3 32-bit finalizer h ^= h >> 16; h *= 0x85ebca6bu; h ^= h >> 13; h *= 0xc2b2ae35u; h ^= h >> 16; return h; } }; PUGI_IMPL_FN_NO_INLINE bool compact_hash_table::rehash(size_t count) { size_t capacity = 32; while (count >= capacity - capacity / 4) capacity *= 2; compact_hash_table rt; rt._capacity = capacity; rt._items = static_cast(xml_memory::allocate(sizeof(item_t) * capacity)); if (!rt._items) return false; memset(rt._items, 0, sizeof(item_t) * capacity); for (size_t i = 0; i < _capacity; ++i) if (_items[i].key) rt.insert(_items[i].key, _items[i].value); if (_items) xml_memory::deallocate(_items); _capacity = capacity; _items = rt._items; assert(_count == rt._count); return true; } PUGI_IMPL_NS_END #endif PUGI_IMPL_NS_BEGIN #ifdef PUGIXML_COMPACT static const uintptr_t xml_memory_block_alignment = 4; #else static const uintptr_t xml_memory_block_alignment = sizeof(void*); #endif // extra metadata bits static const uintptr_t xml_memory_page_contents_shared_mask = 64; static const uintptr_t xml_memory_page_name_allocated_mask = 32; static const uintptr_t xml_memory_page_value_allocated_mask = 16; static const uintptr_t xml_memory_page_type_mask = 15; // combined masks for string uniqueness static const uintptr_t xml_memory_page_name_allocated_or_shared_mask = xml_memory_page_name_allocated_mask | xml_memory_page_contents_shared_mask; static const uintptr_t xml_memory_page_value_allocated_or_shared_mask = xml_memory_page_value_allocated_mask | xml_memory_page_contents_shared_mask; #ifdef PUGIXML_COMPACT #define PUGI_IMPL_GETHEADER_IMPL(object, page, flags) // unused #define PUGI_IMPL_GETPAGE_IMPL(header) (header).get_page() #else #define PUGI_IMPL_GETHEADER_IMPL(object, page, flags) (((reinterpret_cast(object) - reinterpret_cast(page)) << 8) | (flags)) // this macro casts pointers through void* to avoid 'cast increases required alignment of target type' warnings #define PUGI_IMPL_GETPAGE_IMPL(header) static_cast(const_cast(static_cast(reinterpret_cast(&header) - (header >> 8)))) #endif #define PUGI_IMPL_GETPAGE(n) PUGI_IMPL_GETPAGE_IMPL((n)->header) #define PUGI_IMPL_NODETYPE(n) static_cast((n)->header & impl::xml_memory_page_type_mask) struct xml_allocator; struct xml_memory_page { static xml_memory_page* construct(void* memory) { xml_memory_page* result = static_cast(memory); result->allocator = NULL; result->prev = NULL; result->next = NULL; result->busy_size = 0; result->freed_size = 0; #ifdef PUGIXML_COMPACT result->compact_string_base = NULL; result->compact_shared_parent = NULL; result->compact_page_marker = NULL; #endif return result; } xml_allocator* allocator; xml_memory_page* prev; xml_memory_page* next; size_t busy_size; size_t freed_size; #ifdef PUGIXML_COMPACT char_t* compact_string_base; void* compact_shared_parent; uint32_t* compact_page_marker; #endif }; static const size_t xml_memory_page_size = #ifdef PUGIXML_MEMORY_PAGE_SIZE (PUGIXML_MEMORY_PAGE_SIZE) #else 32768 #endif - sizeof(xml_memory_page); struct xml_memory_string_header { uint16_t page_offset; // offset from page->data uint16_t full_size; // 0 if string occupies whole page }; struct xml_allocator { xml_allocator(xml_memory_page* root): _root(root), _busy_size(root->busy_size) { #ifdef PUGIXML_COMPACT _hash = NULL; #endif } xml_memory_page* allocate_page(size_t data_size) { size_t size = sizeof(xml_memory_page) + data_size; // allocate block with some alignment, leaving memory for worst-case padding void* memory = xml_memory::allocate(size); if (!memory) return NULL; // prepare page structure xml_memory_page* page = xml_memory_page::construct(memory); assert(page); assert(this == _root->allocator); page->allocator = this; return page; } static void deallocate_page(xml_memory_page* page) { xml_memory::deallocate(page); } void* allocate_memory_oob(size_t size, xml_memory_page*& out_page); void* allocate_memory(size_t size, xml_memory_page*& out_page) { if (PUGI_IMPL_UNLIKELY(_busy_size + size > xml_memory_page_size)) return allocate_memory_oob(size, out_page); void* buf = reinterpret_cast(_root) + sizeof(xml_memory_page) + _busy_size; _busy_size += size; out_page = _root; return buf; } #ifdef PUGIXML_COMPACT void* allocate_object(size_t size, xml_memory_page*& out_page) { void* result = allocate_memory(size + sizeof(uint32_t), out_page); if (!result) return NULL; // adjust for marker ptrdiff_t offset = static_cast(result) - reinterpret_cast(out_page->compact_page_marker); if (PUGI_IMPL_UNLIKELY(static_cast(offset) >= 256 * xml_memory_block_alignment)) { // insert new marker uint32_t* marker = static_cast(result); *marker = static_cast(reinterpret_cast(marker) - reinterpret_cast(out_page)); out_page->compact_page_marker = marker; // since we don't reuse the page space until we reallocate it, we can just pretend that we freed the marker block // this will make sure deallocate_memory correctly tracks the size out_page->freed_size += sizeof(uint32_t); return marker + 1; } else { // roll back uint32_t part _busy_size -= sizeof(uint32_t); return result; } } #else void* allocate_object(size_t size, xml_memory_page*& out_page) { return allocate_memory(size, out_page); } #endif void deallocate_memory(void* ptr, size_t size, xml_memory_page* page) { if (page == _root) page->busy_size = _busy_size; assert(ptr >= reinterpret_cast(page) + sizeof(xml_memory_page) && ptr < reinterpret_cast(page) + sizeof(xml_memory_page) + page->busy_size); (void)!ptr; page->freed_size += size; assert(page->freed_size <= page->busy_size); if (page->freed_size == page->busy_size) { if (page->next == NULL) { assert(_root == page); // top page freed, just reset sizes page->busy_size = 0; page->freed_size = 0; #ifdef PUGIXML_COMPACT // reset compact state to maximize efficiency page->compact_string_base = NULL; page->compact_shared_parent = NULL; page->compact_page_marker = NULL; #endif _busy_size = 0; } else { assert(_root != page); assert(page->prev); // remove from the list page->prev->next = page->next; page->next->prev = page->prev; // deallocate deallocate_page(page); } } } char_t* allocate_string(size_t length) { static const size_t max_encoded_offset = (1 << 16) * xml_memory_block_alignment; PUGI_IMPL_STATIC_ASSERT(xml_memory_page_size <= max_encoded_offset); // allocate memory for string and header block size_t size = sizeof(xml_memory_string_header) + length * sizeof(char_t); // round size up to block alignment boundary size_t full_size = (size + (xml_memory_block_alignment - 1)) & ~(xml_memory_block_alignment - 1); xml_memory_page* page; xml_memory_string_header* header = static_cast(allocate_memory(full_size, page)); if (!header) return NULL; // setup header ptrdiff_t page_offset = reinterpret_cast(header) - reinterpret_cast(page) - sizeof(xml_memory_page); assert(page_offset % xml_memory_block_alignment == 0); assert(page_offset >= 0 && static_cast(page_offset) < max_encoded_offset); header->page_offset = static_cast(static_cast(page_offset) / xml_memory_block_alignment); // full_size == 0 for large strings that occupy the whole page assert(full_size % xml_memory_block_alignment == 0); assert(full_size < max_encoded_offset || (page->busy_size == full_size && page_offset == 0)); header->full_size = static_cast(full_size < max_encoded_offset ? full_size / xml_memory_block_alignment : 0); // round-trip through void* to avoid 'cast increases required alignment of target type' warning // header is guaranteed a pointer-sized alignment, which should be enough for char_t return static_cast(static_cast(header + 1)); } void deallocate_string(char_t* string) { // this function casts pointers through void* to avoid 'cast increases required alignment of target type' warnings // we're guaranteed the proper (pointer-sized) alignment on the input string if it was allocated via allocate_string // get header xml_memory_string_header* header = static_cast(static_cast(string)) - 1; assert(header); // deallocate size_t page_offset = sizeof(xml_memory_page) + header->page_offset * xml_memory_block_alignment; xml_memory_page* page = reinterpret_cast(static_cast(reinterpret_cast(header) - page_offset)); // if full_size == 0 then this string occupies the whole page size_t full_size = header->full_size == 0 ? page->busy_size : header->full_size * xml_memory_block_alignment; deallocate_memory(header, full_size, page); } bool reserve() { #ifdef PUGIXML_COMPACT return _hash->reserve(); #else return true; #endif } xml_memory_page* _root; size_t _busy_size; #ifdef PUGIXML_COMPACT compact_hash_table* _hash; #endif }; PUGI_IMPL_FN_NO_INLINE void* xml_allocator::allocate_memory_oob(size_t size, xml_memory_page*& out_page) { const size_t large_allocation_threshold = xml_memory_page_size / 4; xml_memory_page* page = allocate_page(size <= large_allocation_threshold ? xml_memory_page_size : size); out_page = page; if (!page) return NULL; if (size <= large_allocation_threshold) { _root->busy_size = _busy_size; // insert page at the end of linked list page->prev = _root; _root->next = page; _root = page; _busy_size = size; } else { // insert page before the end of linked list, so that it is deleted as soon as possible // the last page is not deleted even if it's empty (see deallocate_memory) assert(_root->prev); page->prev = _root->prev; page->next = _root; _root->prev->next = page; _root->prev = page; page->busy_size = size; } return reinterpret_cast(page) + sizeof(xml_memory_page); } PUGI_IMPL_NS_END #ifdef PUGIXML_COMPACT PUGI_IMPL_NS_BEGIN static const uintptr_t compact_alignment_log2 = 2; static const uintptr_t compact_alignment = 1 << compact_alignment_log2; class compact_header { public: compact_header(xml_memory_page* page, unsigned int flags) { PUGI_IMPL_STATIC_ASSERT(xml_memory_block_alignment == compact_alignment); ptrdiff_t offset = (reinterpret_cast(this) - reinterpret_cast(page->compact_page_marker)); assert(offset % compact_alignment == 0 && static_cast(offset) < 256 * compact_alignment); _page = static_cast(offset >> compact_alignment_log2); _flags = static_cast(flags); } void operator&=(uintptr_t mod) { _flags &= static_cast(mod); } void operator|=(uintptr_t mod) { _flags |= static_cast(mod); } uintptr_t operator&(uintptr_t mod) const { return _flags & mod; } xml_memory_page* get_page() const { // round-trip through void* to silence 'cast increases required alignment of target type' warnings const char* page_marker = reinterpret_cast(this) - (_page << compact_alignment_log2); const char* page = page_marker - *reinterpret_cast(static_cast(page_marker)); return const_cast(reinterpret_cast(static_cast(page))); } private: unsigned char _page; unsigned char _flags; }; PUGI_IMPL_FN xml_memory_page* compact_get_page(const void* object, int header_offset) { const compact_header* header = reinterpret_cast(static_cast(object) - header_offset); return header->get_page(); } template PUGI_IMPL_FN_NO_INLINE T* compact_get_value(const void* object) { return static_cast(compact_get_page(object, header_offset)->allocator->_hash->find(object)); } template PUGI_IMPL_FN_NO_INLINE void compact_set_value(const void* object, T* value) { compact_get_page(object, header_offset)->allocator->_hash->insert(object, value); } template class compact_pointer { public: compact_pointer(): _data(0) { } void operator=(const compact_pointer& rhs) { *this = rhs + 0; } void operator=(T* value) { if (value) { // value is guaranteed to be compact-aligned; 'this' is not // our decoding is based on 'this' aligned to compact alignment downwards (see operator T*) // so for negative offsets (e.g. -3) we need to adjust the diff by compact_alignment - 1 to // compensate for arithmetic shift rounding for negative values ptrdiff_t diff = reinterpret_cast(value) - reinterpret_cast(this); ptrdiff_t offset = ((diff + int(compact_alignment - 1)) >> compact_alignment_log2) - start; if (static_cast(offset) <= 253) _data = static_cast(offset + 1); else { compact_set_value(this, value); _data = 255; } } else _data = 0; } operator T*() const { if (_data) { if (_data < 255) { uintptr_t base = reinterpret_cast(this) & ~(compact_alignment - 1); return reinterpret_cast(base + (_data - 1 + start) * compact_alignment); } else return compact_get_value(this); } else return NULL; } T* operator->() const { return *this; } private: unsigned char _data; }; template class compact_pointer_parent { public: compact_pointer_parent(): _data(0) { } void operator=(const compact_pointer_parent& rhs) { *this = rhs + 0; } void operator=(T* value) { if (value) { // value is guaranteed to be compact-aligned; 'this' is not // our decoding is based on 'this' aligned to compact alignment downwards (see operator T*) // so for negative offsets (e.g. -3) we need to adjust the diff by compact_alignment - 1 to // compensate for arithmetic shift behavior for negative values ptrdiff_t diff = reinterpret_cast(value) - reinterpret_cast(this); ptrdiff_t offset = ((diff + int(compact_alignment - 1)) >> compact_alignment_log2) + 65533; if (static_cast(offset) <= 65533) { _data = static_cast(offset + 1); } else { xml_memory_page* page = compact_get_page(this, header_offset); if (PUGI_IMPL_UNLIKELY(page->compact_shared_parent == NULL)) page->compact_shared_parent = value; if (page->compact_shared_parent == value) { _data = 65534; } else { compact_set_value(this, value); _data = 65535; } } } else { _data = 0; } } operator T*() const { if (_data) { if (_data < 65534) { uintptr_t base = reinterpret_cast(this) & ~(compact_alignment - 1); return reinterpret_cast(base + (_data - 1 - 65533) * compact_alignment); } else if (_data == 65534) return static_cast(compact_get_page(this, header_offset)->compact_shared_parent); else return compact_get_value(this); } else return NULL; } T* operator->() const { return *this; } private: uint16_t _data; }; template class compact_string { public: compact_string(): _data(0) { } void operator=(const compact_string& rhs) { *this = rhs + 0; } void operator=(char_t* value) { if (value) { xml_memory_page* page = compact_get_page(this, header_offset); if (PUGI_IMPL_UNLIKELY(page->compact_string_base == NULL)) page->compact_string_base = value; ptrdiff_t offset = value - page->compact_string_base; if (static_cast(offset) < (65535 << 7)) { // round-trip through void* to silence 'cast increases required alignment of target type' warnings uint16_t* base = reinterpret_cast(static_cast(reinterpret_cast(this) - base_offset)); if (*base == 0) { *base = static_cast((offset >> 7) + 1); _data = static_cast((offset & 127) + 1); } else { ptrdiff_t remainder = offset - ((*base - 1) << 7); if (static_cast(remainder) <= 253) { _data = static_cast(remainder + 1); } else { compact_set_value(this, value); _data = 255; } } } else { compact_set_value(this, value); _data = 255; } } else { _data = 0; } } operator char_t*() const { if (_data) { if (_data < 255) { xml_memory_page* page = compact_get_page(this, header_offset); // round-trip through void* to silence 'cast increases required alignment of target type' warnings const uint16_t* base = reinterpret_cast(static_cast(reinterpret_cast(this) - base_offset)); assert(*base); ptrdiff_t offset = ((*base - 1) << 7) + (_data - 1); return page->compact_string_base + offset; } else { return compact_get_value(this); } } else return NULL; } private: unsigned char _data; }; PUGI_IMPL_NS_END #endif #ifdef PUGIXML_COMPACT namespace pugi { struct xml_attribute_struct { xml_attribute_struct(impl::xml_memory_page* page): header(page, 0), namevalue_base(0) { PUGI_IMPL_STATIC_ASSERT(sizeof(xml_attribute_struct) == 8); } impl::compact_header header; uint16_t namevalue_base; impl::compact_string<4, 2> name; impl::compact_string<5, 3> value; impl::compact_pointer prev_attribute_c; impl::compact_pointer next_attribute; }; struct xml_node_struct { xml_node_struct(impl::xml_memory_page* page, xml_node_type type): header(page, type), namevalue_base(0) { PUGI_IMPL_STATIC_ASSERT(sizeof(xml_node_struct) == 12); } impl::compact_header header; uint16_t namevalue_base; impl::compact_string<4, 2> name; impl::compact_string<5, 3> value; impl::compact_pointer_parent parent; impl::compact_pointer first_child; impl::compact_pointer prev_sibling_c; impl::compact_pointer next_sibling; impl::compact_pointer first_attribute; }; } #else namespace pugi { struct xml_attribute_struct { xml_attribute_struct(impl::xml_memory_page* page): name(NULL), value(NULL), prev_attribute_c(NULL), next_attribute(NULL) { header = PUGI_IMPL_GETHEADER_IMPL(this, page, 0); } uintptr_t header; char_t* name; char_t* value; xml_attribute_struct* prev_attribute_c; xml_attribute_struct* next_attribute; }; struct xml_node_struct { xml_node_struct(impl::xml_memory_page* page, xml_node_type type): name(NULL), value(NULL), parent(NULL), first_child(NULL), prev_sibling_c(NULL), next_sibling(NULL), first_attribute(NULL) { header = PUGI_IMPL_GETHEADER_IMPL(this, page, type); } uintptr_t header; char_t* name; char_t* value; xml_node_struct* parent; xml_node_struct* first_child; xml_node_struct* prev_sibling_c; xml_node_struct* next_sibling; xml_attribute_struct* first_attribute; }; } #endif PUGI_IMPL_NS_BEGIN struct xml_extra_buffer { char_t* buffer; xml_extra_buffer* next; }; struct xml_document_struct: public xml_node_struct, public xml_allocator { xml_document_struct(xml_memory_page* page): xml_node_struct(page, node_document), xml_allocator(page), buffer(NULL), extra_buffers(NULL) { } const char_t* buffer; xml_extra_buffer* extra_buffers; #ifdef PUGIXML_COMPACT compact_hash_table hash; #endif }; template inline xml_allocator& get_allocator(const Object* object) { assert(object); return *PUGI_IMPL_GETPAGE(object)->allocator; } template inline xml_document_struct& get_document(const Object* object) { assert(object); return *static_cast(PUGI_IMPL_GETPAGE(object)->allocator); } PUGI_IMPL_NS_END // Low-level DOM operations PUGI_IMPL_NS_BEGIN inline xml_attribute_struct* allocate_attribute(xml_allocator& alloc) { xml_memory_page* page; void* memory = alloc.allocate_object(sizeof(xml_attribute_struct), page); if (!memory) return NULL; return new (memory) xml_attribute_struct(page); } inline xml_node_struct* allocate_node(xml_allocator& alloc, xml_node_type type) { xml_memory_page* page; void* memory = alloc.allocate_object(sizeof(xml_node_struct), page); if (!memory) return NULL; return new (memory) xml_node_struct(page, type); } inline void destroy_attribute(xml_attribute_struct* a, xml_allocator& alloc) { if (a->header & impl::xml_memory_page_name_allocated_mask) alloc.deallocate_string(a->name); if (a->header & impl::xml_memory_page_value_allocated_mask) alloc.deallocate_string(a->value); alloc.deallocate_memory(a, sizeof(xml_attribute_struct), PUGI_IMPL_GETPAGE(a)); } inline void destroy_node(xml_node_struct* n, xml_allocator& alloc) { if (n->header & impl::xml_memory_page_name_allocated_mask) alloc.deallocate_string(n->name); if (n->header & impl::xml_memory_page_value_allocated_mask) alloc.deallocate_string(n->value); for (xml_attribute_struct* attr = n->first_attribute; attr; ) { xml_attribute_struct* next = attr->next_attribute; destroy_attribute(attr, alloc); attr = next; } for (xml_node_struct* child = n->first_child; child; ) { xml_node_struct* next = child->next_sibling; destroy_node(child, alloc); child = next; } alloc.deallocate_memory(n, sizeof(xml_node_struct), PUGI_IMPL_GETPAGE(n)); } inline void append_node(xml_node_struct* child, xml_node_struct* node) { child->parent = node; xml_node_struct* head = node->first_child; if (head) { xml_node_struct* tail = head->prev_sibling_c; tail->next_sibling = child; child->prev_sibling_c = tail; head->prev_sibling_c = child; } else { node->first_child = child; child->prev_sibling_c = child; } } inline void prepend_node(xml_node_struct* child, xml_node_struct* node) { child->parent = node; xml_node_struct* head = node->first_child; if (head) { child->prev_sibling_c = head->prev_sibling_c; head->prev_sibling_c = child; } else child->prev_sibling_c = child; child->next_sibling = head; node->first_child = child; } inline void insert_node_after(xml_node_struct* child, xml_node_struct* node) { xml_node_struct* parent = node->parent; child->parent = parent; xml_node_struct* next = node->next_sibling; if (next) next->prev_sibling_c = child; else parent->first_child->prev_sibling_c = child; child->next_sibling = next; child->prev_sibling_c = node; node->next_sibling = child; } inline void insert_node_before(xml_node_struct* child, xml_node_struct* node) { xml_node_struct* parent = node->parent; child->parent = parent; xml_node_struct* prev = node->prev_sibling_c; if (prev->next_sibling) prev->next_sibling = child; else parent->first_child = child; child->prev_sibling_c = prev; child->next_sibling = node; node->prev_sibling_c = child; } inline void remove_node(xml_node_struct* node) { xml_node_struct* parent = node->parent; xml_node_struct* next = node->next_sibling; xml_node_struct* prev = node->prev_sibling_c; if (next) next->prev_sibling_c = prev; else parent->first_child->prev_sibling_c = prev; if (prev->next_sibling) prev->next_sibling = next; else parent->first_child = next; node->parent = NULL; node->prev_sibling_c = NULL; node->next_sibling = NULL; } inline void append_attribute(xml_attribute_struct* attr, xml_node_struct* node) { xml_attribute_struct* head = node->first_attribute; if (head) { xml_attribute_struct* tail = head->prev_attribute_c; tail->next_attribute = attr; attr->prev_attribute_c = tail; head->prev_attribute_c = attr; } else { node->first_attribute = attr; attr->prev_attribute_c = attr; } } inline void prepend_attribute(xml_attribute_struct* attr, xml_node_struct* node) { xml_attribute_struct* head = node->first_attribute; if (head) { attr->prev_attribute_c = head->prev_attribute_c; head->prev_attribute_c = attr; } else attr->prev_attribute_c = attr; attr->next_attribute = head; node->first_attribute = attr; } inline void insert_attribute_after(xml_attribute_struct* attr, xml_attribute_struct* place, xml_node_struct* node) { xml_attribute_struct* next = place->next_attribute; if (next) next->prev_attribute_c = attr; else node->first_attribute->prev_attribute_c = attr; attr->next_attribute = next; attr->prev_attribute_c = place; place->next_attribute = attr; } inline void insert_attribute_before(xml_attribute_struct* attr, xml_attribute_struct* place, xml_node_struct* node) { xml_attribute_struct* prev = place->prev_attribute_c; if (prev->next_attribute) prev->next_attribute = attr; else node->first_attribute = attr; attr->prev_attribute_c = prev; attr->next_attribute = place; place->prev_attribute_c = attr; } inline void remove_attribute(xml_attribute_struct* attr, xml_node_struct* node) { xml_attribute_struct* next = attr->next_attribute; xml_attribute_struct* prev = attr->prev_attribute_c; if (next) next->prev_attribute_c = prev; else node->first_attribute->prev_attribute_c = prev; if (prev->next_attribute) prev->next_attribute = next; else node->first_attribute = next; attr->prev_attribute_c = NULL; attr->next_attribute = NULL; } PUGI_IMPL_FN_NO_INLINE xml_node_struct* append_new_node(xml_node_struct* node, xml_allocator& alloc, xml_node_type type = node_element) { if (!alloc.reserve()) return NULL; xml_node_struct* child = allocate_node(alloc, type); if (!child) return NULL; append_node(child, node); return child; } PUGI_IMPL_FN_NO_INLINE xml_attribute_struct* append_new_attribute(xml_node_struct* node, xml_allocator& alloc) { if (!alloc.reserve()) return NULL; xml_attribute_struct* attr = allocate_attribute(alloc); if (!attr) return NULL; append_attribute(attr, node); return attr; } PUGI_IMPL_NS_END // Helper classes for code generation PUGI_IMPL_NS_BEGIN struct opt_false { enum { value = 0 }; }; struct opt_true { enum { value = 1 }; }; PUGI_IMPL_NS_END // Unicode utilities PUGI_IMPL_NS_BEGIN inline uint16_t endian_swap(uint16_t value) { return static_cast(((value & 0xff) << 8) | (value >> 8)); } inline uint32_t endian_swap(uint32_t value) { return ((value & 0xff) << 24) | ((value & 0xff00) << 8) | ((value & 0xff0000) >> 8) | (value >> 24); } struct utf8_counter { typedef size_t value_type; static value_type low(value_type result, uint32_t ch) { // U+0000..U+007F if (ch < 0x80) return result + 1; // U+0080..U+07FF else if (ch < 0x800) return result + 2; // U+0800..U+FFFF else return result + 3; } static value_type high(value_type result, uint32_t) { // U+10000..U+10FFFF return result + 4; } }; struct utf8_writer { typedef uint8_t* value_type; static value_type low(value_type result, uint32_t ch) { // U+0000..U+007F if (ch < 0x80) { *result = static_cast(ch); return result + 1; } // U+0080..U+07FF else if (ch < 0x800) { result[0] = static_cast(0xC0 | (ch >> 6)); result[1] = static_cast(0x80 | (ch & 0x3F)); return result + 2; } // U+0800..U+FFFF else { result[0] = static_cast(0xE0 | (ch >> 12)); result[1] = static_cast(0x80 | ((ch >> 6) & 0x3F)); result[2] = static_cast(0x80 | (ch & 0x3F)); return result + 3; } } static value_type high(value_type result, uint32_t ch) { // U+10000..U+10FFFF result[0] = static_cast(0xF0 | (ch >> 18)); result[1] = static_cast(0x80 | ((ch >> 12) & 0x3F)); result[2] = static_cast(0x80 | ((ch >> 6) & 0x3F)); result[3] = static_cast(0x80 | (ch & 0x3F)); return result + 4; } static value_type any(value_type result, uint32_t ch) { return (ch < 0x10000) ? low(result, ch) : high(result, ch); } }; struct utf16_counter { typedef size_t value_type; static value_type low(value_type result, uint32_t) { return result + 1; } static value_type high(value_type result, uint32_t) { return result + 2; } }; struct utf16_writer { typedef uint16_t* value_type; static value_type low(value_type result, uint32_t ch) { *result = static_cast(ch); return result + 1; } static value_type high(value_type result, uint32_t ch) { uint32_t msh = (ch - 0x10000U) >> 10; uint32_t lsh = (ch - 0x10000U) & 0x3ff; result[0] = static_cast(0xD800 + msh); result[1] = static_cast(0xDC00 + lsh); return result + 2; } static value_type any(value_type result, uint32_t ch) { return (ch < 0x10000) ? low(result, ch) : high(result, ch); } }; struct utf32_counter { typedef size_t value_type; static value_type low(value_type result, uint32_t) { return result + 1; } static value_type high(value_type result, uint32_t) { return result + 1; } }; struct utf32_writer { typedef uint32_t* value_type; static value_type low(value_type result, uint32_t ch) { *result = ch; return result + 1; } static value_type high(value_type result, uint32_t ch) { *result = ch; return result + 1; } static value_type any(value_type result, uint32_t ch) { *result = ch; return result + 1; } }; struct latin1_writer { typedef uint8_t* value_type; static value_type low(value_type result, uint32_t ch) { *result = static_cast(ch > 255 ? '?' : ch); return result + 1; } static value_type high(value_type result, uint32_t ch) { (void)ch; *result = '?'; return result + 1; } }; struct utf8_decoder { typedef uint8_t type; template static inline typename Traits::value_type process(const uint8_t* data, size_t size, typename Traits::value_type result, Traits) { const uint8_t utf8_byte_mask = 0x3f; while (size) { uint8_t lead = *data; // 0xxxxxxx -> U+0000..U+007F if (lead < 0x80) { result = Traits::low(result, lead); data += 1; size -= 1; // process aligned single-byte (ascii) blocks if ((reinterpret_cast(data) & 3) == 0) { // round-trip through void* to silence 'cast increases required alignment of target type' warnings while (size >= 4 && (*static_cast(static_cast(data)) & 0x80808080) == 0) { result = Traits::low(result, data[0]); result = Traits::low(result, data[1]); result = Traits::low(result, data[2]); result = Traits::low(result, data[3]); data += 4; size -= 4; } } } // 110xxxxx -> U+0080..U+07FF else if (static_cast(lead - 0xC0) < 0x20 && size >= 2 && (data[1] & 0xc0) == 0x80) { result = Traits::low(result, ((lead & ~0xC0) << 6) | (data[1] & utf8_byte_mask)); data += 2; size -= 2; } // 1110xxxx -> U+0800-U+FFFF else if (static_cast(lead - 0xE0) < 0x10 && size >= 3 && (data[1] & 0xc0) == 0x80 && (data[2] & 0xc0) == 0x80) { result = Traits::low(result, ((lead & ~0xE0) << 12) | ((data[1] & utf8_byte_mask) << 6) | (data[2] & utf8_byte_mask)); data += 3; size -= 3; } // 11110xxx -> U+10000..U+10FFFF else if (static_cast(lead - 0xF0) < 0x08 && size >= 4 && (data[1] & 0xc0) == 0x80 && (data[2] & 0xc0) == 0x80 && (data[3] & 0xc0) == 0x80) { result = Traits::high(result, ((lead & ~0xF0) << 18) | ((data[1] & utf8_byte_mask) << 12) | ((data[2] & utf8_byte_mask) << 6) | (data[3] & utf8_byte_mask)); data += 4; size -= 4; } // 10xxxxxx or 11111xxx -> invalid else { data += 1; size -= 1; } } return result; } }; template struct utf16_decoder { typedef uint16_t type; template static inline typename Traits::value_type process(const uint16_t* data, size_t size, typename Traits::value_type result, Traits) { while (size) { uint16_t lead = opt_swap::value ? endian_swap(*data) : *data; // U+0000..U+D7FF if (lead < 0xD800) { result = Traits::low(result, lead); data += 1; size -= 1; } // U+E000..U+FFFF else if (static_cast(lead - 0xE000) < 0x2000) { result = Traits::low(result, lead); data += 1; size -= 1; } // surrogate pair lead else if (static_cast(lead - 0xD800) < 0x400 && size >= 2) { uint16_t next = opt_swap::value ? endian_swap(data[1]) : data[1]; if (static_cast(next - 0xDC00) < 0x400) { result = Traits::high(result, 0x10000 + ((lead & 0x3ff) << 10) + (next & 0x3ff)); data += 2; size -= 2; } else { data += 1; size -= 1; } } else { data += 1; size -= 1; } } return result; } }; template struct utf32_decoder { typedef uint32_t type; template static inline typename Traits::value_type process(const uint32_t* data, size_t size, typename Traits::value_type result, Traits) { while (size) { uint32_t lead = opt_swap::value ? endian_swap(*data) : *data; // U+0000..U+FFFF if (lead < 0x10000) { result = Traits::low(result, lead); data += 1; size -= 1; } // U+10000..U+10FFFF else { result = Traits::high(result, lead); data += 1; size -= 1; } } return result; } }; struct latin1_decoder { typedef uint8_t type; template static inline typename Traits::value_type process(const uint8_t* data, size_t size, typename Traits::value_type result, Traits) { while (size) { result = Traits::low(result, *data); data += 1; size -= 1; } return result; } }; template struct wchar_selector; template <> struct wchar_selector<2> { typedef uint16_t type; typedef utf16_counter counter; typedef utf16_writer writer; typedef utf16_decoder decoder; }; template <> struct wchar_selector<4> { typedef uint32_t type; typedef utf32_counter counter; typedef utf32_writer writer; typedef utf32_decoder decoder; }; typedef wchar_selector::counter wchar_counter; typedef wchar_selector::writer wchar_writer; struct wchar_decoder { typedef wchar_t type; template static inline typename Traits::value_type process(const wchar_t* data, size_t size, typename Traits::value_type result, Traits traits) { typedef wchar_selector::decoder decoder; return decoder::process(reinterpret_cast(data), size, result, traits); } }; #ifdef PUGIXML_WCHAR_MODE PUGI_IMPL_FN void convert_wchar_endian_swap(wchar_t* result, const wchar_t* data, size_t length) { for (size_t i = 0; i < length; ++i) result[i] = static_cast(endian_swap(static_cast::type>(data[i]))); } #endif PUGI_IMPL_NS_END PUGI_IMPL_NS_BEGIN enum chartype_t { ct_parse_pcdata = 1, // \0, &, \r, < ct_parse_attr = 2, // \0, &, \r, ', " ct_parse_attr_ws = 4, // \0, &, \r, ', ", \n, tab ct_space = 8, // \r, \n, space, tab ct_parse_cdata = 16, // \0, ], >, \r ct_parse_comment = 32, // \0, -, >, \r ct_symbol = 64, // Any symbol > 127, a-z, A-Z, 0-9, _, :, -, . ct_start_symbol = 128 // Any symbol > 127, a-z, A-Z, _, : }; static const unsigned char chartype_table[256] = { 55, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 0, 0, 63, 0, 0, // 0-15 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16-31 8, 0, 6, 0, 0, 0, 7, 6, 0, 0, 0, 0, 0, 96, 64, 0, // 32-47 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 192, 0, 1, 0, 48, 0, // 48-63 0, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, // 64-79 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 0, 0, 16, 0, 192, // 80-95 0, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, // 96-111 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 0, 0, 0, 0, 0, // 112-127 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, // 128+ 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192 }; enum chartypex_t { ctx_special_pcdata = 1, // Any symbol >= 0 and < 32 (except \t, \r, \n), &, <, > ctx_special_attr = 2, // Any symbol >= 0 and < 32, &, <, ", ' ctx_start_symbol = 4, // Any symbol > 127, a-z, A-Z, _ ctx_digit = 8, // 0-9 ctx_symbol = 16 // Any symbol > 127, a-z, A-Z, 0-9, _, -, . }; static const unsigned char chartypex_table[256] = { 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 3, 3, 2, 3, 3, // 0-15 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 16-31 0, 0, 2, 0, 0, 0, 3, 2, 0, 0, 0, 0, 0, 16, 16, 0, // 32-47 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 0, 0, 3, 0, 1, 0, // 48-63 0, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, // 64-79 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 20, // 80-95 0, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, // 96-111 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, // 112-127 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, // 128+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20 }; #ifdef PUGIXML_WCHAR_MODE #define PUGI_IMPL_IS_CHARTYPE_IMPL(c, ct, table) ((static_cast(c) < 128 ? table[static_cast(c)] : table[128]) & (ct)) #else #define PUGI_IMPL_IS_CHARTYPE_IMPL(c, ct, table) (table[static_cast(c)] & (ct)) #endif #define PUGI_IMPL_IS_CHARTYPE(c, ct) PUGI_IMPL_IS_CHARTYPE_IMPL(c, ct, chartype_table) #define PUGI_IMPL_IS_CHARTYPEX(c, ct) PUGI_IMPL_IS_CHARTYPE_IMPL(c, ct, chartypex_table) PUGI_IMPL_FN bool is_little_endian() { unsigned int ui = 1; return *reinterpret_cast(&ui) == 1; } PUGI_IMPL_FN xml_encoding get_wchar_encoding() { PUGI_IMPL_STATIC_ASSERT(sizeof(wchar_t) == 2 || sizeof(wchar_t) == 4); if (sizeof(wchar_t) == 2) return is_little_endian() ? encoding_utf16_le : encoding_utf16_be; else return is_little_endian() ? encoding_utf32_le : encoding_utf32_be; } PUGI_IMPL_FN bool parse_declaration_encoding(const uint8_t* data, size_t size, const uint8_t*& out_encoding, size_t& out_length) { #define PUGI_IMPL_SCANCHAR(ch) { if (offset >= size || data[offset] != ch) return false; offset++; } #define PUGI_IMPL_SCANCHARTYPE(ct) { while (offset < size && PUGI_IMPL_IS_CHARTYPE(data[offset], ct)) offset++; } // check if we have a non-empty XML declaration if (size < 6 || !((data[0] == '<') & (data[1] == '?') & (data[2] == 'x') & (data[3] == 'm') & (data[4] == 'l') && PUGI_IMPL_IS_CHARTYPE(data[5], ct_space))) return false; // scan XML declaration until the encoding field for (size_t i = 6; i + 1 < size; ++i) { // declaration can not contain ? in quoted values if (data[i] == '?') return false; if (data[i] == 'e' && data[i + 1] == 'n') { size_t offset = i; // encoding follows the version field which can't contain 'en' so this has to be the encoding if XML is well formed PUGI_IMPL_SCANCHAR('e'); PUGI_IMPL_SCANCHAR('n'); PUGI_IMPL_SCANCHAR('c'); PUGI_IMPL_SCANCHAR('o'); PUGI_IMPL_SCANCHAR('d'); PUGI_IMPL_SCANCHAR('i'); PUGI_IMPL_SCANCHAR('n'); PUGI_IMPL_SCANCHAR('g'); // S? = S? PUGI_IMPL_SCANCHARTYPE(ct_space); PUGI_IMPL_SCANCHAR('='); PUGI_IMPL_SCANCHARTYPE(ct_space); // the only two valid delimiters are ' and " uint8_t delimiter = (offset < size && data[offset] == '"') ? '"' : '\''; PUGI_IMPL_SCANCHAR(delimiter); size_t start = offset; out_encoding = data + offset; PUGI_IMPL_SCANCHARTYPE(ct_symbol); out_length = offset - start; PUGI_IMPL_SCANCHAR(delimiter); return true; } } return false; #undef PUGI_IMPL_SCANCHAR #undef PUGI_IMPL_SCANCHARTYPE } PUGI_IMPL_FN xml_encoding guess_buffer_encoding(const uint8_t* data, size_t size) { // skip encoding autodetection if input buffer is too small if (size < 4) return encoding_utf8; uint8_t d0 = data[0], d1 = data[1], d2 = data[2], d3 = data[3]; // look for BOM in first few bytes if (d0 == 0 && d1 == 0 && d2 == 0xfe && d3 == 0xff) return encoding_utf32_be; if (d0 == 0xff && d1 == 0xfe && d2 == 0 && d3 == 0) return encoding_utf32_le; if (d0 == 0xfe && d1 == 0xff) return encoding_utf16_be; if (d0 == 0xff && d1 == 0xfe) return encoding_utf16_le; if (d0 == 0xef && d1 == 0xbb && d2 == 0xbf) return encoding_utf8; // look for <, (contents); return guess_buffer_encoding(data, size); } PUGI_IMPL_FN bool get_mutable_buffer(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, bool is_mutable) { size_t length = size / sizeof(char_t); if (is_mutable) { out_buffer = static_cast(const_cast(contents)); out_length = length; } else { char_t* buffer = static_cast(xml_memory::allocate((length + 1) * sizeof(char_t))); if (!buffer) return false; if (contents) memcpy(buffer, contents, length * sizeof(char_t)); else assert(length == 0); buffer[length] = 0; out_buffer = buffer; out_length = length + 1; } return true; } #ifdef PUGIXML_WCHAR_MODE PUGI_IMPL_FN bool need_endian_swap_utf(xml_encoding le, xml_encoding re) { return (le == encoding_utf16_be && re == encoding_utf16_le) || (le == encoding_utf16_le && re == encoding_utf16_be) || (le == encoding_utf32_be && re == encoding_utf32_le) || (le == encoding_utf32_le && re == encoding_utf32_be); } PUGI_IMPL_FN bool convert_buffer_endian_swap(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, bool is_mutable) { const char_t* data = static_cast(contents); size_t length = size / sizeof(char_t); if (is_mutable) { char_t* buffer = const_cast(data); convert_wchar_endian_swap(buffer, data, length); out_buffer = buffer; out_length = length; } else { char_t* buffer = static_cast(xml_memory::allocate((length + 1) * sizeof(char_t))); if (!buffer) return false; convert_wchar_endian_swap(buffer, data, length); buffer[length] = 0; out_buffer = buffer; out_length = length + 1; } return true; } template PUGI_IMPL_FN bool convert_buffer_generic(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, D) { const typename D::type* data = static_cast(contents); size_t data_length = size / sizeof(typename D::type); // first pass: get length in wchar_t units size_t length = D::process(data, data_length, 0, wchar_counter()); // allocate buffer of suitable length char_t* buffer = static_cast(xml_memory::allocate((length + 1) * sizeof(char_t))); if (!buffer) return false; // second pass: convert utf16 input to wchar_t wchar_writer::value_type obegin = reinterpret_cast(buffer); wchar_writer::value_type oend = D::process(data, data_length, obegin, wchar_writer()); assert(oend == obegin + length); *oend = 0; out_buffer = buffer; out_length = length + 1; return true; } PUGI_IMPL_FN bool convert_buffer(char_t*& out_buffer, size_t& out_length, xml_encoding encoding, const void* contents, size_t size, bool is_mutable) { // get native encoding xml_encoding wchar_encoding = get_wchar_encoding(); // fast path: no conversion required if (encoding == wchar_encoding) return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable); // only endian-swapping is required if (need_endian_swap_utf(encoding, wchar_encoding)) return convert_buffer_endian_swap(out_buffer, out_length, contents, size, is_mutable); // source encoding is utf8 if (encoding == encoding_utf8) return convert_buffer_generic(out_buffer, out_length, contents, size, utf8_decoder()); // source encoding is utf16 if (encoding == encoding_utf16_be || encoding == encoding_utf16_le) { xml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be; return (native_encoding == encoding) ? convert_buffer_generic(out_buffer, out_length, contents, size, utf16_decoder()) : convert_buffer_generic(out_buffer, out_length, contents, size, utf16_decoder()); } // source encoding is utf32 if (encoding == encoding_utf32_be || encoding == encoding_utf32_le) { xml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be; return (native_encoding == encoding) ? convert_buffer_generic(out_buffer, out_length, contents, size, utf32_decoder()) : convert_buffer_generic(out_buffer, out_length, contents, size, utf32_decoder()); } // source encoding is latin1 if (encoding == encoding_latin1) return convert_buffer_generic(out_buffer, out_length, contents, size, latin1_decoder()); assert(false && "Invalid encoding"); // unreachable return false; } #else template PUGI_IMPL_FN bool convert_buffer_generic(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, D) { const typename D::type* data = static_cast(contents); size_t data_length = size / sizeof(typename D::type); // first pass: get length in utf8 units size_t length = D::process(data, data_length, 0, utf8_counter()); // allocate buffer of suitable length char_t* buffer = static_cast(xml_memory::allocate((length + 1) * sizeof(char_t))); if (!buffer) return false; // second pass: convert utf16 input to utf8 uint8_t* obegin = reinterpret_cast(buffer); uint8_t* oend = D::process(data, data_length, obegin, utf8_writer()); assert(oend == obegin + length); *oend = 0; out_buffer = buffer; out_length = length + 1; return true; } PUGI_IMPL_FN size_t get_latin1_7bit_prefix_length(const uint8_t* data, size_t size) { for (size_t i = 0; i < size; ++i) if (data[i] > 127) return i; return size; } PUGI_IMPL_FN bool convert_buffer_latin1(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, bool is_mutable) { const uint8_t* data = static_cast(contents); size_t data_length = size; // get size of prefix that does not need utf8 conversion size_t prefix_length = get_latin1_7bit_prefix_length(data, data_length); assert(prefix_length <= data_length); const uint8_t* postfix = data + prefix_length; size_t postfix_length = data_length - prefix_length; // if no conversion is needed, just return the original buffer if (postfix_length == 0) return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable); // first pass: get length in utf8 units size_t length = prefix_length + latin1_decoder::process(postfix, postfix_length, 0, utf8_counter()); // allocate buffer of suitable length char_t* buffer = static_cast(xml_memory::allocate((length + 1) * sizeof(char_t))); if (!buffer) return false; // second pass: convert latin1 input to utf8 memcpy(buffer, data, prefix_length); uint8_t* obegin = reinterpret_cast(buffer); uint8_t* oend = latin1_decoder::process(postfix, postfix_length, obegin + prefix_length, utf8_writer()); assert(oend == obegin + length); *oend = 0; out_buffer = buffer; out_length = length + 1; return true; } PUGI_IMPL_FN bool convert_buffer(char_t*& out_buffer, size_t& out_length, xml_encoding encoding, const void* contents, size_t size, bool is_mutable) { // fast path: no conversion required if (encoding == encoding_utf8) return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable); // source encoding is utf16 if (encoding == encoding_utf16_be || encoding == encoding_utf16_le) { xml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be; return (native_encoding == encoding) ? convert_buffer_generic(out_buffer, out_length, contents, size, utf16_decoder()) : convert_buffer_generic(out_buffer, out_length, contents, size, utf16_decoder()); } // source encoding is utf32 if (encoding == encoding_utf32_be || encoding == encoding_utf32_le) { xml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be; return (native_encoding == encoding) ? convert_buffer_generic(out_buffer, out_length, contents, size, utf32_decoder()) : convert_buffer_generic(out_buffer, out_length, contents, size, utf32_decoder()); } // source encoding is latin1 if (encoding == encoding_latin1) return convert_buffer_latin1(out_buffer, out_length, contents, size, is_mutable); assert(false && "Invalid encoding"); // unreachable return false; } #endif PUGI_IMPL_FN size_t as_utf8_begin(const wchar_t* str, size_t length) { // get length in utf8 characters return wchar_decoder::process(str, length, 0, utf8_counter()); } PUGI_IMPL_FN void as_utf8_end(char* buffer, size_t size, const wchar_t* str, size_t length) { // convert to utf8 uint8_t* begin = reinterpret_cast(buffer); uint8_t* end = wchar_decoder::process(str, length, begin, utf8_writer()); assert(begin + size == end); (void)!end; (void)!size; } #ifndef PUGIXML_NO_STL PUGI_IMPL_FN std::string as_utf8_impl(const wchar_t* str, size_t length) { // first pass: get length in utf8 characters size_t size = as_utf8_begin(str, length); // allocate resulting string std::string result; result.resize(size); // second pass: convert to utf8 if (size > 0) as_utf8_end(&result[0], size, str, length); return result; } PUGI_IMPL_FN std::basic_string as_wide_impl(const char* str, size_t size) { const uint8_t* data = reinterpret_cast(str); // first pass: get length in wchar_t units size_t length = utf8_decoder::process(data, size, 0, wchar_counter()); // allocate resulting string std::basic_string result; result.resize(length); // second pass: convert to wchar_t if (length > 0) { wchar_writer::value_type begin = reinterpret_cast(&result[0]); wchar_writer::value_type end = utf8_decoder::process(data, size, begin, wchar_writer()); assert(begin + length == end); (void)!end; } return result; } #endif template inline bool strcpy_insitu_allow(size_t length, const Header& header, uintptr_t header_mask, char_t* target) { // never reuse shared memory if (header & xml_memory_page_contents_shared_mask) return false; size_t target_length = strlength(target); // always reuse document buffer memory if possible if ((header & header_mask) == 0) return target_length >= length; // reuse heap memory if waste is not too great const size_t reuse_threshold = 32; return target_length >= length && (target_length < reuse_threshold || target_length - length < target_length / 2); } template PUGI_IMPL_FN bool strcpy_insitu(String& dest, Header& header, uintptr_t header_mask, const char_t* source, size_t source_length) { assert((header & header_mask) == 0 || dest); // header bit indicates whether dest was previously allocated if (source_length == 0) { // empty string and null pointer are equivalent, so just deallocate old memory xml_allocator* alloc = PUGI_IMPL_GETPAGE_IMPL(header)->allocator; if (header & header_mask) alloc->deallocate_string(dest); // mark the string as not allocated dest = NULL; header &= ~header_mask; return true; } else if (dest && strcpy_insitu_allow(source_length, header, header_mask, dest)) { // we can reuse old buffer, so just copy the new data (including zero terminator) memcpy(dest, source, source_length * sizeof(char_t)); dest[source_length] = 0; return true; } else { xml_allocator* alloc = PUGI_IMPL_GETPAGE_IMPL(header)->allocator; if (!alloc->reserve()) return false; // allocate new buffer char_t* buf = alloc->allocate_string(source_length + 1); if (!buf) return false; // copy the string (including zero terminator) memcpy(buf, source, source_length * sizeof(char_t)); buf[source_length] = 0; // deallocate old buffer (*after* the above to protect against overlapping memory and/or allocation failures) if (header & header_mask) alloc->deallocate_string(dest); // the string is now allocated, so set the flag dest = buf; header |= header_mask; return true; } } struct gap { char_t* end; size_t size; gap(): end(NULL), size(0) { } // Push new gap, move s count bytes further (skipping the gap). // Collapse previous gap. void push(char_t*& s, size_t count) { if (end) // there was a gap already; collapse it { // Move [old_gap_end, new_gap_start) to [old_gap_start, ...) assert(s >= end); memmove(end - size, end, (s - end) * sizeof(char_t)); } s += count; // end of current gap // "merge" two gaps end = s; size += count; } // Collapse all gaps, return past-the-end pointer char_t* flush(char_t* s) { if (end) { // Move [old_gap_end, current_pos) to [old_gap_start, ...) assert(s >= end); memmove(end - size, end, (s - end) * sizeof(char_t)); return s - size; } else return s; } }; PUGI_IMPL_FN char_t* strconv_escape(char_t* s, gap& g) { char_t* stre = s + 1; switch (*stre) { case '#': // &#... { unsigned int ucsc = 0; if (stre[1] == 'x') // &#x... (hex code) { stre += 2; char_t ch = *stre; if (ch == ';') return stre; for (;;) { if (static_cast(ch - '0') <= 9) ucsc = 16 * ucsc + (ch - '0'); else if (static_cast((ch | ' ') - 'a') <= 5) ucsc = 16 * ucsc + ((ch | ' ') - 'a' + 10); else if (ch == ';') break; else // cancel return stre; ch = *++stre; } ++stre; } else // &#... (dec code) { char_t ch = *++stre; if (ch == ';') return stre; for (;;) { if (static_cast(ch - '0') <= 9) ucsc = 10 * ucsc + (ch - '0'); else if (ch == ';') break; else // cancel return stre; ch = *++stre; } ++stre; } #ifdef PUGIXML_WCHAR_MODE s = reinterpret_cast(wchar_writer::any(reinterpret_cast(s), ucsc)); #else s = reinterpret_cast(utf8_writer::any(reinterpret_cast(s), ucsc)); #endif g.push(s, stre - s); return stre; } case 'a': // &a { ++stre; if (*stre == 'm') // &am { if (*++stre == 'p' && *++stre == ';') // & { *s++ = '&'; ++stre; g.push(s, stre - s); return stre; } } else if (*stre == 'p') // &ap { if (*++stre == 'o' && *++stre == 's' && *++stre == ';') // ' { *s++ = '\''; ++stre; g.push(s, stre - s); return stre; } } break; } case 'g': // &g { if (*++stre == 't' && *++stre == ';') // > { *s++ = '>'; ++stre; g.push(s, stre - s); return stre; } break; } case 'l': // &l { if (*++stre == 't' && *++stre == ';') // < { *s++ = '<'; ++stre; g.push(s, stre - s); return stre; } break; } case 'q': // &q { if (*++stre == 'u' && *++stre == 'o' && *++stre == 't' && *++stre == ';') // " { *s++ = '"'; ++stre; g.push(s, stre - s); return stre; } break; } default: break; } return stre; } // Parser utilities #define PUGI_IMPL_ENDSWITH(c, e) ((c) == (e) || ((c) == 0 && endch == (e))) #define PUGI_IMPL_SKIPWS() { while (PUGI_IMPL_IS_CHARTYPE(*s, ct_space)) ++s; } #define PUGI_IMPL_OPTSET(OPT) ( optmsk & (OPT) ) #define PUGI_IMPL_PUSHNODE(TYPE) { cursor = append_new_node(cursor, *alloc, TYPE); if (!cursor) PUGI_IMPL_THROW_ERROR(status_out_of_memory, s); } #define PUGI_IMPL_POPNODE() { cursor = cursor->parent; } #define PUGI_IMPL_SCANFOR(X) { while (*s != 0 && !(X)) ++s; } #define PUGI_IMPL_SCANWHILE(X) { while (X) ++s; } #define PUGI_IMPL_SCANWHILE_UNROLL(X) { for (;;) { char_t ss = s[0]; if (PUGI_IMPL_UNLIKELY(!(X))) { break; } ss = s[1]; if (PUGI_IMPL_UNLIKELY(!(X))) { s += 1; break; } ss = s[2]; if (PUGI_IMPL_UNLIKELY(!(X))) { s += 2; break; } ss = s[3]; if (PUGI_IMPL_UNLIKELY(!(X))) { s += 3; break; } s += 4; } } #define PUGI_IMPL_ENDSEG() { ch = *s; *s = 0; ++s; } #define PUGI_IMPL_THROW_ERROR(err, m) return error_offset = m, error_status = err, static_cast(NULL) #define PUGI_IMPL_CHECK_ERROR(err, m) { if (*s == 0) PUGI_IMPL_THROW_ERROR(err, m); } PUGI_IMPL_FN char_t* strconv_comment(char_t* s, char_t endch) { gap g; while (true) { PUGI_IMPL_SCANWHILE_UNROLL(!PUGI_IMPL_IS_CHARTYPE(ss, ct_parse_comment)); if (*s == '\r') // Either a single 0x0d or 0x0d 0x0a pair { *s++ = '\n'; // replace first one with 0x0a if (*s == '\n') g.push(s, 1); } else if (s[0] == '-' && s[1] == '-' && PUGI_IMPL_ENDSWITH(s[2], '>')) // comment ends here { *g.flush(s) = 0; return s + (s[2] == '>' ? 3 : 2); } else if (*s == 0) { return NULL; } else ++s; } } PUGI_IMPL_FN char_t* strconv_cdata(char_t* s, char_t endch) { gap g; while (true) { PUGI_IMPL_SCANWHILE_UNROLL(!PUGI_IMPL_IS_CHARTYPE(ss, ct_parse_cdata)); if (*s == '\r') // Either a single 0x0d or 0x0d 0x0a pair { *s++ = '\n'; // replace first one with 0x0a if (*s == '\n') g.push(s, 1); } else if (s[0] == ']' && s[1] == ']' && PUGI_IMPL_ENDSWITH(s[2], '>')) // CDATA ends here { *g.flush(s) = 0; return s + 1; } else if (*s == 0) { return NULL; } else ++s; } } typedef char_t* (*strconv_pcdata_t)(char_t*); template struct strconv_pcdata_impl { static char_t* parse(char_t* s) { gap g; char_t* begin = s; while (true) { PUGI_IMPL_SCANWHILE_UNROLL(!PUGI_IMPL_IS_CHARTYPE(ss, ct_parse_pcdata)); if (*s == '<') // PCDATA ends here { char_t* end = g.flush(s); if (opt_trim::value) while (end > begin && PUGI_IMPL_IS_CHARTYPE(end[-1], ct_space)) --end; *end = 0; return s + 1; } else if (opt_eol::value && *s == '\r') // Either a single 0x0d or 0x0d 0x0a pair { *s++ = '\n'; // replace first one with 0x0a if (*s == '\n') g.push(s, 1); } else if (opt_escape::value && *s == '&') { s = strconv_escape(s, g); } else if (*s == 0) { char_t* end = g.flush(s); if (opt_trim::value) while (end > begin && PUGI_IMPL_IS_CHARTYPE(end[-1], ct_space)) --end; *end = 0; return s; } else ++s; } } }; PUGI_IMPL_FN strconv_pcdata_t get_strconv_pcdata(unsigned int optmask) { PUGI_IMPL_STATIC_ASSERT(parse_escapes == 0x10 && parse_eol == 0x20 && parse_trim_pcdata == 0x0800); switch (((optmask >> 4) & 3) | ((optmask >> 9) & 4)) // get bitmask for flags (trim eol escapes); this simultaneously checks 3 options from assertion above { case 0: return strconv_pcdata_impl::parse; case 1: return strconv_pcdata_impl::parse; case 2: return strconv_pcdata_impl::parse; case 3: return strconv_pcdata_impl::parse; case 4: return strconv_pcdata_impl::parse; case 5: return strconv_pcdata_impl::parse; case 6: return strconv_pcdata_impl::parse; case 7: return strconv_pcdata_impl::parse; default: assert(false); return NULL; // unreachable } } typedef char_t* (*strconv_attribute_t)(char_t*, char_t); template struct strconv_attribute_impl { static char_t* parse_wnorm(char_t* s, char_t end_quote) { gap g; // trim leading whitespaces if (PUGI_IMPL_IS_CHARTYPE(*s, ct_space)) { char_t* str = s; do ++str; while (PUGI_IMPL_IS_CHARTYPE(*str, ct_space)); g.push(s, str - s); } while (true) { PUGI_IMPL_SCANWHILE_UNROLL(!PUGI_IMPL_IS_CHARTYPE(ss, ct_parse_attr_ws | ct_space)); if (*s == end_quote) { char_t* str = g.flush(s); do *str-- = 0; while (PUGI_IMPL_IS_CHARTYPE(*str, ct_space)); return s + 1; } else if (PUGI_IMPL_IS_CHARTYPE(*s, ct_space)) { *s++ = ' '; if (PUGI_IMPL_IS_CHARTYPE(*s, ct_space)) { char_t* str = s + 1; while (PUGI_IMPL_IS_CHARTYPE(*str, ct_space)) ++str; g.push(s, str - s); } } else if (opt_escape::value && *s == '&') { s = strconv_escape(s, g); } else if (!*s) { return NULL; } else ++s; } } static char_t* parse_wconv(char_t* s, char_t end_quote) { gap g; while (true) { PUGI_IMPL_SCANWHILE_UNROLL(!PUGI_IMPL_IS_CHARTYPE(ss, ct_parse_attr_ws)); if (*s == end_quote) { *g.flush(s) = 0; return s + 1; } else if (PUGI_IMPL_IS_CHARTYPE(*s, ct_space)) { if (*s == '\r') { *s++ = ' '; if (*s == '\n') g.push(s, 1); } else *s++ = ' '; } else if (opt_escape::value && *s == '&') { s = strconv_escape(s, g); } else if (!*s) { return NULL; } else ++s; } } static char_t* parse_eol(char_t* s, char_t end_quote) { gap g; while (true) { PUGI_IMPL_SCANWHILE_UNROLL(!PUGI_IMPL_IS_CHARTYPE(ss, ct_parse_attr)); if (*s == end_quote) { *g.flush(s) = 0; return s + 1; } else if (*s == '\r') { *s++ = '\n'; if (*s == '\n') g.push(s, 1); } else if (opt_escape::value && *s == '&') { s = strconv_escape(s, g); } else if (!*s) { return NULL; } else ++s; } } static char_t* parse_simple(char_t* s, char_t end_quote) { gap g; while (true) { PUGI_IMPL_SCANWHILE_UNROLL(!PUGI_IMPL_IS_CHARTYPE(ss, ct_parse_attr)); if (*s == end_quote) { *g.flush(s) = 0; return s + 1; } else if (opt_escape::value && *s == '&') { s = strconv_escape(s, g); } else if (!*s) { return NULL; } else ++s; } } }; PUGI_IMPL_FN strconv_attribute_t get_strconv_attribute(unsigned int optmask) { PUGI_IMPL_STATIC_ASSERT(parse_escapes == 0x10 && parse_eol == 0x20 && parse_wconv_attribute == 0x40 && parse_wnorm_attribute == 0x80); switch ((optmask >> 4) & 15) // get bitmask for flags (wnorm wconv eol escapes); this simultaneously checks 4 options from assertion above { case 0: return strconv_attribute_impl::parse_simple; case 1: return strconv_attribute_impl::parse_simple; case 2: return strconv_attribute_impl::parse_eol; case 3: return strconv_attribute_impl::parse_eol; case 4: return strconv_attribute_impl::parse_wconv; case 5: return strconv_attribute_impl::parse_wconv; case 6: return strconv_attribute_impl::parse_wconv; case 7: return strconv_attribute_impl::parse_wconv; case 8: return strconv_attribute_impl::parse_wnorm; case 9: return strconv_attribute_impl::parse_wnorm; case 10: return strconv_attribute_impl::parse_wnorm; case 11: return strconv_attribute_impl::parse_wnorm; case 12: return strconv_attribute_impl::parse_wnorm; case 13: return strconv_attribute_impl::parse_wnorm; case 14: return strconv_attribute_impl::parse_wnorm; case 15: return strconv_attribute_impl::parse_wnorm; default: assert(false); return NULL; // unreachable } } inline xml_parse_result make_parse_result(xml_parse_status status, ptrdiff_t offset = 0) { xml_parse_result result; result.status = status; result.offset = offset; return result; } struct xml_parser { xml_allocator* alloc; char_t* error_offset; xml_parse_status error_status; xml_parser(xml_allocator* alloc_): alloc(alloc_), error_offset(NULL), error_status(status_ok) { } // DOCTYPE consists of nested sections of the following possible types: // , , "...", '...' // // // First group can not contain nested groups // Second group can contain nested groups of the same type // Third group can contain all other groups char_t* parse_doctype_primitive(char_t* s) { if (*s == '"' || *s == '\'') { // quoted string char_t ch = *s++; PUGI_IMPL_SCANFOR(*s == ch); if (!*s) PUGI_IMPL_THROW_ERROR(status_bad_doctype, s); s++; } else if (s[0] == '<' && s[1] == '?') { // s += 2; PUGI_IMPL_SCANFOR(s[0] == '?' && s[1] == '>'); // no need for ENDSWITH because ?> can't terminate proper doctype if (!*s) PUGI_IMPL_THROW_ERROR(status_bad_doctype, s); s += 2; } else if (s[0] == '<' && s[1] == '!' && s[2] == '-' && s[3] == '-') { s += 4; PUGI_IMPL_SCANFOR(s[0] == '-' && s[1] == '-' && s[2] == '>'); // no need for ENDSWITH because --> can't terminate proper doctype if (!*s) PUGI_IMPL_THROW_ERROR(status_bad_doctype, s); s += 3; } else PUGI_IMPL_THROW_ERROR(status_bad_doctype, s); return s; } char_t* parse_doctype_ignore(char_t* s) { size_t depth = 0; assert(s[0] == '<' && s[1] == '!' && s[2] == '['); s += 3; while (*s) { if (s[0] == '<' && s[1] == '!' && s[2] == '[') { // nested ignore section s += 3; depth++; } else if (s[0] == ']' && s[1] == ']' && s[2] == '>') { // ignore section end s += 3; if (depth == 0) return s; depth--; } else s++; } PUGI_IMPL_THROW_ERROR(status_bad_doctype, s); } char_t* parse_doctype_group(char_t* s, char_t endch) { size_t depth = 0; assert((s[0] == '<' || s[0] == 0) && s[1] == '!'); s += 2; while (*s) { if (s[0] == '<' && s[1] == '!' && s[2] != '-') { if (s[2] == '[') { // ignore s = parse_doctype_ignore(s); if (!s) return s; } else { // some control group s += 2; depth++; } } else if (s[0] == '<' || s[0] == '"' || s[0] == '\'') { // unknown tag (forbidden), or some primitive group s = parse_doctype_primitive(s); if (!s) return s; } else if (*s == '>') { if (depth == 0) return s; depth--; s++; } else s++; } if (depth != 0 || endch != '>') PUGI_IMPL_THROW_ERROR(status_bad_doctype, s); return s; } char_t* parse_exclamation(char_t* s, xml_node_struct* cursor, unsigned int optmsk, char_t endch) { // parse node contents, starting with exclamation mark ++s; if (*s == '-') // 'value = s; // Save the offset. } if (PUGI_IMPL_OPTSET(parse_eol) && PUGI_IMPL_OPTSET(parse_comments)) { s = strconv_comment(s, endch); if (!s) PUGI_IMPL_THROW_ERROR(status_bad_comment, cursor->value); } else { // Scan for terminating '-->'. PUGI_IMPL_SCANFOR(s[0] == '-' && s[1] == '-' && PUGI_IMPL_ENDSWITH(s[2], '>')); PUGI_IMPL_CHECK_ERROR(status_bad_comment, s); if (PUGI_IMPL_OPTSET(parse_comments)) *s = 0; // Zero-terminate this segment at the first terminating '-'. s += (s[2] == '>' ? 3 : 2); // Step over the '\0->'. } } else PUGI_IMPL_THROW_ERROR(status_bad_comment, s); } else if (*s == '[') { // 'value = s; // Save the offset. if (PUGI_IMPL_OPTSET(parse_eol)) { s = strconv_cdata(s, endch); if (!s) PUGI_IMPL_THROW_ERROR(status_bad_cdata, cursor->value); } else { // Scan for terminating ']]>'. PUGI_IMPL_SCANFOR(s[0] == ']' && s[1] == ']' && PUGI_IMPL_ENDSWITH(s[2], '>')); PUGI_IMPL_CHECK_ERROR(status_bad_cdata, s); *s++ = 0; // Zero-terminate this segment. } } else // Flagged for discard, but we still have to scan for the terminator. { // Scan for terminating ']]>'. PUGI_IMPL_SCANFOR(s[0] == ']' && s[1] == ']' && PUGI_IMPL_ENDSWITH(s[2], '>')); PUGI_IMPL_CHECK_ERROR(status_bad_cdata, s); ++s; } s += (s[1] == '>' ? 2 : 1); // Step over the last ']>'. } else PUGI_IMPL_THROW_ERROR(status_bad_cdata, s); } else if (s[0] == 'D' && s[1] == 'O' && s[2] == 'C' && s[3] == 'T' && s[4] == 'Y' && s[5] == 'P' && PUGI_IMPL_ENDSWITH(s[6], 'E')) { s -= 2; if (cursor->parent) PUGI_IMPL_THROW_ERROR(status_bad_doctype, s); char_t* mark = s + 9; s = parse_doctype_group(s, endch); if (!s) return s; assert((*s == 0 && endch == '>') || *s == '>'); if (*s) *s++ = 0; if (PUGI_IMPL_OPTSET(parse_doctype)) { while (PUGI_IMPL_IS_CHARTYPE(*mark, ct_space)) ++mark; PUGI_IMPL_PUSHNODE(node_doctype); cursor->value = mark; } } else if (*s == 0 && endch == '-') PUGI_IMPL_THROW_ERROR(status_bad_comment, s); else if (*s == 0 && endch == '[') PUGI_IMPL_THROW_ERROR(status_bad_cdata, s); else PUGI_IMPL_THROW_ERROR(status_unrecognized_tag, s); return s; } char_t* parse_question(char_t* s, xml_node_struct*& ref_cursor, unsigned int optmsk, char_t endch) { // load into registers xml_node_struct* cursor = ref_cursor; char_t ch = 0; // parse node contents, starting with question mark ++s; // read PI target char_t* target = s; if (!PUGI_IMPL_IS_CHARTYPE(*s, ct_start_symbol)) PUGI_IMPL_THROW_ERROR(status_bad_pi, s); PUGI_IMPL_SCANWHILE(PUGI_IMPL_IS_CHARTYPE(*s, ct_symbol)); PUGI_IMPL_CHECK_ERROR(status_bad_pi, s); // determine node type; stricmp / strcasecmp is not portable bool declaration = (target[0] | ' ') == 'x' && (target[1] | ' ') == 'm' && (target[2] | ' ') == 'l' && target + 3 == s; if (declaration ? PUGI_IMPL_OPTSET(parse_declaration) : PUGI_IMPL_OPTSET(parse_pi)) { if (declaration) { // disallow non top-level declarations if (cursor->parent) PUGI_IMPL_THROW_ERROR(status_bad_pi, s); PUGI_IMPL_PUSHNODE(node_declaration); } else { PUGI_IMPL_PUSHNODE(node_pi); } cursor->name = target; PUGI_IMPL_ENDSEG(); // parse value/attributes if (ch == '?') { // empty node if (!PUGI_IMPL_ENDSWITH(*s, '>')) PUGI_IMPL_THROW_ERROR(status_bad_pi, s); s += (*s == '>'); PUGI_IMPL_POPNODE(); } else if (PUGI_IMPL_IS_CHARTYPE(ch, ct_space)) { PUGI_IMPL_SKIPWS(); // scan for tag end char_t* value = s; PUGI_IMPL_SCANFOR(s[0] == '?' && PUGI_IMPL_ENDSWITH(s[1], '>')); PUGI_IMPL_CHECK_ERROR(status_bad_pi, s); if (declaration) { // replace ending ? with / so that 'element' terminates properly *s = '/'; // we exit from this function with cursor at node_declaration, which is a signal to parse() to go to LOC_ATTRIBUTES s = value; } else { // store value and step over > cursor->value = value; PUGI_IMPL_POPNODE(); PUGI_IMPL_ENDSEG(); s += (*s == '>'); } } else PUGI_IMPL_THROW_ERROR(status_bad_pi, s); } else { // scan for tag end PUGI_IMPL_SCANFOR(s[0] == '?' && PUGI_IMPL_ENDSWITH(s[1], '>')); PUGI_IMPL_CHECK_ERROR(status_bad_pi, s); s += (s[1] == '>' ? 2 : 1); } // store from registers ref_cursor = cursor; return s; } char_t* parse_tree(char_t* s, xml_node_struct* root, unsigned int optmsk, char_t endch) { strconv_attribute_t strconv_attribute = get_strconv_attribute(optmsk); strconv_pcdata_t strconv_pcdata = get_strconv_pcdata(optmsk); char_t ch = 0; xml_node_struct* cursor = root; char_t* mark = s; char_t* merged_pcdata = s; while (*s != 0) { if (*s == '<') { ++s; LOC_TAG: if (PUGI_IMPL_IS_CHARTYPE(*s, ct_start_symbol)) // '<#...' { PUGI_IMPL_PUSHNODE(node_element); // Append a new node to the tree. cursor->name = s; PUGI_IMPL_SCANWHILE_UNROLL(PUGI_IMPL_IS_CHARTYPE(ss, ct_symbol)); // Scan for a terminator. PUGI_IMPL_ENDSEG(); // Save char in 'ch', terminate & step over. if (ch == '>') { // end of tag } else if (PUGI_IMPL_IS_CHARTYPE(ch, ct_space)) { LOC_ATTRIBUTES: while (true) { PUGI_IMPL_SKIPWS(); // Eat any whitespace. if (PUGI_IMPL_IS_CHARTYPE(*s, ct_start_symbol)) // <... #... { xml_attribute_struct* a = append_new_attribute(cursor, *alloc); // Make space for this attribute. if (!a) PUGI_IMPL_THROW_ERROR(status_out_of_memory, s); a->name = s; // Save the offset. PUGI_IMPL_SCANWHILE_UNROLL(PUGI_IMPL_IS_CHARTYPE(ss, ct_symbol)); // Scan for a terminator. PUGI_IMPL_ENDSEG(); // Save char in 'ch', terminate & step over. if (PUGI_IMPL_IS_CHARTYPE(ch, ct_space)) { PUGI_IMPL_SKIPWS(); // Eat any whitespace. ch = *s; ++s; } if (ch == '=') // '<... #=...' { PUGI_IMPL_SKIPWS(); // Eat any whitespace. if (*s == '"' || *s == '\'') // '<... #="...' { ch = *s; // Save quote char to avoid breaking on "''" -or- '""'. ++s; // Step over the quote. a->value = s; // Save the offset. s = strconv_attribute(s, ch); if (!s) PUGI_IMPL_THROW_ERROR(status_bad_attribute, a->value); // After this line the loop continues from the start; // Whitespaces, / and > are ok, symbols and EOF are wrong, // everything else will be detected if (PUGI_IMPL_IS_CHARTYPE(*s, ct_start_symbol)) PUGI_IMPL_THROW_ERROR(status_bad_attribute, s); } else PUGI_IMPL_THROW_ERROR(status_bad_attribute, s); } else PUGI_IMPL_THROW_ERROR(status_bad_attribute, s); } else if (*s == '/') { ++s; if (*s == '>') { PUGI_IMPL_POPNODE(); s++; break; } else if (*s == 0 && endch == '>') { PUGI_IMPL_POPNODE(); break; } else PUGI_IMPL_THROW_ERROR(status_bad_start_element, s); } else if (*s == '>') { ++s; break; } else if (*s == 0 && endch == '>') { break; } else PUGI_IMPL_THROW_ERROR(status_bad_start_element, s); } // !!! } else if (ch == '/') // '<#.../' { if (!PUGI_IMPL_ENDSWITH(*s, '>')) PUGI_IMPL_THROW_ERROR(status_bad_start_element, s); PUGI_IMPL_POPNODE(); // Pop. s += (*s == '>'); } else if (ch == 0) { // we stepped over null terminator, backtrack & handle closing tag --s; if (endch != '>') PUGI_IMPL_THROW_ERROR(status_bad_start_element, s); } else PUGI_IMPL_THROW_ERROR(status_bad_start_element, s); } else if (*s == '/') { ++s; mark = s; char_t* name = cursor->name; if (!name) PUGI_IMPL_THROW_ERROR(status_end_element_mismatch, mark); while (PUGI_IMPL_IS_CHARTYPE(*s, ct_symbol)) { if (*s++ != *name++) PUGI_IMPL_THROW_ERROR(status_end_element_mismatch, mark); } if (*name) { if (*s == 0 && name[0] == endch && name[1] == 0) PUGI_IMPL_THROW_ERROR(status_bad_end_element, s); else PUGI_IMPL_THROW_ERROR(status_end_element_mismatch, mark); } PUGI_IMPL_POPNODE(); // Pop. PUGI_IMPL_SKIPWS(); if (*s == 0) { if (endch != '>') PUGI_IMPL_THROW_ERROR(status_bad_end_element, s); } else { if (*s != '>') PUGI_IMPL_THROW_ERROR(status_bad_end_element, s); ++s; } } else if (*s == '?') // 'first_child) continue; } } if (!PUGI_IMPL_OPTSET(parse_trim_pcdata)) s = mark; if (cursor->parent || PUGI_IMPL_OPTSET(parse_fragment)) { char_t* parsed_pcdata = s; s = strconv_pcdata(s); if (PUGI_IMPL_OPTSET(parse_embed_pcdata) && cursor->parent && !cursor->first_child && !cursor->value) { cursor->value = parsed_pcdata; // Save the offset. } else if (PUGI_IMPL_OPTSET(parse_merge_pcdata) && cursor->first_child && PUGI_IMPL_NODETYPE(cursor->first_child->prev_sibling_c) == node_pcdata) { assert(merged_pcdata >= cursor->first_child->prev_sibling_c->value); // Catch up to the end of last parsed value; only needed for the first fragment. merged_pcdata += strlength(merged_pcdata); size_t length = strlength(parsed_pcdata); // Must use memmove instead of memcpy as this move may overlap memmove(merged_pcdata, parsed_pcdata, (length + 1) * sizeof(char_t)); merged_pcdata += length; } else { xml_node_struct* prev_cursor = cursor; PUGI_IMPL_PUSHNODE(node_pcdata); // Append a new node on the tree. cursor->value = parsed_pcdata; // Save the offset. merged_pcdata = parsed_pcdata; // Used for parse_merge_pcdata above, cheaper to save unconditionally cursor = prev_cursor; // Pop since this is a standalone. } if (!*s) break; } else { PUGI_IMPL_SCANFOR(*s == '<'); // '...<' if (!*s) break; ++s; } // We're after '<' goto LOC_TAG; } } // check that last tag is closed if (cursor != root) PUGI_IMPL_THROW_ERROR(status_end_element_mismatch, s); return s; } #ifdef PUGIXML_WCHAR_MODE static char_t* parse_skip_bom(char_t* s) { unsigned int bom = 0xfeff; return (s[0] == static_cast(bom)) ? s + 1 : s; } #else static char_t* parse_skip_bom(char_t* s) { return (s[0] == '\xef' && s[1] == '\xbb' && s[2] == '\xbf') ? s + 3 : s; } #endif static bool has_element_node_siblings(xml_node_struct* node) { while (node) { if (PUGI_IMPL_NODETYPE(node) == node_element) return true; node = node->next_sibling; } return false; } static xml_parse_result parse(char_t* buffer, size_t length, xml_document_struct* xmldoc, xml_node_struct* root, unsigned int optmsk) { // early-out for empty documents if (length == 0) return make_parse_result(PUGI_IMPL_OPTSET(parse_fragment) ? status_ok : status_no_document_element); // get last child of the root before parsing xml_node_struct* last_root_child = root->first_child ? root->first_child->prev_sibling_c + 0 : NULL; // create parser on stack xml_parser parser(static_cast(xmldoc)); // save last character and make buffer zero-terminated (speeds up parsing) char_t endch = buffer[length - 1]; buffer[length - 1] = 0; // skip BOM to make sure it does not end up as part of parse output char_t* buffer_data = parse_skip_bom(buffer); // perform actual parsing parser.parse_tree(buffer_data, root, optmsk, endch); xml_parse_result result = make_parse_result(parser.error_status, parser.error_offset ? parser.error_offset - buffer : 0); assert(result.offset >= 0 && static_cast(result.offset) <= length); if (result) { // since we removed last character, we have to handle the only possible false positive (stray <) if (endch == '<') return make_parse_result(status_unrecognized_tag, length - 1); // check if there are any element nodes parsed xml_node_struct* first_root_child_parsed = last_root_child ? last_root_child->next_sibling + 0 : root->first_child + 0; if (!PUGI_IMPL_OPTSET(parse_fragment) && !has_element_node_siblings(first_root_child_parsed)) return make_parse_result(status_no_document_element, length - 1); } else { // roll back offset if it occurs on a null terminator in the source buffer if (result.offset > 0 && static_cast(result.offset) == length - 1 && endch == 0) result.offset--; } return result; } }; // Output facilities PUGI_IMPL_FN xml_encoding get_write_native_encoding() { #ifdef PUGIXML_WCHAR_MODE return get_wchar_encoding(); #else return encoding_utf8; #endif } PUGI_IMPL_FN xml_encoding get_write_encoding(xml_encoding encoding) { // replace wchar encoding with utf implementation if (encoding == encoding_wchar) return get_wchar_encoding(); // replace utf16 encoding with utf16 with specific endianness if (encoding == encoding_utf16) return is_little_endian() ? encoding_utf16_le : encoding_utf16_be; // replace utf32 encoding with utf32 with specific endianness if (encoding == encoding_utf32) return is_little_endian() ? encoding_utf32_le : encoding_utf32_be; // only do autodetection if no explicit encoding is requested if (encoding != encoding_auto) return encoding; // assume utf8 encoding return encoding_utf8; } template PUGI_IMPL_FN size_t convert_buffer_output_generic(typename T::value_type dest, const char_t* data, size_t length, D, T) { PUGI_IMPL_STATIC_ASSERT(sizeof(char_t) == sizeof(typename D::type)); typename T::value_type end = D::process(reinterpret_cast(data), length, dest, T()); return static_cast(end - dest) * sizeof(*dest); } template PUGI_IMPL_FN size_t convert_buffer_output_generic(typename T::value_type dest, const char_t* data, size_t length, D, T, bool opt_swap) { PUGI_IMPL_STATIC_ASSERT(sizeof(char_t) == sizeof(typename D::type)); typename T::value_type end = D::process(reinterpret_cast(data), length, dest, T()); if (opt_swap) { for (typename T::value_type i = dest; i != end; ++i) *i = endian_swap(*i); } return static_cast(end - dest) * sizeof(*dest); } #ifdef PUGIXML_WCHAR_MODE PUGI_IMPL_FN size_t get_valid_length(const char_t* data, size_t length) { if (length < 1) return 0; // discard last character if it's the lead of a surrogate pair return (sizeof(wchar_t) == 2 && static_cast(static_cast(data[length - 1]) - 0xD800) < 0x400) ? length - 1 : length; } PUGI_IMPL_FN size_t convert_buffer_output(char_t* r_char, uint8_t* r_u8, uint16_t* r_u16, uint32_t* r_u32, const char_t* data, size_t length, xml_encoding encoding) { // only endian-swapping is required if (need_endian_swap_utf(encoding, get_wchar_encoding())) { convert_wchar_endian_swap(r_char, data, length); return length * sizeof(char_t); } // convert to utf8 if (encoding == encoding_utf8) return convert_buffer_output_generic(r_u8, data, length, wchar_decoder(), utf8_writer()); // convert to utf16 if (encoding == encoding_utf16_be || encoding == encoding_utf16_le) { xml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be; return convert_buffer_output_generic(r_u16, data, length, wchar_decoder(), utf16_writer(), native_encoding != encoding); } // convert to utf32 if (encoding == encoding_utf32_be || encoding == encoding_utf32_le) { xml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be; return convert_buffer_output_generic(r_u32, data, length, wchar_decoder(), utf32_writer(), native_encoding != encoding); } // convert to latin1 if (encoding == encoding_latin1) return convert_buffer_output_generic(r_u8, data, length, wchar_decoder(), latin1_writer()); assert(false && "Invalid encoding"); // unreachable return 0; } #else PUGI_IMPL_FN size_t get_valid_length(const char_t* data, size_t length) { if (length < 5) return 0; for (size_t i = 1; i <= 4; ++i) { uint8_t ch = static_cast(data[length - i]); // either a standalone character or a leading one if ((ch & 0xc0) != 0x80) return length - i; } // there are four non-leading characters at the end, sequence tail is broken so might as well process the whole chunk return length; } PUGI_IMPL_FN size_t convert_buffer_output(char_t* /* r_char */, uint8_t* r_u8, uint16_t* r_u16, uint32_t* r_u32, const char_t* data, size_t length, xml_encoding encoding) { if (encoding == encoding_utf16_be || encoding == encoding_utf16_le) { xml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be; return convert_buffer_output_generic(r_u16, data, length, utf8_decoder(), utf16_writer(), native_encoding != encoding); } if (encoding == encoding_utf32_be || encoding == encoding_utf32_le) { xml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be; return convert_buffer_output_generic(r_u32, data, length, utf8_decoder(), utf32_writer(), native_encoding != encoding); } if (encoding == encoding_latin1) return convert_buffer_output_generic(r_u8, data, length, utf8_decoder(), latin1_writer()); assert(false && "Invalid encoding"); // unreachable return 0; } #endif class xml_buffered_writer { xml_buffered_writer(const xml_buffered_writer&); xml_buffered_writer& operator=(const xml_buffered_writer&); public: xml_buffered_writer(xml_writer& writer_, xml_encoding user_encoding): writer(writer_), bufsize(0), encoding(get_write_encoding(user_encoding)) { PUGI_IMPL_STATIC_ASSERT(bufcapacity >= 8); } size_t flush() { flush(buffer, bufsize); bufsize = 0; return 0; } void flush(const char_t* data, size_t size) { if (size == 0) return; // fast path, just write data if (encoding == get_write_native_encoding()) writer.write(data, size * sizeof(char_t)); else { // convert chunk size_t result = convert_buffer_output(scratch.data_char, scratch.data_u8, scratch.data_u16, scratch.data_u32, data, size, encoding); assert(result <= sizeof(scratch)); // write data writer.write(scratch.data_u8, result); } } void write_direct(const char_t* data, size_t length) { // flush the remaining buffer contents flush(); // handle large chunks if (length > bufcapacity) { if (encoding == get_write_native_encoding()) { // fast path, can just write data chunk writer.write(data, length * sizeof(char_t)); return; } // need to convert in suitable chunks while (length > bufcapacity) { // get chunk size by selecting such number of characters that are guaranteed to fit into scratch buffer // and form a complete codepoint sequence (i.e. discard start of last codepoint if necessary) size_t chunk_size = get_valid_length(data, bufcapacity); assert(chunk_size); // convert chunk and write flush(data, chunk_size); // iterate data += chunk_size; length -= chunk_size; } // small tail is copied below bufsize = 0; } memcpy(buffer + bufsize, data, length * sizeof(char_t)); bufsize += length; } void write_buffer(const char_t* data, size_t length) { size_t offset = bufsize; if (offset + length <= bufcapacity) { memcpy(buffer + offset, data, length * sizeof(char_t)); bufsize = offset + length; } else { write_direct(data, length); } } void write_string(const char_t* data) { // write the part of the string that fits in the buffer size_t offset = bufsize; while (*data && offset < bufcapacity) buffer[offset++] = *data++; // write the rest if (offset < bufcapacity) { bufsize = offset; } else { // backtrack a bit if we have split the codepoint size_t length = offset - bufsize; size_t extra = length - get_valid_length(data - length, length); bufsize = offset - extra; write_direct(data - extra, strlength(data) + extra); } } void write(char_t d0) { size_t offset = bufsize; if (offset > bufcapacity - 1) offset = flush(); buffer[offset + 0] = d0; bufsize = offset + 1; } void write(char_t d0, char_t d1) { size_t offset = bufsize; if (offset > bufcapacity - 2) offset = flush(); buffer[offset + 0] = d0; buffer[offset + 1] = d1; bufsize = offset + 2; } void write(char_t d0, char_t d1, char_t d2) { size_t offset = bufsize; if (offset > bufcapacity - 3) offset = flush(); buffer[offset + 0] = d0; buffer[offset + 1] = d1; buffer[offset + 2] = d2; bufsize = offset + 3; } void write(char_t d0, char_t d1, char_t d2, char_t d3) { size_t offset = bufsize; if (offset > bufcapacity - 4) offset = flush(); buffer[offset + 0] = d0; buffer[offset + 1] = d1; buffer[offset + 2] = d2; buffer[offset + 3] = d3; bufsize = offset + 4; } void write(char_t d0, char_t d1, char_t d2, char_t d3, char_t d4) { size_t offset = bufsize; if (offset > bufcapacity - 5) offset = flush(); buffer[offset + 0] = d0; buffer[offset + 1] = d1; buffer[offset + 2] = d2; buffer[offset + 3] = d3; buffer[offset + 4] = d4; bufsize = offset + 5; } void write(char_t d0, char_t d1, char_t d2, char_t d3, char_t d4, char_t d5) { size_t offset = bufsize; if (offset > bufcapacity - 6) offset = flush(); buffer[offset + 0] = d0; buffer[offset + 1] = d1; buffer[offset + 2] = d2; buffer[offset + 3] = d3; buffer[offset + 4] = d4; buffer[offset + 5] = d5; bufsize = offset + 6; } // utf8 maximum expansion: x4 (-> utf32) // utf16 maximum expansion: x2 (-> utf32) // utf32 maximum expansion: x1 enum { bufcapacitybytes = #ifdef PUGIXML_MEMORY_OUTPUT_STACK PUGIXML_MEMORY_OUTPUT_STACK #else 10240 #endif , bufcapacity = bufcapacitybytes / (sizeof(char_t) + 4) }; char_t buffer[bufcapacity]; union { uint8_t data_u8[4 * bufcapacity]; uint16_t data_u16[2 * bufcapacity]; uint32_t data_u32[bufcapacity]; char_t data_char[bufcapacity]; } scratch; xml_writer& writer; size_t bufsize; xml_encoding encoding; }; PUGI_IMPL_FN void text_output_escaped(xml_buffered_writer& writer, const char_t* s, chartypex_t type, unsigned int flags) { while (*s) { const char_t* prev = s; // While *s is a usual symbol PUGI_IMPL_SCANWHILE_UNROLL(!PUGI_IMPL_IS_CHARTYPEX(ss, type)); writer.write_buffer(prev, static_cast(s - prev)); switch (*s) { case 0: break; case '&': writer.write('&', 'a', 'm', 'p', ';'); ++s; break; case '<': writer.write('&', 'l', 't', ';'); ++s; break; case '>': writer.write('&', 'g', 't', ';'); ++s; break; case '"': if (flags & format_attribute_single_quote) writer.write('"'); else writer.write('&', 'q', 'u', 'o', 't', ';'); ++s; break; case '\'': if (flags & format_attribute_single_quote) writer.write('&', 'a', 'p', 'o', 's', ';'); else writer.write('\''); ++s; break; default: // s is not a usual symbol { unsigned int ch = static_cast(*s++); assert(ch < 32); if (!(flags & format_skip_control_chars)) writer.write('&', '#', static_cast((ch / 10) + '0'), static_cast((ch % 10) + '0'), ';'); } } } } PUGI_IMPL_FN void text_output(xml_buffered_writer& writer, const char_t* s, chartypex_t type, unsigned int flags) { if (flags & format_no_escapes) writer.write_string(s); else text_output_escaped(writer, s, type, flags); } PUGI_IMPL_FN void text_output_cdata(xml_buffered_writer& writer, const char_t* s) { do { writer.write('<', '!', '[', 'C', 'D'); writer.write('A', 'T', 'A', '['); const char_t* prev = s; // look for ]]> sequence - we can't output it as is since it terminates CDATA while (*s && !(s[0] == ']' && s[1] == ']' && s[2] == '>')) ++s; // skip ]] if we stopped at ]]>, > will go to the next CDATA section if (*s) s += 2; writer.write_buffer(prev, static_cast(s - prev)); writer.write(']', ']', '>'); } while (*s); } PUGI_IMPL_FN void text_output_indent(xml_buffered_writer& writer, const char_t* indent, size_t indent_length, unsigned int depth) { switch (indent_length) { case 1: { for (unsigned int i = 0; i < depth; ++i) writer.write(indent[0]); break; } case 2: { for (unsigned int i = 0; i < depth; ++i) writer.write(indent[0], indent[1]); break; } case 3: { for (unsigned int i = 0; i < depth; ++i) writer.write(indent[0], indent[1], indent[2]); break; } case 4: { for (unsigned int i = 0; i < depth; ++i) writer.write(indent[0], indent[1], indent[2], indent[3]); break; } default: { for (unsigned int i = 0; i < depth; ++i) writer.write_buffer(indent, indent_length); } } } PUGI_IMPL_FN void node_output_comment(xml_buffered_writer& writer, const char_t* s) { writer.write('<', '!', '-', '-'); while (*s) { const char_t* prev = s; // look for -\0 or -- sequence - we can't output it since -- is illegal in comment body while (*s && !(s[0] == '-' && (s[1] == '-' || s[1] == 0))) ++s; writer.write_buffer(prev, static_cast(s - prev)); if (*s) { assert(*s == '-'); writer.write('-', ' '); ++s; } } writer.write('-', '-', '>'); } PUGI_IMPL_FN void node_output_pi_value(xml_buffered_writer& writer, const char_t* s) { while (*s) { const char_t* prev = s; // look for ?> sequence - we can't output it since ?> terminates PI while (*s && !(s[0] == '?' && s[1] == '>')) ++s; writer.write_buffer(prev, static_cast(s - prev)); if (*s) { assert(s[0] == '?' && s[1] == '>'); writer.write('?', ' ', '>'); s += 2; } } } PUGI_IMPL_FN void node_output_attributes(xml_buffered_writer& writer, xml_node_struct* node, const char_t* indent, size_t indent_length, unsigned int flags, unsigned int depth) { const char_t* default_name = PUGIXML_TEXT(":anonymous"); const char_t enquotation_char = (flags & format_attribute_single_quote) ? '\'' : '"'; for (xml_attribute_struct* a = node->first_attribute; a; a = a->next_attribute) { if ((flags & (format_indent_attributes | format_raw)) == format_indent_attributes) { writer.write('\n'); text_output_indent(writer, indent, indent_length, depth + 1); } else { writer.write(' '); } writer.write_string(a->name ? a->name + 0 : default_name); writer.write('=', enquotation_char); if (a->value) text_output(writer, a->value, ctx_special_attr, flags); writer.write(enquotation_char); } } PUGI_IMPL_FN bool node_output_start(xml_buffered_writer& writer, xml_node_struct* node, const char_t* indent, size_t indent_length, unsigned int flags, unsigned int depth) { const char_t* default_name = PUGIXML_TEXT(":anonymous"); const char_t* name = node->name ? node->name + 0 : default_name; writer.write('<'); writer.write_string(name); if (node->first_attribute) node_output_attributes(writer, node, indent, indent_length, flags, depth); // element nodes can have value if parse_embed_pcdata was used if (!node->value) { if (!node->first_child) { if (flags & format_no_empty_element_tags) { writer.write('>', '<', '/'); writer.write_string(name); writer.write('>'); return false; } else { if ((flags & format_raw) == 0) writer.write(' '); writer.write('/', '>'); return false; } } else { writer.write('>'); return true; } } else { writer.write('>'); text_output(writer, node->value, ctx_special_pcdata, flags); if (!node->first_child) { writer.write('<', '/'); writer.write_string(name); writer.write('>'); return false; } else { return true; } } } PUGI_IMPL_FN void node_output_end(xml_buffered_writer& writer, xml_node_struct* node) { const char_t* default_name = PUGIXML_TEXT(":anonymous"); const char_t* name = node->name ? node->name + 0 : default_name; writer.write('<', '/'); writer.write_string(name); writer.write('>'); } PUGI_IMPL_FN void node_output_simple(xml_buffered_writer& writer, xml_node_struct* node, unsigned int flags) { const char_t* default_name = PUGIXML_TEXT(":anonymous"); switch (PUGI_IMPL_NODETYPE(node)) { case node_pcdata: text_output(writer, node->value ? node->value + 0 : PUGIXML_TEXT(""), ctx_special_pcdata, flags); break; case node_cdata: text_output_cdata(writer, node->value ? node->value + 0 : PUGIXML_TEXT("")); break; case node_comment: node_output_comment(writer, node->value ? node->value + 0 : PUGIXML_TEXT("")); break; case node_pi: writer.write('<', '?'); writer.write_string(node->name ? node->name + 0 : default_name); if (node->value) { writer.write(' '); node_output_pi_value(writer, node->value); } writer.write('?', '>'); break; case node_declaration: writer.write('<', '?'); writer.write_string(node->name ? node->name + 0 : default_name); node_output_attributes(writer, node, PUGIXML_TEXT(""), 0, flags | format_raw, 0); writer.write('?', '>'); break; case node_doctype: writer.write('<', '!', 'D', 'O', 'C'); writer.write('T', 'Y', 'P', 'E'); if (node->value) { writer.write(' '); writer.write_string(node->value); } writer.write('>'); break; default: assert(false && "Invalid node type"); // unreachable } } enum indent_flags_t { indent_newline = 1, indent_indent = 2 }; PUGI_IMPL_FN void node_output(xml_buffered_writer& writer, xml_node_struct* root, const char_t* indent, unsigned int flags, unsigned int depth) { size_t indent_length = ((flags & (format_indent | format_indent_attributes)) && (flags & format_raw) == 0) ? strlength(indent) : 0; unsigned int indent_flags = indent_indent; xml_node_struct* node = root; do { assert(node); // begin writing current node if (PUGI_IMPL_NODETYPE(node) == node_pcdata || PUGI_IMPL_NODETYPE(node) == node_cdata) { node_output_simple(writer, node, flags); indent_flags = 0; } else { if ((indent_flags & indent_newline) && (flags & format_raw) == 0) writer.write('\n'); if ((indent_flags & indent_indent) && indent_length) text_output_indent(writer, indent, indent_length, depth); if (PUGI_IMPL_NODETYPE(node) == node_element) { indent_flags = indent_newline | indent_indent; if (node_output_start(writer, node, indent, indent_length, flags, depth)) { // element nodes can have value if parse_embed_pcdata was used if (node->value) indent_flags = 0; node = node->first_child; depth++; continue; } } else if (PUGI_IMPL_NODETYPE(node) == node_document) { indent_flags = indent_indent; if (node->first_child) { node = node->first_child; continue; } } else { node_output_simple(writer, node, flags); indent_flags = indent_newline | indent_indent; } } // continue to the next node while (node != root) { if (node->next_sibling) { node = node->next_sibling; break; } node = node->parent; // write closing node if (PUGI_IMPL_NODETYPE(node) == node_element) { depth--; if ((indent_flags & indent_newline) && (flags & format_raw) == 0) writer.write('\n'); if ((indent_flags & indent_indent) && indent_length) text_output_indent(writer, indent, indent_length, depth); node_output_end(writer, node); indent_flags = indent_newline | indent_indent; } } } while (node != root); if ((indent_flags & indent_newline) && (flags & format_raw) == 0) writer.write('\n'); } PUGI_IMPL_FN bool has_declaration(xml_node_struct* node) { for (xml_node_struct* child = node->first_child; child; child = child->next_sibling) { xml_node_type type = PUGI_IMPL_NODETYPE(child); if (type == node_declaration) return true; if (type == node_element) return false; } return false; } PUGI_IMPL_FN bool is_attribute_of(xml_attribute_struct* attr, xml_node_struct* node) { for (xml_attribute_struct* a = node->first_attribute; a; a = a->next_attribute) if (a == attr) return true; return false; } PUGI_IMPL_FN bool allow_insert_attribute(xml_node_type parent) { return parent == node_element || parent == node_declaration; } PUGI_IMPL_FN bool allow_insert_child(xml_node_type parent, xml_node_type child) { if (parent != node_document && parent != node_element) return false; if (child == node_document || child == node_null) return false; if (parent != node_document && (child == node_declaration || child == node_doctype)) return false; return true; } PUGI_IMPL_FN bool allow_move(xml_node parent, xml_node child) { // check that child can be a child of parent if (!allow_insert_child(parent.type(), child.type())) return false; // check that node is not moved between documents if (parent.root() != child.root()) return false; // check that new parent is not in the child subtree xml_node cur = parent; while (cur) { if (cur == child) return false; cur = cur.parent(); } return true; } template PUGI_IMPL_FN void node_copy_string(String& dest, Header& header, uintptr_t header_mask, char_t* source, Header& source_header, xml_allocator* alloc) { assert(!dest && (header & header_mask) == 0); // copies are performed into fresh nodes if (source) { if (alloc && (source_header & header_mask) == 0) { dest = source; // since strcpy_insitu can reuse document buffer memory we need to mark both source and dest as shared header |= xml_memory_page_contents_shared_mask; source_header |= xml_memory_page_contents_shared_mask; } else strcpy_insitu(dest, header, header_mask, source, strlength(source)); } } PUGI_IMPL_FN void node_copy_contents(xml_node_struct* dn, xml_node_struct* sn, xml_allocator* shared_alloc) { node_copy_string(dn->name, dn->header, xml_memory_page_name_allocated_mask, sn->name, sn->header, shared_alloc); node_copy_string(dn->value, dn->header, xml_memory_page_value_allocated_mask, sn->value, sn->header, shared_alloc); for (xml_attribute_struct* sa = sn->first_attribute; sa; sa = sa->next_attribute) { xml_attribute_struct* da = append_new_attribute(dn, get_allocator(dn)); if (da) { node_copy_string(da->name, da->header, xml_memory_page_name_allocated_mask, sa->name, sa->header, shared_alloc); node_copy_string(da->value, da->header, xml_memory_page_value_allocated_mask, sa->value, sa->header, shared_alloc); } } } PUGI_IMPL_FN void node_copy_tree(xml_node_struct* dn, xml_node_struct* sn) { xml_allocator& alloc = get_allocator(dn); xml_allocator* shared_alloc = (&alloc == &get_allocator(sn)) ? &alloc : NULL; node_copy_contents(dn, sn, shared_alloc); xml_node_struct* dit = dn; xml_node_struct* sit = sn->first_child; while (sit && sit != sn) { // loop invariant: dit is inside the subtree rooted at dn assert(dit); // when a tree is copied into one of the descendants, we need to skip that subtree to avoid an infinite loop if (sit != dn) { xml_node_struct* copy = append_new_node(dit, alloc, PUGI_IMPL_NODETYPE(sit)); if (copy) { node_copy_contents(copy, sit, shared_alloc); if (sit->first_child) { dit = copy; sit = sit->first_child; continue; } } } // continue to the next node do { if (sit->next_sibling) { sit = sit->next_sibling; break; } sit = sit->parent; dit = dit->parent; // loop invariant: dit is inside the subtree rooted at dn while sit is inside sn assert(sit == sn || dit); } while (sit != sn); } assert(!sit || dit == dn->parent); } PUGI_IMPL_FN void node_copy_attribute(xml_attribute_struct* da, xml_attribute_struct* sa) { xml_allocator& alloc = get_allocator(da); xml_allocator* shared_alloc = (&alloc == &get_allocator(sa)) ? &alloc : NULL; node_copy_string(da->name, da->header, xml_memory_page_name_allocated_mask, sa->name, sa->header, shared_alloc); node_copy_string(da->value, da->header, xml_memory_page_value_allocated_mask, sa->value, sa->header, shared_alloc); } inline bool is_text_node(xml_node_struct* node) { xml_node_type type = PUGI_IMPL_NODETYPE(node); return type == node_pcdata || type == node_cdata; } // get value with conversion functions template PUGI_IMPL_FN PUGI_IMPL_UNSIGNED_OVERFLOW U string_to_integer(const char_t* value, U minv, U maxv) { U result = 0; const char_t* s = value; while (PUGI_IMPL_IS_CHARTYPE(*s, ct_space)) s++; bool negative = (*s == '-'); s += (*s == '+' || *s == '-'); bool overflow = false; if (s[0] == '0' && (s[1] | ' ') == 'x') { s += 2; // since overflow detection relies on length of the sequence skip leading zeros while (*s == '0') s++; const char_t* start = s; for (;;) { if (static_cast(*s - '0') < 10) result = result * 16 + (*s - '0'); else if (static_cast((*s | ' ') - 'a') < 6) result = result * 16 + ((*s | ' ') - 'a' + 10); else break; s++; } size_t digits = static_cast(s - start); overflow = digits > sizeof(U) * 2; } else { // since overflow detection relies on length of the sequence skip leading zeros while (*s == '0') s++; const char_t* start = s; for (;;) { if (static_cast(*s - '0') < 10) result = result * 10 + (*s - '0'); else break; s++; } size_t digits = static_cast(s - start); PUGI_IMPL_STATIC_ASSERT(sizeof(U) == 8 || sizeof(U) == 4 || sizeof(U) == 2); const size_t max_digits10 = sizeof(U) == 8 ? 20 : sizeof(U) == 4 ? 10 : 5; const char_t max_lead = sizeof(U) == 8 ? '1' : sizeof(U) == 4 ? '4' : '6'; const size_t high_bit = sizeof(U) * 8 - 1; overflow = digits >= max_digits10 && !(digits == max_digits10 && (*start < max_lead || (*start == max_lead && result >> high_bit))); } if (negative) { // Workaround for crayc++ CC-3059: Expected no overflow in routine. #ifdef _CRAYC return (overflow || result > ~minv + 1) ? minv : ~result + 1; #else return (overflow || result > 0 - minv) ? minv : 0 - result; #endif } else return (overflow || result > maxv) ? maxv : result; } PUGI_IMPL_FN int get_value_int(const char_t* value) { return string_to_integer(value, static_cast(INT_MIN), INT_MAX); } PUGI_IMPL_FN unsigned int get_value_uint(const char_t* value) { return string_to_integer(value, 0, UINT_MAX); } PUGI_IMPL_FN double get_value_double(const char_t* value) { #ifdef PUGIXML_WCHAR_MODE return wcstod(value, NULL); #else return strtod(value, NULL); #endif } PUGI_IMPL_FN float get_value_float(const char_t* value) { #ifdef PUGIXML_WCHAR_MODE return static_cast(wcstod(value, NULL)); #else return static_cast(strtod(value, NULL)); #endif } PUGI_IMPL_FN bool get_value_bool(const char_t* value) { // only look at first char char_t first = *value; // 1*, t* (true), T* (True), y* (yes), Y* (YES) return (first == '1' || first == 't' || first == 'T' || first == 'y' || first == 'Y'); } #ifdef PUGIXML_HAS_LONG_LONG PUGI_IMPL_FN long long get_value_llong(const char_t* value) { return string_to_integer(value, static_cast(LLONG_MIN), LLONG_MAX); } PUGI_IMPL_FN unsigned long long get_value_ullong(const char_t* value) { return string_to_integer(value, 0, ULLONG_MAX); } #endif template PUGI_IMPL_FN PUGI_IMPL_UNSIGNED_OVERFLOW char_t* integer_to_string(char_t* begin, char_t* end, U value, bool negative) { char_t* result = end - 1; U rest = negative ? 0 - value : value; do { *result-- = static_cast('0' + (rest % 10)); rest /= 10; } while (rest); assert(result >= begin); (void)begin; *result = '-'; return result + !negative; } // set value with conversion functions template PUGI_IMPL_FN bool set_value_ascii(String& dest, Header& header, uintptr_t header_mask, char* buf) { #ifdef PUGIXML_WCHAR_MODE char_t wbuf[128]; assert(strlen(buf) < sizeof(wbuf) / sizeof(wbuf[0])); size_t offset = 0; for (; buf[offset]; ++offset) wbuf[offset] = buf[offset]; return strcpy_insitu(dest, header, header_mask, wbuf, offset); #else return strcpy_insitu(dest, header, header_mask, buf, strlen(buf)); #endif } template PUGI_IMPL_FN bool set_value_integer(String& dest, Header& header, uintptr_t header_mask, U value, bool negative) { char_t buf[64]; char_t* end = buf + sizeof(buf) / sizeof(buf[0]); char_t* begin = integer_to_string(buf, end, value, negative); return strcpy_insitu(dest, header, header_mask, begin, end - begin); } template PUGI_IMPL_FN bool set_value_convert(String& dest, Header& header, uintptr_t header_mask, float value, int precision) { char buf[128]; PUGI_IMPL_SNPRINTF(buf, "%.*g", precision, double(value)); return set_value_ascii(dest, header, header_mask, buf); } template PUGI_IMPL_FN bool set_value_convert(String& dest, Header& header, uintptr_t header_mask, double value, int precision) { char buf[128]; PUGI_IMPL_SNPRINTF(buf, "%.*g", precision, value); return set_value_ascii(dest, header, header_mask, buf); } template PUGI_IMPL_FN bool set_value_bool(String& dest, Header& header, uintptr_t header_mask, bool value) { return strcpy_insitu(dest, header, header_mask, value ? PUGIXML_TEXT("true") : PUGIXML_TEXT("false"), value ? 4 : 5); } PUGI_IMPL_FN xml_parse_result load_buffer_impl(xml_document_struct* doc, xml_node_struct* root, void* contents, size_t size, unsigned int options, xml_encoding encoding, bool is_mutable, bool own, char_t** out_buffer) { // check input buffer if (!contents && size) return make_parse_result(status_io_error); // get actual encoding xml_encoding buffer_encoding = impl::get_buffer_encoding(encoding, contents, size); // if convert_buffer below throws bad_alloc, we still need to deallocate contents if we own it auto_deleter contents_guard(own ? contents : NULL, xml_memory::deallocate); // get private buffer char_t* buffer = NULL; size_t length = 0; // coverity[var_deref_model] if (!impl::convert_buffer(buffer, length, buffer_encoding, contents, size, is_mutable)) return impl::make_parse_result(status_out_of_memory); // after this we either deallocate contents (below) or hold on to it via doc->buffer, so we don't need to guard it contents_guard.release(); // delete original buffer if we performed a conversion if (own && buffer != contents && contents) impl::xml_memory::deallocate(contents); // grab onto buffer if it's our buffer, user is responsible for deallocating contents himself if (own || buffer != contents) *out_buffer = buffer; // store buffer for offset_debug doc->buffer = buffer; // parse xml_parse_result res = impl::xml_parser::parse(buffer, length, doc, root, options); // remember encoding res.encoding = buffer_encoding; return res; } template PUGI_IMPL_FN xml_parse_status convert_file_size(T length, size_t& out_result) { // check for I/O errors if (length < 0) return status_io_error; // check for overflow size_t result = static_cast(length); if (static_cast(result) != length) return status_out_of_memory; out_result = result; return status_ok; } // we need to get length of entire file to load it in memory; the only (relatively) sane way to do it is via seek/tell trick PUGI_IMPL_FN xml_parse_status get_file_size(FILE* file, size_t& out_result) { #if defined(__linux__) || defined(__APPLE__) // this simultaneously retrieves the file size and file mode (to guard against loading non-files) struct stat st; if (fstat(fileno(file), &st) != 0) return status_io_error; // anything that's not a regular file doesn't have a coherent length if (!S_ISREG(st.st_mode)) return status_io_error; xml_parse_status status = convert_file_size(st.st_size, out_result); #elif defined(PUGI_IMPL_MSVC_CRT_VERSION) && PUGI_IMPL_MSVC_CRT_VERSION >= 1400 // there are 64-bit versions of fseek/ftell, let's use them _fseeki64(file, 0, SEEK_END); __int64 length = _ftelli64(file); _fseeki64(file, 0, SEEK_SET); xml_parse_status status = convert_file_size(length, out_result); #elif defined(__MINGW32__) && !defined(__NO_MINGW_LFS) && (!defined(__STRICT_ANSI__) || defined(__MINGW64_VERSION_MAJOR)) // there are 64-bit versions of fseek/ftell, let's use them fseeko64(file, 0, SEEK_END); off64_t length = ftello64(file); fseeko64(file, 0, SEEK_SET); xml_parse_status status = convert_file_size(length, out_result); #else // if this is a 32-bit OS, long is enough; if this is a unix system, long is 64-bit, which is enough; otherwise we can't do anything anyway. fseek(file, 0, SEEK_END); long length = ftell(file); fseek(file, 0, SEEK_SET); xml_parse_status status = convert_file_size(length, out_result); #endif return status; } // This function assumes that buffer has extra sizeof(char_t) writable bytes after size PUGI_IMPL_FN size_t zero_terminate_buffer(void* buffer, size_t size, xml_encoding encoding) { // We only need to zero-terminate if encoding conversion does not do it for us #ifdef PUGIXML_WCHAR_MODE xml_encoding wchar_encoding = get_wchar_encoding(); if (encoding == wchar_encoding || need_endian_swap_utf(encoding, wchar_encoding)) { size_t length = size / sizeof(char_t); static_cast(buffer)[length] = 0; return (length + 1) * sizeof(char_t); } #else if (encoding == encoding_utf8) { static_cast(buffer)[size] = 0; return size + 1; } #endif return size; } PUGI_IMPL_FN xml_parse_result load_file_impl(xml_document_struct* doc, FILE* file, unsigned int options, xml_encoding encoding, char_t** out_buffer) { if (!file) return make_parse_result(status_file_not_found); // get file size (can result in I/O errors) size_t size = 0; xml_parse_status size_status = get_file_size(file, size); if (size_status != status_ok) return make_parse_result(size_status); size_t max_suffix_size = sizeof(char_t); // allocate buffer for the whole file char* contents = static_cast(xml_memory::allocate(size + max_suffix_size)); if (!contents) return make_parse_result(status_out_of_memory); // read file in memory size_t read_size = fread(contents, 1, size, file); if (read_size != size) { xml_memory::deallocate(contents); return make_parse_result(status_io_error); } xml_encoding real_encoding = get_buffer_encoding(encoding, contents, size); return load_buffer_impl(doc, doc, contents, zero_terminate_buffer(contents, size, real_encoding), options, real_encoding, true, true, out_buffer); } PUGI_IMPL_FN void close_file(FILE* file) { fclose(file); } #ifndef PUGIXML_NO_STL template struct xml_stream_chunk { static xml_stream_chunk* create() { void* memory = xml_memory::allocate(sizeof(xml_stream_chunk)); if (!memory) return NULL; return new (memory) xml_stream_chunk(); } static void destroy(xml_stream_chunk* chunk) { // free chunk chain while (chunk) { xml_stream_chunk* next_ = chunk->next; xml_memory::deallocate(chunk); chunk = next_; } } xml_stream_chunk(): next(NULL), size(0) { } xml_stream_chunk* next; size_t size; T data[xml_memory_page_size / sizeof(T)]; }; template PUGI_IMPL_FN xml_parse_status load_stream_data_noseek(std::basic_istream& stream, void** out_buffer, size_t* out_size) { auto_deleter > chunks(NULL, xml_stream_chunk::destroy); // read file to a chunk list size_t total = 0; xml_stream_chunk* last = NULL; while (!stream.eof()) { // allocate new chunk xml_stream_chunk* chunk = xml_stream_chunk::create(); if (!chunk) return status_out_of_memory; // append chunk to list if (last) last = last->next = chunk; else chunks.data = last = chunk; // read data to chunk stream.read(chunk->data, static_cast(sizeof(chunk->data) / sizeof(T))); chunk->size = static_cast(stream.gcount()) * sizeof(T); // read may set failbit | eofbit in case gcount() is less than read length, so check for other I/O errors if (stream.bad() || (!stream.eof() && stream.fail())) return status_io_error; // guard against huge files (chunk size is small enough to make this overflow check work) if (total + chunk->size < total) return status_out_of_memory; total += chunk->size; } size_t max_suffix_size = sizeof(char_t); // copy chunk list to a contiguous buffer char* buffer = static_cast(xml_memory::allocate(total + max_suffix_size)); if (!buffer) return status_out_of_memory; char* write = buffer; for (xml_stream_chunk* chunk = chunks.data; chunk; chunk = chunk->next) { assert(write + chunk->size <= buffer + total); memcpy(write, chunk->data, chunk->size); write += chunk->size; } assert(write == buffer + total); // return buffer *out_buffer = buffer; *out_size = total; return status_ok; } template PUGI_IMPL_FN xml_parse_status load_stream_data_seek(std::basic_istream& stream, void** out_buffer, size_t* out_size) { // get length of remaining data in stream typename std::basic_istream::pos_type pos = stream.tellg(); stream.seekg(0, std::ios::end); std::streamoff length = stream.tellg() - pos; stream.seekg(pos); if (stream.fail() || pos < 0) return status_io_error; // guard against huge files size_t read_length = static_cast(length); if (static_cast(read_length) != length || length < 0) return status_out_of_memory; size_t max_suffix_size = sizeof(char_t); // read stream data into memory (guard against stream exceptions with buffer holder) auto_deleter buffer(xml_memory::allocate(read_length * sizeof(T) + max_suffix_size), xml_memory::deallocate); if (!buffer.data) return status_out_of_memory; stream.read(static_cast(buffer.data), static_cast(read_length)); // read may set failbit | eofbit in case gcount() is less than read_length (i.e. line ending conversion), so check for other I/O errors if (stream.bad() || (!stream.eof() && stream.fail())) return status_io_error; // return buffer size_t actual_length = static_cast(stream.gcount()); assert(actual_length <= read_length); *out_buffer = buffer.release(); *out_size = actual_length * sizeof(T); return status_ok; } template PUGI_IMPL_FN xml_parse_result load_stream_impl(xml_document_struct* doc, std::basic_istream& stream, unsigned int options, xml_encoding encoding, char_t** out_buffer) { void* buffer = NULL; size_t size = 0; xml_parse_status status = status_ok; // if stream has an error bit set, bail out (otherwise tellg() can fail and we'll clear error bits) if (stream.fail()) return make_parse_result(status_io_error); // load stream to memory (using seek-based implementation if possible, since it's faster and takes less memory) if (stream.tellg() < 0) { stream.clear(); // clear error flags that could be set by a failing tellg status = load_stream_data_noseek(stream, &buffer, &size); } else status = load_stream_data_seek(stream, &buffer, &size); if (status != status_ok) return make_parse_result(status); xml_encoding real_encoding = get_buffer_encoding(encoding, buffer, size); return load_buffer_impl(doc, doc, buffer, zero_terminate_buffer(buffer, size, real_encoding), options, real_encoding, true, true, out_buffer); } #endif #if defined(PUGI_IMPL_MSVC_CRT_VERSION) || defined(__BORLANDC__) || (defined(__MINGW32__) && (!defined(__STRICT_ANSI__) || defined(__MINGW64_VERSION_MAJOR))) PUGI_IMPL_FN FILE* open_file_wide(const wchar_t* path, const wchar_t* mode) { #ifdef PUGIXML_NO_STL // ensure these symbols are consistently referenced to avoid 'unreferenced function' warnings // note that generally these functions are used in STL builds, but PUGIXML_NO_STL leaves the only usage in convert_path_heap (void)&as_utf8_begin; (void)&as_utf8_end; (void)&strlength_wide; #endif #if defined(PUGI_IMPL_MSVC_CRT_VERSION) && PUGI_IMPL_MSVC_CRT_VERSION >= 1400 FILE* file = NULL; return _wfopen_s(&file, path, mode) == 0 ? file : NULL; #else return _wfopen(path, mode); #endif } #else PUGI_IMPL_FN char* convert_path_heap(const wchar_t* str) { assert(str); // first pass: get length in utf8 characters size_t length = strlength_wide(str); size_t size = as_utf8_begin(str, length); // allocate resulting string char* result = static_cast(xml_memory::allocate(size + 1)); if (!result) return NULL; // second pass: convert to utf8 as_utf8_end(result, size, str, length); // zero-terminate result[size] = 0; return result; } PUGI_IMPL_FN FILE* open_file_wide(const wchar_t* path, const wchar_t* mode) { // there is no standard function to open wide paths, so our best bet is to try utf8 path char* path_utf8 = convert_path_heap(path); if (!path_utf8) return NULL; // convert mode to ASCII (we mirror _wfopen interface) char mode_ascii[4] = {0}; for (size_t i = 0; mode[i]; ++i) mode_ascii[i] = static_cast(mode[i]); // try to open the utf8 path FILE* result = fopen(path_utf8, mode_ascii); // free dummy buffer xml_memory::deallocate(path_utf8); return result; } #endif PUGI_IMPL_FN FILE* open_file(const char* path, const char* mode) { #if defined(PUGI_IMPL_MSVC_CRT_VERSION) && PUGI_IMPL_MSVC_CRT_VERSION >= 1400 FILE* file = NULL; return fopen_s(&file, path, mode) == 0 ? file : NULL; #else return fopen(path, mode); #endif } PUGI_IMPL_FN bool save_file_impl(const xml_document& doc, FILE* file, const char_t* indent, unsigned int flags, xml_encoding encoding) { if (!file) return false; xml_writer_file writer(file); doc.save(writer, indent, flags, encoding); return fflush(file) == 0 && ferror(file) == 0; } struct name_null_sentry { xml_node_struct* node; char_t* name; name_null_sentry(xml_node_struct* node_): node(node_), name(node_->name) { node->name = NULL; } ~name_null_sentry() { node->name = name; } }; PUGI_IMPL_NS_END namespace pugi { PUGI_IMPL_FN xml_writer::~xml_writer() { } PUGI_IMPL_FN xml_writer_file::xml_writer_file(void* file_): file(file_) { } PUGI_IMPL_FN void xml_writer_file::write(const void* data, size_t size) { size_t result = fwrite(data, 1, size, static_cast(file)); (void)!result; // unfortunately we can't do proper error handling here } #ifndef PUGIXML_NO_STL PUGI_IMPL_FN xml_writer_stream::xml_writer_stream(std::basic_ostream& stream): narrow_stream(&stream), wide_stream(NULL) { } PUGI_IMPL_FN xml_writer_stream::xml_writer_stream(std::basic_ostream& stream): narrow_stream(NULL), wide_stream(&stream) { } PUGI_IMPL_FN void xml_writer_stream::write(const void* data, size_t size) { if (narrow_stream) { assert(!wide_stream); narrow_stream->write(reinterpret_cast(data), static_cast(size)); } else { assert(wide_stream); assert(size % sizeof(wchar_t) == 0); wide_stream->write(reinterpret_cast(data), static_cast(size / sizeof(wchar_t))); } } #endif PUGI_IMPL_FN xml_tree_walker::xml_tree_walker(): _depth(0) { } PUGI_IMPL_FN xml_tree_walker::~xml_tree_walker() { } PUGI_IMPL_FN int xml_tree_walker::depth() const { return _depth; } PUGI_IMPL_FN bool xml_tree_walker::begin(xml_node&) { return true; } PUGI_IMPL_FN bool xml_tree_walker::end(xml_node&) { return true; } PUGI_IMPL_FN xml_attribute::xml_attribute(): _attr(NULL) { } PUGI_IMPL_FN xml_attribute::xml_attribute(xml_attribute_struct* attr): _attr(attr) { } PUGI_IMPL_FN static void unspecified_bool_xml_attribute(xml_attribute***) { } PUGI_IMPL_FN xml_attribute::operator xml_attribute::unspecified_bool_type() const { return _attr ? unspecified_bool_xml_attribute : NULL; } PUGI_IMPL_FN bool xml_attribute::operator!() const { return !_attr; } PUGI_IMPL_FN bool xml_attribute::operator==(const xml_attribute& r) const { return (_attr == r._attr); } PUGI_IMPL_FN bool xml_attribute::operator!=(const xml_attribute& r) const { return (_attr != r._attr); } PUGI_IMPL_FN bool xml_attribute::operator<(const xml_attribute& r) const { return (_attr < r._attr); } PUGI_IMPL_FN bool xml_attribute::operator>(const xml_attribute& r) const { return (_attr > r._attr); } PUGI_IMPL_FN bool xml_attribute::operator<=(const xml_attribute& r) const { return (_attr <= r._attr); } PUGI_IMPL_FN bool xml_attribute::operator>=(const xml_attribute& r) const { return (_attr >= r._attr); } PUGI_IMPL_FN xml_attribute xml_attribute::next_attribute() const { if (!_attr) return xml_attribute(); return xml_attribute(_attr->next_attribute); } PUGI_IMPL_FN xml_attribute xml_attribute::previous_attribute() const { if (!_attr) return xml_attribute(); xml_attribute_struct* prev = _attr->prev_attribute_c; return prev->next_attribute ? xml_attribute(prev) : xml_attribute(); } PUGI_IMPL_FN const char_t* xml_attribute::as_string(const char_t* def) const { if (!_attr) return def; const char_t* value = _attr->value; return value ? value : def; } PUGI_IMPL_FN int xml_attribute::as_int(int def) const { if (!_attr) return def; const char_t* value = _attr->value; return value ? impl::get_value_int(value) : def; } PUGI_IMPL_FN unsigned int xml_attribute::as_uint(unsigned int def) const { if (!_attr) return def; const char_t* value = _attr->value; return value ? impl::get_value_uint(value) : def; } PUGI_IMPL_FN double xml_attribute::as_double(double def) const { if (!_attr) return def; const char_t* value = _attr->value; return value ? impl::get_value_double(value) : def; } PUGI_IMPL_FN float xml_attribute::as_float(float def) const { if (!_attr) return def; const char_t* value = _attr->value; return value ? impl::get_value_float(value) : def; } PUGI_IMPL_FN bool xml_attribute::as_bool(bool def) const { if (!_attr) return def; const char_t* value = _attr->value; return value ? impl::get_value_bool(value) : def; } #ifdef PUGIXML_HAS_LONG_LONG PUGI_IMPL_FN long long xml_attribute::as_llong(long long def) const { if (!_attr) return def; const char_t* value = _attr->value; return value ? impl::get_value_llong(value) : def; } PUGI_IMPL_FN unsigned long long xml_attribute::as_ullong(unsigned long long def) const { if (!_attr) return def; const char_t* value = _attr->value; return value ? impl::get_value_ullong(value) : def; } #endif PUGI_IMPL_FN bool xml_attribute::empty() const { return !_attr; } PUGI_IMPL_FN const char_t* xml_attribute::name() const { if (!_attr) return PUGIXML_TEXT(""); const char_t* name = _attr->name; return name ? name : PUGIXML_TEXT(""); } PUGI_IMPL_FN const char_t* xml_attribute::value() const { if (!_attr) return PUGIXML_TEXT(""); const char_t* value = _attr->value; return value ? value : PUGIXML_TEXT(""); } PUGI_IMPL_FN size_t xml_attribute::hash_value() const { return reinterpret_cast(_attr) / sizeof(xml_attribute_struct); } PUGI_IMPL_FN xml_attribute_struct* xml_attribute::internal_object() const { return _attr; } PUGI_IMPL_FN xml_attribute& xml_attribute::operator=(const char_t* rhs) { set_value(rhs); return *this; } PUGI_IMPL_FN xml_attribute& xml_attribute::operator=(int rhs) { set_value(rhs); return *this; } PUGI_IMPL_FN xml_attribute& xml_attribute::operator=(unsigned int rhs) { set_value(rhs); return *this; } PUGI_IMPL_FN xml_attribute& xml_attribute::operator=(long rhs) { set_value(rhs); return *this; } PUGI_IMPL_FN xml_attribute& xml_attribute::operator=(unsigned long rhs) { set_value(rhs); return *this; } PUGI_IMPL_FN xml_attribute& xml_attribute::operator=(double rhs) { set_value(rhs); return *this; } PUGI_IMPL_FN xml_attribute& xml_attribute::operator=(float rhs) { set_value(rhs); return *this; } PUGI_IMPL_FN xml_attribute& xml_attribute::operator=(bool rhs) { set_value(rhs); return *this; } #ifdef PUGIXML_HAS_STRING_VIEW PUGI_IMPL_FN xml_attribute& xml_attribute::operator=(string_view_t rhs) { set_value(rhs); return *this; } #endif #ifdef PUGIXML_HAS_LONG_LONG PUGI_IMPL_FN xml_attribute& xml_attribute::operator=(long long rhs) { set_value(rhs); return *this; } PUGI_IMPL_FN xml_attribute& xml_attribute::operator=(unsigned long long rhs) { set_value(rhs); return *this; } #endif PUGI_IMPL_FN bool xml_attribute::set_name(const char_t* rhs) { if (!_attr) return false; return impl::strcpy_insitu(_attr->name, _attr->header, impl::xml_memory_page_name_allocated_mask, rhs, impl::strlength(rhs)); } PUGI_IMPL_FN bool xml_attribute::set_name(const char_t* rhs, size_t size) { if (!_attr) return false; return impl::strcpy_insitu(_attr->name, _attr->header, impl::xml_memory_page_name_allocated_mask, rhs, size); } #ifdef PUGIXML_HAS_STRING_VIEW PUGI_IMPL_FN bool xml_attribute::set_name(string_view_t rhs) { if (!_attr) return false; return impl::strcpy_insitu(_attr->name, _attr->header, impl::xml_memory_page_name_allocated_mask, rhs.data(), rhs.size()); } #endif PUGI_IMPL_FN bool xml_attribute::set_value(const char_t* rhs) { if (!_attr) return false; return impl::strcpy_insitu(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, impl::strlength(rhs)); } PUGI_IMPL_FN bool xml_attribute::set_value(const char_t* rhs, size_t size) { if (!_attr) return false; return impl::strcpy_insitu(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, size); } #ifdef PUGIXML_HAS_STRING_VIEW PUGI_IMPL_FN bool xml_attribute::set_value(string_view_t rhs) { if (!_attr) return false; return impl::strcpy_insitu(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs.data(), rhs.size()); } #endif PUGI_IMPL_FN bool xml_attribute::set_value(int rhs) { if (!_attr) return false; return impl::set_value_integer(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0); } PUGI_IMPL_FN bool xml_attribute::set_value(unsigned int rhs) { if (!_attr) return false; return impl::set_value_integer(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, false); } PUGI_IMPL_FN bool xml_attribute::set_value(long rhs) { if (!_attr) return false; return impl::set_value_integer(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0); } PUGI_IMPL_FN bool xml_attribute::set_value(unsigned long rhs) { if (!_attr) return false; return impl::set_value_integer(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, false); } PUGI_IMPL_FN bool xml_attribute::set_value(double rhs) { if (!_attr) return false; return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, default_double_precision); } PUGI_IMPL_FN bool xml_attribute::set_value(double rhs, int precision) { if (!_attr) return false; return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, precision); } PUGI_IMPL_FN bool xml_attribute::set_value(float rhs) { if (!_attr) return false; return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, default_float_precision); } PUGI_IMPL_FN bool xml_attribute::set_value(float rhs, int precision) { if (!_attr) return false; return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, precision); } PUGI_IMPL_FN bool xml_attribute::set_value(bool rhs) { if (!_attr) return false; return impl::set_value_bool(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs); } #ifdef PUGIXML_HAS_LONG_LONG PUGI_IMPL_FN bool xml_attribute::set_value(long long rhs) { if (!_attr) return false; return impl::set_value_integer(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0); } PUGI_IMPL_FN bool xml_attribute::set_value(unsigned long long rhs) { if (!_attr) return false; return impl::set_value_integer(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, false); } #endif #ifdef __BORLANDC__ PUGI_IMPL_FN bool operator&&(const xml_attribute& lhs, bool rhs) { return (bool)lhs && rhs; } PUGI_IMPL_FN bool operator||(const xml_attribute& lhs, bool rhs) { return (bool)lhs || rhs; } #endif PUGI_IMPL_FN xml_node::xml_node(): _root(NULL) { } PUGI_IMPL_FN xml_node::xml_node(xml_node_struct* p): _root(p) { } PUGI_IMPL_FN static void unspecified_bool_xml_node(xml_node***) { } PUGI_IMPL_FN xml_node::operator xml_node::unspecified_bool_type() const { return _root ? unspecified_bool_xml_node : NULL; } PUGI_IMPL_FN bool xml_node::operator!() const { return !_root; } PUGI_IMPL_FN xml_node::iterator xml_node::begin() const { return iterator(_root ? _root->first_child + 0 : NULL, _root); } PUGI_IMPL_FN xml_node::iterator xml_node::end() const { return iterator(NULL, _root); } PUGI_IMPL_FN xml_node::attribute_iterator xml_node::attributes_begin() const { return attribute_iterator(_root ? _root->first_attribute + 0 : NULL, _root); } PUGI_IMPL_FN xml_node::attribute_iterator xml_node::attributes_end() const { return attribute_iterator(NULL, _root); } PUGI_IMPL_FN xml_object_range xml_node::children() const { return xml_object_range(begin(), end()); } PUGI_IMPL_FN xml_object_range xml_node::children(const char_t* name_) const { return xml_object_range(xml_named_node_iterator(child(name_)._root, _root, name_), xml_named_node_iterator(NULL, _root, name_)); } PUGI_IMPL_FN xml_object_range xml_node::attributes() const { return xml_object_range(attributes_begin(), attributes_end()); } PUGI_IMPL_FN bool xml_node::operator==(const xml_node& r) const { return (_root == r._root); } PUGI_IMPL_FN bool xml_node::operator!=(const xml_node& r) const { return (_root != r._root); } PUGI_IMPL_FN bool xml_node::operator<(const xml_node& r) const { return (_root < r._root); } PUGI_IMPL_FN bool xml_node::operator>(const xml_node& r) const { return (_root > r._root); } PUGI_IMPL_FN bool xml_node::operator<=(const xml_node& r) const { return (_root <= r._root); } PUGI_IMPL_FN bool xml_node::operator>=(const xml_node& r) const { return (_root >= r._root); } PUGI_IMPL_FN bool xml_node::empty() const { return !_root; } PUGI_IMPL_FN const char_t* xml_node::name() const { if (!_root) return PUGIXML_TEXT(""); const char_t* name = _root->name; return name ? name : PUGIXML_TEXT(""); } PUGI_IMPL_FN xml_node_type xml_node::type() const { return _root ? PUGI_IMPL_NODETYPE(_root) : node_null; } PUGI_IMPL_FN const char_t* xml_node::value() const { if (!_root) return PUGIXML_TEXT(""); const char_t* value = _root->value; return value ? value : PUGIXML_TEXT(""); } PUGI_IMPL_FN xml_node xml_node::child(const char_t* name_) const { if (!_root) return xml_node(); for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) { const char_t* iname = i->name; if (iname && impl::strequal(name_, iname)) return xml_node(i); } return xml_node(); } PUGI_IMPL_FN xml_attribute xml_node::attribute(const char_t* name_) const { if (!_root) return xml_attribute(); for (xml_attribute_struct* i = _root->first_attribute; i; i = i->next_attribute) { const char_t* iname = i->name; if (iname && impl::strequal(name_, iname)) return xml_attribute(i); } return xml_attribute(); } PUGI_IMPL_FN xml_node xml_node::next_sibling(const char_t* name_) const { if (!_root) return xml_node(); for (xml_node_struct* i = _root->next_sibling; i; i = i->next_sibling) { const char_t* iname = i->name; if (iname && impl::strequal(name_, iname)) return xml_node(i); } return xml_node(); } PUGI_IMPL_FN xml_node xml_node::next_sibling() const { return _root ? xml_node(_root->next_sibling) : xml_node(); } PUGI_IMPL_FN xml_node xml_node::previous_sibling(const char_t* name_) const { if (!_root) return xml_node(); for (xml_node_struct* i = _root->prev_sibling_c; i->next_sibling; i = i->prev_sibling_c) { const char_t* iname = i->name; if (iname && impl::strequal(name_, iname)) return xml_node(i); } return xml_node(); } #ifdef PUGIXML_HAS_STRING_VIEW PUGI_IMPL_FN xml_node xml_node::child(string_view_t name_) const { if (!_root) return xml_node(); for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) { const char_t* iname = i->name; if (iname && impl::stringview_equal(name_, iname)) return xml_node(i); } return xml_node(); } PUGI_IMPL_FN xml_attribute xml_node::attribute(string_view_t name_) const { if (!_root) return xml_attribute(); for (xml_attribute_struct* i = _root->first_attribute; i; i = i->next_attribute) { const char_t* iname = i->name; if (iname && impl::stringview_equal(name_, iname)) return xml_attribute(i); } return xml_attribute(); } PUGI_IMPL_FN xml_node xml_node::next_sibling(string_view_t name_) const { if (!_root) return xml_node(); for (xml_node_struct* i = _root->next_sibling; i; i = i->next_sibling) { const char_t* iname = i->name; if (iname && impl::stringview_equal(name_, iname)) return xml_node(i); } return xml_node(); } PUGI_IMPL_FN xml_node xml_node::previous_sibling(string_view_t name_) const { if (!_root) return xml_node(); for (xml_node_struct* i = _root->prev_sibling_c; i->next_sibling; i = i->prev_sibling_c) { const char_t* iname = i->name; if (iname && impl::stringview_equal(name_, iname)) return xml_node(i); } return xml_node(); } #endif PUGI_IMPL_FN xml_attribute xml_node::attribute(const char_t* name_, xml_attribute& hint_) const { xml_attribute_struct* hint = hint_._attr; // if hint is not an attribute of node, behavior is not defined assert(!hint || (_root && impl::is_attribute_of(hint, _root))); if (!_root) return xml_attribute(); // optimistically search from hint up until the end for (xml_attribute_struct* i = hint; i; i = i->next_attribute) { const char_t* iname = i->name; if (iname && impl::strequal(name_, iname)) { // update hint to maximize efficiency of searching for consecutive attributes hint_._attr = i->next_attribute; return xml_attribute(i); } } // wrap around and search from the first attribute until the hint // 'j' null pointer check is technically redundant, but it prevents a crash in case the assertion above fails for (xml_attribute_struct* j = _root->first_attribute; j && j != hint; j = j->next_attribute) { const char_t* jname = j->name; if (jname && impl::strequal(name_, jname)) { // update hint to maximize efficiency of searching for consecutive attributes hint_._attr = j->next_attribute; return xml_attribute(j); } } return xml_attribute(); } #ifdef PUGIXML_HAS_STRING_VIEW PUGI_IMPL_FN xml_attribute xml_node::attribute(string_view_t name_, xml_attribute& hint_) const { xml_attribute_struct* hint = hint_._attr; // if hint is not an attribute of node, behavior is not defined assert(!hint || (_root && impl::is_attribute_of(hint, _root))); if (!_root) return xml_attribute(); // optimistically search from hint up until the end for (xml_attribute_struct* i = hint; i; i = i->next_attribute) { const char_t* iname = i->name; if (iname && impl::stringview_equal(name_, iname)) { // update hint to maximize efficiency of searching for consecutive attributes hint_._attr = i->next_attribute; return xml_attribute(i); } } // wrap around and search from the first attribute until the hint // 'j' null pointer check is technically redundant, but it prevents a crash in case the assertion above fails for (xml_attribute_struct* j = _root->first_attribute; j && j != hint; j = j->next_attribute) { const char_t* jname = j->name; if (jname && impl::stringview_equal(name_, jname)) { // update hint to maximize efficiency of searching for consecutive attributes hint_._attr = j->next_attribute; return xml_attribute(j); } } return xml_attribute(); } #endif PUGI_IMPL_FN xml_node xml_node::previous_sibling() const { if (!_root) return xml_node(); xml_node_struct* prev = _root->prev_sibling_c; return prev->next_sibling ? xml_node(prev) : xml_node(); } PUGI_IMPL_FN xml_node xml_node::parent() const { return _root ? xml_node(_root->parent) : xml_node(); } PUGI_IMPL_FN xml_node xml_node::root() const { return _root ? xml_node(&impl::get_document(_root)) : xml_node(); } PUGI_IMPL_FN xml_text xml_node::text() const { return xml_text(_root); } PUGI_IMPL_FN const char_t* xml_node::child_value() const { if (!_root) return PUGIXML_TEXT(""); // element nodes can have value if parse_embed_pcdata was used if (PUGI_IMPL_NODETYPE(_root) == node_element && _root->value) return _root->value; for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) { const char_t* ivalue = i->value; if (impl::is_text_node(i) && ivalue) return ivalue; } return PUGIXML_TEXT(""); } PUGI_IMPL_FN const char_t* xml_node::child_value(const char_t* name_) const { return child(name_).child_value(); } PUGI_IMPL_FN xml_attribute xml_node::first_attribute() const { if (!_root) return xml_attribute(); return xml_attribute(_root->first_attribute); } PUGI_IMPL_FN xml_attribute xml_node::last_attribute() const { if (!_root) return xml_attribute(); xml_attribute_struct* first = _root->first_attribute; return first ? xml_attribute(first->prev_attribute_c) : xml_attribute(); } PUGI_IMPL_FN xml_node xml_node::first_child() const { if (!_root) return xml_node(); return xml_node(_root->first_child); } PUGI_IMPL_FN xml_node xml_node::last_child() const { if (!_root) return xml_node(); xml_node_struct* first = _root->first_child; return first ? xml_node(first->prev_sibling_c) : xml_node(); } PUGI_IMPL_FN bool xml_node::set_name(const char_t* rhs) { xml_node_type type_ = _root ? PUGI_IMPL_NODETYPE(_root) : node_null; if (type_ != node_element && type_ != node_pi && type_ != node_declaration) return false; return impl::strcpy_insitu(_root->name, _root->header, impl::xml_memory_page_name_allocated_mask, rhs, impl::strlength(rhs)); } PUGI_IMPL_FN bool xml_node::set_name(const char_t* rhs, size_t size) { xml_node_type type_ = _root ? PUGI_IMPL_NODETYPE(_root) : node_null; if (type_ != node_element && type_ != node_pi && type_ != node_declaration) return false; return impl::strcpy_insitu(_root->name, _root->header, impl::xml_memory_page_name_allocated_mask, rhs, size); } #ifdef PUGIXML_HAS_STRING_VIEW PUGI_IMPL_FN bool xml_node::set_name(string_view_t rhs) { xml_node_type type_ = _root ? PUGI_IMPL_NODETYPE(_root) : node_null; if (type_ != node_element && type_ != node_pi && type_ != node_declaration) return false; return impl::strcpy_insitu(_root->name, _root->header, impl::xml_memory_page_name_allocated_mask, rhs.data(), rhs.size()); } #endif PUGI_IMPL_FN bool xml_node::set_value(const char_t* rhs) { xml_node_type type_ = _root ? PUGI_IMPL_NODETYPE(_root) : node_null; if (type_ != node_pcdata && type_ != node_cdata && type_ != node_comment && type_ != node_pi && type_ != node_doctype) return false; return impl::strcpy_insitu(_root->value, _root->header, impl::xml_memory_page_value_allocated_mask, rhs, impl::strlength(rhs)); } PUGI_IMPL_FN bool xml_node::set_value(const char_t* rhs, size_t size) { xml_node_type type_ = _root ? PUGI_IMPL_NODETYPE(_root) : node_null; if (type_ != node_pcdata && type_ != node_cdata && type_ != node_comment && type_ != node_pi && type_ != node_doctype) return false; return impl::strcpy_insitu(_root->value, _root->header, impl::xml_memory_page_value_allocated_mask, rhs, size); } #ifdef PUGIXML_HAS_STRING_VIEW PUGI_IMPL_FN bool xml_node::set_value(string_view_t rhs) { xml_node_type type_ = _root ? PUGI_IMPL_NODETYPE(_root) : node_null; if (type_ != node_pcdata && type_ != node_cdata && type_ != node_comment && type_ != node_pi && type_ != node_doctype) return false; return impl::strcpy_insitu(_root->value, _root->header, impl::xml_memory_page_value_allocated_mask, rhs.data(), rhs.size()); } #endif PUGI_IMPL_FN xml_attribute xml_node::append_attribute(const char_t* name_) { if (!impl::allow_insert_attribute(type())) return xml_attribute(); impl::xml_allocator& alloc = impl::get_allocator(_root); if (!alloc.reserve()) return xml_attribute(); xml_attribute a(impl::allocate_attribute(alloc)); if (!a) return xml_attribute(); impl::append_attribute(a._attr, _root); a.set_name(name_); return a; } PUGI_IMPL_FN xml_attribute xml_node::prepend_attribute(const char_t* name_) { if (!impl::allow_insert_attribute(type())) return xml_attribute(); impl::xml_allocator& alloc = impl::get_allocator(_root); if (!alloc.reserve()) return xml_attribute(); xml_attribute a(impl::allocate_attribute(alloc)); if (!a) return xml_attribute(); impl::prepend_attribute(a._attr, _root); a.set_name(name_); return a; } PUGI_IMPL_FN xml_attribute xml_node::insert_attribute_after(const char_t* name_, const xml_attribute& attr) { if (!impl::allow_insert_attribute(type())) return xml_attribute(); if (!attr || !impl::is_attribute_of(attr._attr, _root)) return xml_attribute(); impl::xml_allocator& alloc = impl::get_allocator(_root); if (!alloc.reserve()) return xml_attribute(); xml_attribute a(impl::allocate_attribute(alloc)); if (!a) return xml_attribute(); impl::insert_attribute_after(a._attr, attr._attr, _root); a.set_name(name_); return a; } PUGI_IMPL_FN xml_attribute xml_node::insert_attribute_before(const char_t* name_, const xml_attribute& attr) { if (!impl::allow_insert_attribute(type())) return xml_attribute(); if (!attr || !impl::is_attribute_of(attr._attr, _root)) return xml_attribute(); impl::xml_allocator& alloc = impl::get_allocator(_root); if (!alloc.reserve()) return xml_attribute(); xml_attribute a(impl::allocate_attribute(alloc)); if (!a) return xml_attribute(); impl::insert_attribute_before(a._attr, attr._attr, _root); a.set_name(name_); return a; } #ifdef PUGIXML_HAS_STRING_VIEW PUGI_IMPL_FN xml_attribute xml_node::append_attribute(string_view_t name_) { if (!impl::allow_insert_attribute(type())) return xml_attribute(); impl::xml_allocator& alloc = impl::get_allocator(_root); if (!alloc.reserve()) return xml_attribute(); xml_attribute a(impl::allocate_attribute(alloc)); if (!a) return xml_attribute(); impl::append_attribute(a._attr, _root); a.set_name(name_); return a; } PUGI_IMPL_FN xml_attribute xml_node::prepend_attribute(string_view_t name_) { if (!impl::allow_insert_attribute(type())) return xml_attribute(); impl::xml_allocator& alloc = impl::get_allocator(_root); if (!alloc.reserve()) return xml_attribute(); xml_attribute a(impl::allocate_attribute(alloc)); if (!a) return xml_attribute(); impl::prepend_attribute(a._attr, _root); a.set_name(name_); return a; } PUGI_IMPL_FN xml_attribute xml_node::insert_attribute_after(string_view_t name_, const xml_attribute& attr) { if (!impl::allow_insert_attribute(type())) return xml_attribute(); if (!attr || !impl::is_attribute_of(attr._attr, _root)) return xml_attribute(); impl::xml_allocator& alloc = impl::get_allocator(_root); if (!alloc.reserve()) return xml_attribute(); xml_attribute a(impl::allocate_attribute(alloc)); if (!a) return xml_attribute(); impl::insert_attribute_after(a._attr, attr._attr, _root); a.set_name(name_); return a; } PUGI_IMPL_FN xml_attribute xml_node::insert_attribute_before(string_view_t name_, const xml_attribute& attr) { if (!impl::allow_insert_attribute(type())) return xml_attribute(); if (!attr || !impl::is_attribute_of(attr._attr, _root)) return xml_attribute(); impl::xml_allocator& alloc = impl::get_allocator(_root); if (!alloc.reserve()) return xml_attribute(); xml_attribute a(impl::allocate_attribute(alloc)); if (!a) return xml_attribute(); impl::insert_attribute_before(a._attr, attr._attr, _root); a.set_name(name_); return a; } #endif PUGI_IMPL_FN xml_attribute xml_node::append_copy(const xml_attribute& proto) { if (!proto) return xml_attribute(); if (!impl::allow_insert_attribute(type())) return xml_attribute(); impl::xml_allocator& alloc = impl::get_allocator(_root); if (!alloc.reserve()) return xml_attribute(); xml_attribute a(impl::allocate_attribute(alloc)); if (!a) return xml_attribute(); impl::append_attribute(a._attr, _root); impl::node_copy_attribute(a._attr, proto._attr); return a; } PUGI_IMPL_FN xml_attribute xml_node::prepend_copy(const xml_attribute& proto) { if (!proto) return xml_attribute(); if (!impl::allow_insert_attribute(type())) return xml_attribute(); impl::xml_allocator& alloc = impl::get_allocator(_root); if (!alloc.reserve()) return xml_attribute(); xml_attribute a(impl::allocate_attribute(alloc)); if (!a) return xml_attribute(); impl::prepend_attribute(a._attr, _root); impl::node_copy_attribute(a._attr, proto._attr); return a; } PUGI_IMPL_FN xml_attribute xml_node::insert_copy_after(const xml_attribute& proto, const xml_attribute& attr) { if (!proto) return xml_attribute(); if (!impl::allow_insert_attribute(type())) return xml_attribute(); if (!attr || !impl::is_attribute_of(attr._attr, _root)) return xml_attribute(); impl::xml_allocator& alloc = impl::get_allocator(_root); if (!alloc.reserve()) return xml_attribute(); xml_attribute a(impl::allocate_attribute(alloc)); if (!a) return xml_attribute(); impl::insert_attribute_after(a._attr, attr._attr, _root); impl::node_copy_attribute(a._attr, proto._attr); return a; } PUGI_IMPL_FN xml_attribute xml_node::insert_copy_before(const xml_attribute& proto, const xml_attribute& attr) { if (!proto) return xml_attribute(); if (!impl::allow_insert_attribute(type())) return xml_attribute(); if (!attr || !impl::is_attribute_of(attr._attr, _root)) return xml_attribute(); impl::xml_allocator& alloc = impl::get_allocator(_root); if (!alloc.reserve()) return xml_attribute(); xml_attribute a(impl::allocate_attribute(alloc)); if (!a) return xml_attribute(); impl::insert_attribute_before(a._attr, attr._attr, _root); impl::node_copy_attribute(a._attr, proto._attr); return a; } PUGI_IMPL_FN xml_node xml_node::append_child(xml_node_type type_) { if (!impl::allow_insert_child(type(), type_)) return xml_node(); impl::xml_allocator& alloc = impl::get_allocator(_root); if (!alloc.reserve()) return xml_node(); xml_node n(impl::allocate_node(alloc, type_)); if (!n) return xml_node(); impl::append_node(n._root, _root); if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml")); return n; } PUGI_IMPL_FN xml_node xml_node::prepend_child(xml_node_type type_) { if (!impl::allow_insert_child(type(), type_)) return xml_node(); impl::xml_allocator& alloc = impl::get_allocator(_root); if (!alloc.reserve()) return xml_node(); xml_node n(impl::allocate_node(alloc, type_)); if (!n) return xml_node(); impl::prepend_node(n._root, _root); if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml")); return n; } PUGI_IMPL_FN xml_node xml_node::insert_child_before(xml_node_type type_, const xml_node& node) { if (!impl::allow_insert_child(type(), type_)) return xml_node(); if (!node._root || node._root->parent != _root) return xml_node(); impl::xml_allocator& alloc = impl::get_allocator(_root); if (!alloc.reserve()) return xml_node(); xml_node n(impl::allocate_node(alloc, type_)); if (!n) return xml_node(); impl::insert_node_before(n._root, node._root); if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml")); return n; } PUGI_IMPL_FN xml_node xml_node::insert_child_after(xml_node_type type_, const xml_node& node) { if (!impl::allow_insert_child(type(), type_)) return xml_node(); if (!node._root || node._root->parent != _root) return xml_node(); impl::xml_allocator& alloc = impl::get_allocator(_root); if (!alloc.reserve()) return xml_node(); xml_node n(impl::allocate_node(alloc, type_)); if (!n) return xml_node(); impl::insert_node_after(n._root, node._root); if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml")); return n; } PUGI_IMPL_FN xml_node xml_node::append_child(const char_t* name_) { xml_node result = append_child(node_element); result.set_name(name_); return result; } PUGI_IMPL_FN xml_node xml_node::prepend_child(const char_t* name_) { xml_node result = prepend_child(node_element); result.set_name(name_); return result; } PUGI_IMPL_FN xml_node xml_node::insert_child_after(const char_t* name_, const xml_node& node) { xml_node result = insert_child_after(node_element, node); result.set_name(name_); return result; } PUGI_IMPL_FN xml_node xml_node::insert_child_before(const char_t* name_, const xml_node& node) { xml_node result = insert_child_before(node_element, node); result.set_name(name_); return result; } #ifdef PUGIXML_HAS_STRING_VIEW PUGI_IMPL_FN xml_node xml_node::append_child(string_view_t name_) { xml_node result = append_child(node_element); result.set_name(name_); return result; } PUGI_IMPL_FN xml_node xml_node::prepend_child(string_view_t name_) { xml_node result = prepend_child(node_element); result.set_name(name_); return result; } PUGI_IMPL_FN xml_node xml_node::insert_child_after(string_view_t name_, const xml_node& node) { xml_node result = insert_child_after(node_element, node); result.set_name(name_); return result; } PUGI_IMPL_FN xml_node xml_node::insert_child_before(string_view_t name_, const xml_node& node) { xml_node result = insert_child_before(node_element, node); result.set_name(name_); return result; } #endif PUGI_IMPL_FN xml_node xml_node::append_copy(const xml_node& proto) { xml_node_type type_ = proto.type(); if (!impl::allow_insert_child(type(), type_)) return xml_node(); impl::xml_allocator& alloc = impl::get_allocator(_root); if (!alloc.reserve()) return xml_node(); xml_node n(impl::allocate_node(alloc, type_)); if (!n) return xml_node(); impl::append_node(n._root, _root); impl::node_copy_tree(n._root, proto._root); return n; } PUGI_IMPL_FN xml_node xml_node::prepend_copy(const xml_node& proto) { xml_node_type type_ = proto.type(); if (!impl::allow_insert_child(type(), type_)) return xml_node(); impl::xml_allocator& alloc = impl::get_allocator(_root); if (!alloc.reserve()) return xml_node(); xml_node n(impl::allocate_node(alloc, type_)); if (!n) return xml_node(); impl::prepend_node(n._root, _root); impl::node_copy_tree(n._root, proto._root); return n; } PUGI_IMPL_FN xml_node xml_node::insert_copy_after(const xml_node& proto, const xml_node& node) { xml_node_type type_ = proto.type(); if (!impl::allow_insert_child(type(), type_)) return xml_node(); if (!node._root || node._root->parent != _root) return xml_node(); impl::xml_allocator& alloc = impl::get_allocator(_root); if (!alloc.reserve()) return xml_node(); xml_node n(impl::allocate_node(alloc, type_)); if (!n) return xml_node(); impl::insert_node_after(n._root, node._root); impl::node_copy_tree(n._root, proto._root); return n; } PUGI_IMPL_FN xml_node xml_node::insert_copy_before(const xml_node& proto, const xml_node& node) { xml_node_type type_ = proto.type(); if (!impl::allow_insert_child(type(), type_)) return xml_node(); if (!node._root || node._root->parent != _root) return xml_node(); impl::xml_allocator& alloc = impl::get_allocator(_root); if (!alloc.reserve()) return xml_node(); xml_node n(impl::allocate_node(alloc, type_)); if (!n) return xml_node(); impl::insert_node_before(n._root, node._root); impl::node_copy_tree(n._root, proto._root); return n; } PUGI_IMPL_FN xml_node xml_node::append_move(const xml_node& moved) { if (!impl::allow_move(*this, moved)) return xml_node(); impl::xml_allocator& alloc = impl::get_allocator(_root); if (!alloc.reserve()) return xml_node(); // disable document_buffer_order optimization since moving nodes around changes document order without changing buffer pointers impl::get_document(_root).header |= impl::xml_memory_page_contents_shared_mask; impl::remove_node(moved._root); impl::append_node(moved._root, _root); return moved; } PUGI_IMPL_FN xml_node xml_node::prepend_move(const xml_node& moved) { if (!impl::allow_move(*this, moved)) return xml_node(); impl::xml_allocator& alloc = impl::get_allocator(_root); if (!alloc.reserve()) return xml_node(); // disable document_buffer_order optimization since moving nodes around changes document order without changing buffer pointers impl::get_document(_root).header |= impl::xml_memory_page_contents_shared_mask; impl::remove_node(moved._root); impl::prepend_node(moved._root, _root); return moved; } PUGI_IMPL_FN xml_node xml_node::insert_move_after(const xml_node& moved, const xml_node& node) { if (!impl::allow_move(*this, moved)) return xml_node(); if (!node._root || node._root->parent != _root) return xml_node(); if (moved._root == node._root) return xml_node(); impl::xml_allocator& alloc = impl::get_allocator(_root); if (!alloc.reserve()) return xml_node(); // disable document_buffer_order optimization since moving nodes around changes document order without changing buffer pointers impl::get_document(_root).header |= impl::xml_memory_page_contents_shared_mask; impl::remove_node(moved._root); impl::insert_node_after(moved._root, node._root); return moved; } PUGI_IMPL_FN xml_node xml_node::insert_move_before(const xml_node& moved, const xml_node& node) { if (!impl::allow_move(*this, moved)) return xml_node(); if (!node._root || node._root->parent != _root) return xml_node(); if (moved._root == node._root) return xml_node(); impl::xml_allocator& alloc = impl::get_allocator(_root); if (!alloc.reserve()) return xml_node(); // disable document_buffer_order optimization since moving nodes around changes document order without changing buffer pointers impl::get_document(_root).header |= impl::xml_memory_page_contents_shared_mask; impl::remove_node(moved._root); impl::insert_node_before(moved._root, node._root); return moved; } PUGI_IMPL_FN bool xml_node::remove_attribute(const char_t* name_) { return remove_attribute(attribute(name_)); } #ifdef PUGIXML_HAS_STRING_VIEW PUGI_IMPL_FN bool xml_node::remove_attribute(string_view_t name_) { return remove_attribute(attribute(name_)); } #endif PUGI_IMPL_FN bool xml_node::remove_attribute(const xml_attribute& a) { if (!_root || !a._attr) return false; if (!impl::is_attribute_of(a._attr, _root)) return false; impl::xml_allocator& alloc = impl::get_allocator(_root); if (!alloc.reserve()) return false; impl::remove_attribute(a._attr, _root); impl::destroy_attribute(a._attr, alloc); return true; } PUGI_IMPL_FN bool xml_node::remove_attributes() { if (!_root) return false; impl::xml_allocator& alloc = impl::get_allocator(_root); if (!alloc.reserve()) return false; for (xml_attribute_struct* attr = _root->first_attribute; attr; ) { xml_attribute_struct* next = attr->next_attribute; impl::destroy_attribute(attr, alloc); attr = next; } _root->first_attribute = NULL; return true; } PUGI_IMPL_FN bool xml_node::remove_child(const char_t* name_) { return remove_child(child(name_)); } #ifdef PUGIXML_HAS_STRING_VIEW PUGI_IMPL_FN bool xml_node::remove_child(string_view_t name_) { return remove_child(child(name_)); } #endif PUGI_IMPL_FN bool xml_node::remove_child(const xml_node& n) { if (!_root || !n._root || n._root->parent != _root) return false; impl::xml_allocator& alloc = impl::get_allocator(_root); if (!alloc.reserve()) return false; impl::remove_node(n._root); impl::destroy_node(n._root, alloc); return true; } PUGI_IMPL_FN bool xml_node::remove_children() { if (!_root) return false; impl::xml_allocator& alloc = impl::get_allocator(_root); if (!alloc.reserve()) return false; for (xml_node_struct* cur = _root->first_child; cur; ) { xml_node_struct* next = cur->next_sibling; impl::destroy_node(cur, alloc); cur = next; } _root->first_child = NULL; return true; } PUGI_IMPL_FN xml_parse_result xml_node::append_buffer(const void* contents, size_t size, unsigned int options, xml_encoding encoding) { // append_buffer is only valid for elements/documents if (!impl::allow_insert_child(type(), node_element)) return impl::make_parse_result(status_append_invalid_root); // append buffer can not merge PCDATA into existing PCDATA nodes if ((options & parse_merge_pcdata) != 0 && last_child().type() == node_pcdata) return impl::make_parse_result(status_append_invalid_root); // get document node impl::xml_document_struct* doc = &impl::get_document(_root); // disable document_buffer_order optimization since in a document with multiple buffers comparing buffer pointers does not make sense doc->header |= impl::xml_memory_page_contents_shared_mask; // get extra buffer element (we'll store the document fragment buffer there so that we can deallocate it later) impl::xml_memory_page* page = NULL; impl::xml_extra_buffer* extra = static_cast(doc->allocate_memory(sizeof(impl::xml_extra_buffer) + sizeof(void*), page)); (void)page; if (!extra) return impl::make_parse_result(status_out_of_memory); #ifdef PUGIXML_COMPACT // align the memory block to a pointer boundary; this is required for compact mode where memory allocations are only 4b aligned // note that this requires up to sizeof(void*)-1 additional memory, which the allocation above takes into account extra = reinterpret_cast((reinterpret_cast(extra) + (sizeof(void*) - 1)) & ~(sizeof(void*) - 1)); #endif // add extra buffer to the list extra->buffer = NULL; extra->next = doc->extra_buffers; doc->extra_buffers = extra; // name of the root has to be NULL before parsing - otherwise closing node mismatches will not be detected at the top level impl::name_null_sentry sentry(_root); return impl::load_buffer_impl(doc, _root, const_cast(contents), size, options, encoding, false, false, &extra->buffer); } PUGI_IMPL_FN xml_node xml_node::find_child_by_attribute(const char_t* name_, const char_t* attr_name, const char_t* attr_value) const { if (!_root) return xml_node(); for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) { const char_t* iname = i->name; if (iname && impl::strequal(name_, iname)) { for (xml_attribute_struct* a = i->first_attribute; a; a = a->next_attribute) { const char_t* aname = a->name; if (aname && impl::strequal(attr_name, aname)) { const char_t* avalue = a->value; if (impl::strequal(attr_value, avalue ? avalue : PUGIXML_TEXT(""))) return xml_node(i); } } } } return xml_node(); } PUGI_IMPL_FN xml_node xml_node::find_child_by_attribute(const char_t* attr_name, const char_t* attr_value) const { if (!_root) return xml_node(); for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) for (xml_attribute_struct* a = i->first_attribute; a; a = a->next_attribute) { const char_t* aname = a->name; if (aname && impl::strequal(attr_name, aname)) { const char_t* avalue = a->value; if (impl::strequal(attr_value, avalue ? avalue : PUGIXML_TEXT(""))) return xml_node(i); } } return xml_node(); } #ifndef PUGIXML_NO_STL PUGI_IMPL_FN string_t xml_node::path(char_t delimiter) const { if (!_root) return string_t(); size_t offset = 0; for (xml_node_struct* i = _root; i; i = i->parent) { const char_t* iname = i->name; offset += (i != _root); offset += iname ? impl::strlength(iname) : 0; } string_t result; result.resize(offset); for (xml_node_struct* j = _root; j; j = j->parent) { if (j != _root) result[--offset] = delimiter; const char_t* jname = j->name; if (jname) { size_t length = impl::strlength(jname); offset -= length; memcpy(&result[offset], jname, length * sizeof(char_t)); } } assert(offset == 0); return result; } #endif PUGI_IMPL_FN xml_node xml_node::first_element_by_path(const char_t* path_, char_t delimiter) const { xml_node context = path_[0] == delimiter ? root() : *this; if (!context._root) return xml_node(); const char_t* path_segment = path_; while (*path_segment == delimiter) ++path_segment; const char_t* path_segment_end = path_segment; while (*path_segment_end && *path_segment_end != delimiter) ++path_segment_end; if (path_segment == path_segment_end) return context; const char_t* next_segment = path_segment_end; while (*next_segment == delimiter) ++next_segment; if (*path_segment == '.' && path_segment + 1 == path_segment_end) return context.first_element_by_path(next_segment, delimiter); else if (*path_segment == '.' && *(path_segment+1) == '.' && path_segment + 2 == path_segment_end) return context.parent().first_element_by_path(next_segment, delimiter); else { for (xml_node_struct* j = context._root->first_child; j; j = j->next_sibling) { const char_t* jname = j->name; if (jname && impl::strequalrange(jname, path_segment, static_cast(path_segment_end - path_segment))) { xml_node subsearch = xml_node(j).first_element_by_path(next_segment, delimiter); if (subsearch) return subsearch; } } return xml_node(); } } PUGI_IMPL_FN bool xml_node::traverse(xml_tree_walker& walker) { walker._depth = -1; xml_node arg_begin(_root); if (!walker.begin(arg_begin)) return false; xml_node_struct* cur = _root ? _root->first_child + 0 : NULL; if (cur) { ++walker._depth; do { xml_node arg_for_each(cur); if (!walker.for_each(arg_for_each)) return false; if (cur->first_child) { ++walker._depth; cur = cur->first_child; } else if (cur->next_sibling) cur = cur->next_sibling; else { while (!cur->next_sibling && cur != _root && cur->parent) { --walker._depth; cur = cur->parent; } if (cur != _root) cur = cur->next_sibling; } } while (cur && cur != _root); } assert(walker._depth == -1); xml_node arg_end(_root); return walker.end(arg_end); } PUGI_IMPL_FN size_t xml_node::hash_value() const { return reinterpret_cast(_root) / sizeof(xml_node_struct); } PUGI_IMPL_FN xml_node_struct* xml_node::internal_object() const { return _root; } PUGI_IMPL_FN void xml_node::print(xml_writer& writer, const char_t* indent, unsigned int flags, xml_encoding encoding, unsigned int depth) const { if (!_root) return; impl::xml_buffered_writer buffered_writer(writer, encoding); impl::node_output(buffered_writer, _root, indent, flags, depth); buffered_writer.flush(); } #ifndef PUGIXML_NO_STL PUGI_IMPL_FN void xml_node::print(std::basic_ostream& stream, const char_t* indent, unsigned int flags, xml_encoding encoding, unsigned int depth) const { xml_writer_stream writer(stream); print(writer, indent, flags, encoding, depth); } PUGI_IMPL_FN void xml_node::print(std::basic_ostream& stream, const char_t* indent, unsigned int flags, unsigned int depth) const { xml_writer_stream writer(stream); print(writer, indent, flags, encoding_wchar, depth); } #endif PUGI_IMPL_FN ptrdiff_t xml_node::offset_debug() const { if (!_root) return -1; impl::xml_document_struct& doc = impl::get_document(_root); // we can determine the offset reliably only if there is exactly once parse buffer if (!doc.buffer || doc.extra_buffers) return -1; switch (type()) { case node_document: return 0; case node_element: case node_declaration: case node_pi: return _root->name && (_root->header & impl::xml_memory_page_name_allocated_or_shared_mask) == 0 ? _root->name - doc.buffer : -1; case node_pcdata: case node_cdata: case node_comment: case node_doctype: return _root->value && (_root->header & impl::xml_memory_page_value_allocated_or_shared_mask) == 0 ? _root->value - doc.buffer : -1; default: assert(false && "Invalid node type"); // unreachable return -1; } } #ifdef __BORLANDC__ PUGI_IMPL_FN bool operator&&(const xml_node& lhs, bool rhs) { return (bool)lhs && rhs; } PUGI_IMPL_FN bool operator||(const xml_node& lhs, bool rhs) { return (bool)lhs || rhs; } #endif PUGI_IMPL_FN xml_text::xml_text(xml_node_struct* root): _root(root) { } PUGI_IMPL_FN xml_node_struct* xml_text::_data() const { if (!_root || impl::is_text_node(_root)) return _root; // element nodes can have value if parse_embed_pcdata was used if (PUGI_IMPL_NODETYPE(_root) == node_element && _root->value) return _root; for (xml_node_struct* node = _root->first_child; node; node = node->next_sibling) if (impl::is_text_node(node)) return node; return NULL; } PUGI_IMPL_FN xml_node_struct* xml_text::_data_new() { xml_node_struct* d = _data(); if (d) return d; return xml_node(_root).append_child(node_pcdata).internal_object(); } PUGI_IMPL_FN xml_text::xml_text(): _root(NULL) { } PUGI_IMPL_FN static void unspecified_bool_xml_text(xml_text***) { } PUGI_IMPL_FN xml_text::operator xml_text::unspecified_bool_type() const { return _data() ? unspecified_bool_xml_text : NULL; } PUGI_IMPL_FN bool xml_text::operator!() const { return !_data(); } PUGI_IMPL_FN bool xml_text::empty() const { return _data() == NULL; } PUGI_IMPL_FN const char_t* xml_text::get() const { xml_node_struct* d = _data(); if (!d) return PUGIXML_TEXT(""); const char_t* value = d->value; return value ? value : PUGIXML_TEXT(""); } PUGI_IMPL_FN const char_t* xml_text::as_string(const char_t* def) const { xml_node_struct* d = _data(); if (!d) return def; const char_t* value = d->value; return value ? value : def; } PUGI_IMPL_FN int xml_text::as_int(int def) const { xml_node_struct* d = _data(); if (!d) return def; const char_t* value = d->value; return value ? impl::get_value_int(value) : def; } PUGI_IMPL_FN unsigned int xml_text::as_uint(unsigned int def) const { xml_node_struct* d = _data(); if (!d) return def; const char_t* value = d->value; return value ? impl::get_value_uint(value) : def; } PUGI_IMPL_FN double xml_text::as_double(double def) const { xml_node_struct* d = _data(); if (!d) return def; const char_t* value = d->value; return value ? impl::get_value_double(value) : def; } PUGI_IMPL_FN float xml_text::as_float(float def) const { xml_node_struct* d = _data(); if (!d) return def; const char_t* value = d->value; return value ? impl::get_value_float(value) : def; } PUGI_IMPL_FN bool xml_text::as_bool(bool def) const { xml_node_struct* d = _data(); if (!d) return def; const char_t* value = d->value; return value ? impl::get_value_bool(value) : def; } #ifdef PUGIXML_HAS_LONG_LONG PUGI_IMPL_FN long long xml_text::as_llong(long long def) const { xml_node_struct* d = _data(); if (!d) return def; const char_t* value = d->value; return value ? impl::get_value_llong(value) : def; } PUGI_IMPL_FN unsigned long long xml_text::as_ullong(unsigned long long def) const { xml_node_struct* d = _data(); if (!d) return def; const char_t* value = d->value; return value ? impl::get_value_ullong(value) : def; } #endif PUGI_IMPL_FN bool xml_text::set(const char_t* rhs) { xml_node_struct* dn = _data_new(); return dn ? impl::strcpy_insitu(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, impl::strlength(rhs)) : false; } PUGI_IMPL_FN bool xml_text::set(const char_t* rhs, size_t size) { xml_node_struct* dn = _data_new(); return dn ? impl::strcpy_insitu(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, size) : false; } #ifdef PUGIXML_HAS_STRING_VIEW PUGI_IMPL_FN bool xml_text::set(string_view_t rhs) { xml_node_struct* dn = _data_new(); return dn ? impl::strcpy_insitu(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs.data(), rhs.size()) : false; } #endif PUGI_IMPL_FN bool xml_text::set(int rhs) { xml_node_struct* dn = _data_new(); return dn ? impl::set_value_integer(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0) : false; } PUGI_IMPL_FN bool xml_text::set(unsigned int rhs) { xml_node_struct* dn = _data_new(); return dn ? impl::set_value_integer(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, false) : false; } PUGI_IMPL_FN bool xml_text::set(long rhs) { xml_node_struct* dn = _data_new(); return dn ? impl::set_value_integer(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0) : false; } PUGI_IMPL_FN bool xml_text::set(unsigned long rhs) { xml_node_struct* dn = _data_new(); return dn ? impl::set_value_integer(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, false) : false; } PUGI_IMPL_FN bool xml_text::set(float rhs) { xml_node_struct* dn = _data_new(); return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, default_float_precision) : false; } PUGI_IMPL_FN bool xml_text::set(float rhs, int precision) { xml_node_struct* dn = _data_new(); return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, precision) : false; } PUGI_IMPL_FN bool xml_text::set(double rhs) { xml_node_struct* dn = _data_new(); return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, default_double_precision) : false; } PUGI_IMPL_FN bool xml_text::set(double rhs, int precision) { xml_node_struct* dn = _data_new(); return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, precision) : false; } PUGI_IMPL_FN bool xml_text::set(bool rhs) { xml_node_struct* dn = _data_new(); return dn ? impl::set_value_bool(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false; } #ifdef PUGIXML_HAS_LONG_LONG PUGI_IMPL_FN bool xml_text::set(long long rhs) { xml_node_struct* dn = _data_new(); return dn ? impl::set_value_integer(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0) : false; } PUGI_IMPL_FN bool xml_text::set(unsigned long long rhs) { xml_node_struct* dn = _data_new(); return dn ? impl::set_value_integer(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, false) : false; } #endif PUGI_IMPL_FN xml_text& xml_text::operator=(const char_t* rhs) { set(rhs); return *this; } PUGI_IMPL_FN xml_text& xml_text::operator=(int rhs) { set(rhs); return *this; } PUGI_IMPL_FN xml_text& xml_text::operator=(unsigned int rhs) { set(rhs); return *this; } PUGI_IMPL_FN xml_text& xml_text::operator=(long rhs) { set(rhs); return *this; } PUGI_IMPL_FN xml_text& xml_text::operator=(unsigned long rhs) { set(rhs); return *this; } PUGI_IMPL_FN xml_text& xml_text::operator=(double rhs) { set(rhs); return *this; } PUGI_IMPL_FN xml_text& xml_text::operator=(float rhs) { set(rhs); return *this; } PUGI_IMPL_FN xml_text& xml_text::operator=(bool rhs) { set(rhs); return *this; } #ifdef PUGIXML_HAS_STRING_VIEW PUGI_IMPL_FN xml_text& xml_text::operator=(string_view_t rhs) { set(rhs); return *this; } #endif #ifdef PUGIXML_HAS_LONG_LONG PUGI_IMPL_FN xml_text& xml_text::operator=(long long rhs) { set(rhs); return *this; } PUGI_IMPL_FN xml_text& xml_text::operator=(unsigned long long rhs) { set(rhs); return *this; } #endif PUGI_IMPL_FN xml_node xml_text::data() const { return xml_node(_data()); } #ifdef __BORLANDC__ PUGI_IMPL_FN bool operator&&(const xml_text& lhs, bool rhs) { return (bool)lhs && rhs; } PUGI_IMPL_FN bool operator||(const xml_text& lhs, bool rhs) { return (bool)lhs || rhs; } #endif PUGI_IMPL_FN xml_node_iterator::xml_node_iterator() { } PUGI_IMPL_FN xml_node_iterator::xml_node_iterator(const xml_node& node): _wrap(node), _parent(node.parent()) { } PUGI_IMPL_FN xml_node_iterator::xml_node_iterator(xml_node_struct* ref, xml_node_struct* parent): _wrap(ref), _parent(parent) { } PUGI_IMPL_FN bool xml_node_iterator::operator==(const xml_node_iterator& rhs) const { return _wrap._root == rhs._wrap._root && _parent._root == rhs._parent._root; } PUGI_IMPL_FN bool xml_node_iterator::operator!=(const xml_node_iterator& rhs) const { return _wrap._root != rhs._wrap._root || _parent._root != rhs._parent._root; } PUGI_IMPL_FN xml_node& xml_node_iterator::operator*() const { assert(_wrap._root); return _wrap; } PUGI_IMPL_FN xml_node* xml_node_iterator::operator->() const { assert(_wrap._root); return &_wrap; } PUGI_IMPL_FN xml_node_iterator& xml_node_iterator::operator++() { assert(_wrap._root); _wrap._root = _wrap._root->next_sibling; return *this; } PUGI_IMPL_FN xml_node_iterator xml_node_iterator::operator++(int) { xml_node_iterator temp = *this; ++*this; return temp; } PUGI_IMPL_FN xml_node_iterator& xml_node_iterator::operator--() { _wrap = _wrap._root ? _wrap.previous_sibling() : _parent.last_child(); return *this; } PUGI_IMPL_FN xml_node_iterator xml_node_iterator::operator--(int) { xml_node_iterator temp = *this; --*this; return temp; } PUGI_IMPL_FN xml_attribute_iterator::xml_attribute_iterator() { } PUGI_IMPL_FN xml_attribute_iterator::xml_attribute_iterator(const xml_attribute& attr, const xml_node& parent): _wrap(attr), _parent(parent) { } PUGI_IMPL_FN xml_attribute_iterator::xml_attribute_iterator(xml_attribute_struct* ref, xml_node_struct* parent): _wrap(ref), _parent(parent) { } PUGI_IMPL_FN bool xml_attribute_iterator::operator==(const xml_attribute_iterator& rhs) const { return _wrap._attr == rhs._wrap._attr && _parent._root == rhs._parent._root; } PUGI_IMPL_FN bool xml_attribute_iterator::operator!=(const xml_attribute_iterator& rhs) const { return _wrap._attr != rhs._wrap._attr || _parent._root != rhs._parent._root; } PUGI_IMPL_FN xml_attribute& xml_attribute_iterator::operator*() const { assert(_wrap._attr); return _wrap; } PUGI_IMPL_FN xml_attribute* xml_attribute_iterator::operator->() const { assert(_wrap._attr); return &_wrap; } PUGI_IMPL_FN xml_attribute_iterator& xml_attribute_iterator::operator++() { assert(_wrap._attr); _wrap._attr = _wrap._attr->next_attribute; return *this; } PUGI_IMPL_FN xml_attribute_iterator xml_attribute_iterator::operator++(int) { xml_attribute_iterator temp = *this; ++*this; return temp; } PUGI_IMPL_FN xml_attribute_iterator& xml_attribute_iterator::operator--() { _wrap = _wrap._attr ? _wrap.previous_attribute() : _parent.last_attribute(); return *this; } PUGI_IMPL_FN xml_attribute_iterator xml_attribute_iterator::operator--(int) { xml_attribute_iterator temp = *this; --*this; return temp; } PUGI_IMPL_FN xml_named_node_iterator::xml_named_node_iterator(): _name(NULL) { } PUGI_IMPL_FN xml_named_node_iterator::xml_named_node_iterator(const xml_node& node, const char_t* name): _wrap(node), _parent(node.parent()), _name(name) { } PUGI_IMPL_FN xml_named_node_iterator::xml_named_node_iterator(xml_node_struct* ref, xml_node_struct* parent, const char_t* name): _wrap(ref), _parent(parent), _name(name) { } PUGI_IMPL_FN bool xml_named_node_iterator::operator==(const xml_named_node_iterator& rhs) const { return _wrap._root == rhs._wrap._root && _parent._root == rhs._parent._root; } PUGI_IMPL_FN bool xml_named_node_iterator::operator!=(const xml_named_node_iterator& rhs) const { return _wrap._root != rhs._wrap._root || _parent._root != rhs._parent._root; } PUGI_IMPL_FN xml_node& xml_named_node_iterator::operator*() const { assert(_wrap._root); return _wrap; } PUGI_IMPL_FN xml_node* xml_named_node_iterator::operator->() const { assert(_wrap._root); return &_wrap; } PUGI_IMPL_FN xml_named_node_iterator& xml_named_node_iterator::operator++() { assert(_wrap._root); _wrap = _wrap.next_sibling(_name); return *this; } PUGI_IMPL_FN xml_named_node_iterator xml_named_node_iterator::operator++(int) { xml_named_node_iterator temp = *this; ++*this; return temp; } PUGI_IMPL_FN xml_named_node_iterator& xml_named_node_iterator::operator--() { if (_wrap._root) _wrap = _wrap.previous_sibling(_name); else { _wrap = _parent.last_child(); if (!impl::strequal(_wrap.name(), _name)) _wrap = _wrap.previous_sibling(_name); } return *this; } PUGI_IMPL_FN xml_named_node_iterator xml_named_node_iterator::operator--(int) { xml_named_node_iterator temp = *this; --*this; return temp; } PUGI_IMPL_FN xml_parse_result::xml_parse_result(): status(status_internal_error), offset(0), encoding(encoding_auto) { } PUGI_IMPL_FN xml_parse_result::operator bool() const { return status == status_ok; } PUGI_IMPL_FN const char* xml_parse_result::description() const { switch (status) { case status_ok: return "No error"; case status_file_not_found: return "File was not found"; case status_io_error: return "Error reading from file/stream"; case status_out_of_memory: return "Could not allocate memory"; case status_internal_error: return "Internal error occurred"; case status_unrecognized_tag: return "Could not determine tag type"; case status_bad_pi: return "Error parsing document declaration/processing instruction"; case status_bad_comment: return "Error parsing comment"; case status_bad_cdata: return "Error parsing CDATA section"; case status_bad_doctype: return "Error parsing document type declaration"; case status_bad_pcdata: return "Error parsing PCDATA section"; case status_bad_start_element: return "Error parsing start element tag"; case status_bad_attribute: return "Error parsing element attribute"; case status_bad_end_element: return "Error parsing end element tag"; case status_end_element_mismatch: return "Start-end tags mismatch"; case status_append_invalid_root: return "Unable to append nodes: root is not an element or document"; case status_no_document_element: return "No document element found"; default: return "Unknown error"; } } PUGI_IMPL_FN xml_document::xml_document(): _buffer(NULL) { _create(); } PUGI_IMPL_FN xml_document::~xml_document() { _destroy(); } #ifdef PUGIXML_HAS_MOVE PUGI_IMPL_FN xml_document::xml_document(xml_document&& rhs) PUGIXML_NOEXCEPT_IF_NOT_COMPACT: _buffer(NULL) { _create(); _move(rhs); } PUGI_IMPL_FN xml_document& xml_document::operator=(xml_document&& rhs) PUGIXML_NOEXCEPT_IF_NOT_COMPACT { if (this == &rhs) return *this; _destroy(); _create(); _move(rhs); return *this; } #endif PUGI_IMPL_FN void xml_document::reset() { _destroy(); _create(); } PUGI_IMPL_FN void xml_document::reset(const xml_document& proto) { reset(); impl::node_copy_tree(_root, proto._root); } PUGI_IMPL_FN void xml_document::_create() { assert(!_root); #ifdef PUGIXML_COMPACT // space for page marker for the first page (uint32_t), rounded up to pointer size; assumes pointers are at least 32-bit const size_t page_offset = sizeof(void*); #else const size_t page_offset = 0; #endif // initialize sentinel page PUGI_IMPL_STATIC_ASSERT(sizeof(impl::xml_memory_page) + sizeof(impl::xml_document_struct) + page_offset <= sizeof(_memory)); // prepare page structure impl::xml_memory_page* page = impl::xml_memory_page::construct(_memory); assert(page); page->busy_size = impl::xml_memory_page_size; // setup first page marker #ifdef PUGIXML_COMPACT // round-trip through void* to avoid 'cast increases required alignment of target type' warning page->compact_page_marker = reinterpret_cast(static_cast(reinterpret_cast(page) + sizeof(impl::xml_memory_page))); *page->compact_page_marker = sizeof(impl::xml_memory_page); #endif // allocate new root _root = new (reinterpret_cast(page) + sizeof(impl::xml_memory_page) + page_offset) impl::xml_document_struct(page); _root->prev_sibling_c = _root; // setup sentinel page page->allocator = static_cast(_root); // setup hash table pointer in allocator #ifdef PUGIXML_COMPACT page->allocator->_hash = &static_cast(_root)->hash; #endif // verify the document allocation assert(reinterpret_cast(_root) + sizeof(impl::xml_document_struct) <= _memory + sizeof(_memory)); } PUGI_IMPL_FN void xml_document::_destroy() { assert(_root); // destroy static storage if (_buffer) { impl::xml_memory::deallocate(_buffer); _buffer = NULL; } // destroy extra buffers (note: no need to destroy linked list nodes, they're allocated using document allocator) for (impl::xml_extra_buffer* extra = static_cast(_root)->extra_buffers; extra; extra = extra->next) { if (extra->buffer) impl::xml_memory::deallocate(extra->buffer); } // destroy dynamic storage, leave sentinel page (it's in static memory) impl::xml_memory_page* root_page = PUGI_IMPL_GETPAGE(_root); assert(root_page && !root_page->prev); assert(reinterpret_cast(root_page) >= _memory && reinterpret_cast(root_page) < _memory + sizeof(_memory)); for (impl::xml_memory_page* page = root_page->next; page; ) { impl::xml_memory_page* next = page->next; impl::xml_allocator::deallocate_page(page); page = next; } #ifdef PUGIXML_COMPACT // destroy hash table static_cast(_root)->hash.clear(); #endif _root = NULL; } #ifdef PUGIXML_HAS_MOVE PUGI_IMPL_FN void xml_document::_move(xml_document& rhs) PUGIXML_NOEXCEPT_IF_NOT_COMPACT { impl::xml_document_struct* doc = static_cast(_root); impl::xml_document_struct* other = static_cast(rhs._root); // save first child pointer for later; this needs hash access xml_node_struct* other_first_child = other->first_child; #ifdef PUGIXML_COMPACT // reserve space for the hash table up front; this is the only operation that can fail // if it does, we have no choice but to throw (if we have exceptions) if (other_first_child) { size_t other_children = 0; for (xml_node_struct* node = other_first_child; node; node = node->next_sibling) other_children++; // in compact mode, each pointer assignment could result in a hash table request // during move, we have to relocate document first_child and parents of all children // normally there's just one child and its parent has a pointerless encoding but // we assume the worst here if (!other->_hash->reserve(other_children + 1)) { #ifdef PUGIXML_NO_EXCEPTIONS return; #else throw std::bad_alloc(); #endif } } #endif // move allocation state // note that other->_root may point to the embedded document page, in which case we should keep original (empty) state if (other->_root != PUGI_IMPL_GETPAGE(other)) { doc->_root = other->_root; doc->_busy_size = other->_busy_size; } // move buffer state doc->buffer = other->buffer; doc->extra_buffers = other->extra_buffers; _buffer = rhs._buffer; #ifdef PUGIXML_COMPACT // move compact hash; note that the hash table can have pointers to other but they will be "inactive", similarly to nodes removed with remove_child doc->hash = other->hash; doc->_hash = &doc->hash; // make sure we don't access other hash up until the end when we reinitialize other document other->_hash = NULL; #endif // move page structure impl::xml_memory_page* doc_page = PUGI_IMPL_GETPAGE(doc); assert(doc_page && !doc_page->prev && !doc_page->next); impl::xml_memory_page* other_page = PUGI_IMPL_GETPAGE(other); assert(other_page && !other_page->prev); // relink pages since root page is embedded into xml_document if (impl::xml_memory_page* page = other_page->next) { assert(page->prev == other_page); page->prev = doc_page; doc_page->next = page; other_page->next = NULL; } // make sure pages point to the correct document state for (impl::xml_memory_page* page = doc_page->next; page; page = page->next) { assert(page->allocator == other); page->allocator = doc; #ifdef PUGIXML_COMPACT // this automatically migrates most children between documents and prevents ->parent assignment from allocating if (page->compact_shared_parent == other) page->compact_shared_parent = doc; #endif } // move tree structure assert(!doc->first_child); doc->first_child = other_first_child; for (xml_node_struct* node = other_first_child; node; node = node->next_sibling) { #ifdef PUGIXML_COMPACT // most children will have migrated when we reassigned compact_shared_parent assert(node->parent == other || node->parent == doc); node->parent = doc; #else assert(node->parent == other); node->parent = doc; #endif } // reset other document new (other) impl::xml_document_struct(PUGI_IMPL_GETPAGE(other)); rhs._buffer = NULL; } #endif #ifndef PUGIXML_NO_STL PUGI_IMPL_FN xml_parse_result xml_document::load(std::basic_istream& stream, unsigned int options, xml_encoding encoding) { reset(); return impl::load_stream_impl(static_cast(_root), stream, options, encoding, &_buffer); } PUGI_IMPL_FN xml_parse_result xml_document::load(std::basic_istream& stream, unsigned int options) { reset(); return impl::load_stream_impl(static_cast(_root), stream, options, encoding_wchar, &_buffer); } #endif PUGI_IMPL_FN xml_parse_result xml_document::load_string(const char_t* contents, unsigned int options) { // Force native encoding (skip autodetection) #ifdef PUGIXML_WCHAR_MODE xml_encoding encoding = encoding_wchar; #else xml_encoding encoding = encoding_utf8; #endif return load_buffer(contents, impl::strlength(contents) * sizeof(char_t), options, encoding); } PUGI_IMPL_FN xml_parse_result xml_document::load(const char_t* contents, unsigned int options) { return load_string(contents, options); } PUGI_IMPL_FN xml_parse_result xml_document::load_file(const char* path_, unsigned int options, xml_encoding encoding) { reset(); using impl::auto_deleter; // MSVC7 workaround auto_deleter file(impl::open_file(path_, "rb"), impl::close_file); return impl::load_file_impl(static_cast(_root), file.data, options, encoding, &_buffer); } PUGI_IMPL_FN xml_parse_result xml_document::load_file(const wchar_t* path_, unsigned int options, xml_encoding encoding) { reset(); using impl::auto_deleter; // MSVC7 workaround auto_deleter file(impl::open_file_wide(path_, L"rb"), impl::close_file); return impl::load_file_impl(static_cast(_root), file.data, options, encoding, &_buffer); } PUGI_IMPL_FN xml_parse_result xml_document::load_buffer(const void* contents, size_t size, unsigned int options, xml_encoding encoding) { reset(); return impl::load_buffer_impl(static_cast(_root), _root, const_cast(contents), size, options, encoding, false, false, &_buffer); } PUGI_IMPL_FN xml_parse_result xml_document::load_buffer_inplace(void* contents, size_t size, unsigned int options, xml_encoding encoding) { reset(); return impl::load_buffer_impl(static_cast(_root), _root, contents, size, options, encoding, true, false, &_buffer); } PUGI_IMPL_FN xml_parse_result xml_document::load_buffer_inplace_own(void* contents, size_t size, unsigned int options, xml_encoding encoding) { reset(); return impl::load_buffer_impl(static_cast(_root), _root, contents, size, options, encoding, true, true, &_buffer); } PUGI_IMPL_FN void xml_document::save(xml_writer& writer, const char_t* indent, unsigned int flags, xml_encoding encoding) const { impl::xml_buffered_writer buffered_writer(writer, encoding); if ((flags & format_write_bom) && buffered_writer.encoding != encoding_latin1) { // BOM always represents the codepoint U+FEFF, so just write it in native encoding #ifdef PUGIXML_WCHAR_MODE unsigned int bom = 0xfeff; buffered_writer.write(static_cast(bom)); #else buffered_writer.write('\xef', '\xbb', '\xbf'); #endif } if (!(flags & format_no_declaration) && !impl::has_declaration(_root)) { buffered_writer.write_string(PUGIXML_TEXT("'); if (!(flags & format_raw)) buffered_writer.write('\n'); } impl::node_output(buffered_writer, _root, indent, flags, 0); buffered_writer.flush(); } #ifndef PUGIXML_NO_STL PUGI_IMPL_FN void xml_document::save(std::basic_ostream& stream, const char_t* indent, unsigned int flags, xml_encoding encoding) const { xml_writer_stream writer(stream); save(writer, indent, flags, encoding); } PUGI_IMPL_FN void xml_document::save(std::basic_ostream& stream, const char_t* indent, unsigned int flags) const { xml_writer_stream writer(stream); save(writer, indent, flags, encoding_wchar); } #endif PUGI_IMPL_FN bool xml_document::save_file(const char* path_, const char_t* indent, unsigned int flags, xml_encoding encoding) const { using impl::auto_deleter; // MSVC7 workaround auto_deleter file(impl::open_file(path_, (flags & format_save_file_text) ? "w" : "wb"), impl::close_file); return impl::save_file_impl(*this, file.data, indent, flags, encoding) && fclose(file.release()) == 0; } PUGI_IMPL_FN bool xml_document::save_file(const wchar_t* path_, const char_t* indent, unsigned int flags, xml_encoding encoding) const { using impl::auto_deleter; // MSVC7 workaround auto_deleter file(impl::open_file_wide(path_, (flags & format_save_file_text) ? L"w" : L"wb"), impl::close_file); return impl::save_file_impl(*this, file.data, indent, flags, encoding) && fclose(file.release()) == 0; } PUGI_IMPL_FN xml_node xml_document::document_element() const { assert(_root); for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) if (PUGI_IMPL_NODETYPE(i) == node_element) return xml_node(i); return xml_node(); } #ifndef PUGIXML_NO_STL PUGI_IMPL_FN std::string PUGIXML_FUNCTION as_utf8(const wchar_t* str) { assert(str); return impl::as_utf8_impl(str, impl::strlength_wide(str)); } PUGI_IMPL_FN std::string PUGIXML_FUNCTION as_utf8(const std::basic_string& str) { return impl::as_utf8_impl(str.c_str(), str.size()); } PUGI_IMPL_FN std::basic_string PUGIXML_FUNCTION as_wide(const char* str) { assert(str); return impl::as_wide_impl(str, strlen(str)); } PUGI_IMPL_FN std::basic_string PUGIXML_FUNCTION as_wide(const std::string& str) { return impl::as_wide_impl(str.c_str(), str.size()); } #endif PUGI_IMPL_FN void PUGIXML_FUNCTION set_memory_management_functions(allocation_function allocate, deallocation_function deallocate) { impl::xml_memory::allocate = allocate; impl::xml_memory::deallocate = deallocate; } PUGI_IMPL_FN allocation_function PUGIXML_FUNCTION get_memory_allocation_function() { return impl::xml_memory::allocate; } PUGI_IMPL_FN deallocation_function PUGIXML_FUNCTION get_memory_deallocation_function() { return impl::xml_memory::deallocate; } } #if !defined(PUGIXML_NO_STL) && (defined(_MSC_VER) || defined(__ICC)) namespace std { // Workarounds for (non-standard) iterator category detection for older versions (MSVC7/IC8 and earlier) PUGI_IMPL_FN std::bidirectional_iterator_tag _Iter_cat(const pugi::xml_node_iterator&) { return std::bidirectional_iterator_tag(); } PUGI_IMPL_FN std::bidirectional_iterator_tag _Iter_cat(const pugi::xml_attribute_iterator&) { return std::bidirectional_iterator_tag(); } PUGI_IMPL_FN std::bidirectional_iterator_tag _Iter_cat(const pugi::xml_named_node_iterator&) { return std::bidirectional_iterator_tag(); } } #endif #if !defined(PUGIXML_NO_STL) && defined(__SUNPRO_CC) namespace std { // Workarounds for (non-standard) iterator category detection PUGI_IMPL_FN std::bidirectional_iterator_tag __iterator_category(const pugi::xml_node_iterator&) { return std::bidirectional_iterator_tag(); } PUGI_IMPL_FN std::bidirectional_iterator_tag __iterator_category(const pugi::xml_attribute_iterator&) { return std::bidirectional_iterator_tag(); } PUGI_IMPL_FN std::bidirectional_iterator_tag __iterator_category(const pugi::xml_named_node_iterator&) { return std::bidirectional_iterator_tag(); } } #endif #ifndef PUGIXML_NO_XPATH // STL replacements PUGI_IMPL_NS_BEGIN struct equal_to { template bool operator()(const T& lhs, const T& rhs) const { return lhs == rhs; } }; struct not_equal_to { template bool operator()(const T& lhs, const T& rhs) const { return lhs != rhs; } }; struct less { template bool operator()(const T& lhs, const T& rhs) const { return lhs < rhs; } }; struct less_equal { template bool operator()(const T& lhs, const T& rhs) const { return lhs <= rhs; } }; template inline void swap(T& lhs, T& rhs) { T temp = lhs; lhs = rhs; rhs = temp; } template PUGI_IMPL_FN I min_element(I begin, I end, const Pred& pred) { I result = begin; for (I it = begin + 1; it != end; ++it) if (pred(*it, *result)) result = it; return result; } template PUGI_IMPL_FN void reverse(I begin, I end) { while (end - begin > 1) swap(*begin++, *--end); } template PUGI_IMPL_FN I unique(I begin, I end) { // fast skip head while (end - begin > 1 && *begin != *(begin + 1)) begin++; if (begin == end) return begin; // last written element I write = begin++; // merge unique elements while (begin != end) { if (*begin != *write) *++write = *begin++; else begin++; } // past-the-end (write points to live element) return write + 1; } template PUGI_IMPL_FN void insertion_sort(T* begin, T* end, const Pred& pred) { if (begin == end) return; for (T* it = begin + 1; it != end; ++it) { T val = *it; T* hole = it; // move hole backwards while (hole > begin && pred(val, *(hole - 1))) { *hole = *(hole - 1); hole--; } // fill hole with element *hole = val; } } template inline I median3(I first, I middle, I last, const Pred& pred) { if (pred(*middle, *first)) swap(middle, first); if (pred(*last, *middle)) swap(last, middle); if (pred(*middle, *first)) swap(middle, first); return middle; } template PUGI_IMPL_FN void partition3(T* begin, T* end, T pivot, const Pred& pred, T** out_eqbeg, T** out_eqend) { // invariant: array is split into 4 groups: = < ? > (each variable denotes the boundary between the groups) T* eq = begin; T* lt = begin; T* gt = end; while (lt < gt) { if (pred(*lt, pivot)) lt++; else if (*lt == pivot) swap(*eq++, *lt++); else swap(*lt, *--gt); } // we now have just 4 groups: = < >; move equal elements to the middle T* eqbeg = gt; for (T* it = begin; it != eq; ++it) swap(*it, *--eqbeg); *out_eqbeg = eqbeg; *out_eqend = gt; } template PUGI_IMPL_FN void sort(I begin, I end, const Pred& pred) { // sort large chunks while (end - begin > 16) { // find median element I middle = begin + (end - begin) / 2; I median = median3(begin, middle, end - 1, pred); // partition in three chunks (< = >) I eqbeg, eqend; partition3(begin, end, *median, pred, &eqbeg, &eqend); // loop on larger half if (eqbeg - begin > end - eqend) { sort(eqend, end, pred); end = eqbeg; } else { sort(begin, eqbeg, pred); begin = eqend; } } // insertion sort small chunk insertion_sort(begin, end, pred); } PUGI_IMPL_FN bool hash_insert(const void** table, size_t size, const void* key) { assert(key); unsigned int h = static_cast(reinterpret_cast(key)); // MurmurHash3 32-bit finalizer h ^= h >> 16; h *= 0x85ebca6bu; h ^= h >> 13; h *= 0xc2b2ae35u; h ^= h >> 16; size_t hashmod = size - 1; size_t bucket = h & hashmod; for (size_t probe = 0; probe <= hashmod; ++probe) { if (table[bucket] == NULL) { table[bucket] = key; return true; } if (table[bucket] == key) return false; // hash collision, quadratic probing bucket = (bucket + probe + 1) & hashmod; } assert(false && "Hash table is full"); // unreachable return false; } PUGI_IMPL_NS_END // Allocator used for AST and evaluation stacks PUGI_IMPL_NS_BEGIN static const size_t xpath_memory_page_size = #ifdef PUGIXML_MEMORY_XPATH_PAGE_SIZE PUGIXML_MEMORY_XPATH_PAGE_SIZE #else 4096 #endif ; static const uintptr_t xpath_memory_block_alignment = sizeof(double) > sizeof(void*) ? sizeof(double) : sizeof(void*); struct xpath_memory_block { xpath_memory_block* next; size_t capacity; union { char data[xpath_memory_page_size]; double alignment; }; }; struct xpath_allocator { xpath_memory_block* _root; size_t _root_size; bool* _error; xpath_allocator(xpath_memory_block* root, bool* error = NULL): _root(root), _root_size(0), _error(error) { } void* allocate(size_t size) { // round size up to block alignment boundary size = (size + xpath_memory_block_alignment - 1) & ~(xpath_memory_block_alignment - 1); if (_root_size + size <= _root->capacity) { void* buf = &_root->data[0] + _root_size; _root_size += size; return buf; } else { // make sure we have at least 1/4th of the page free after allocation to satisfy subsequent allocation requests size_t block_capacity_base = sizeof(_root->data); size_t block_capacity_req = size + block_capacity_base / 4; size_t block_capacity = (block_capacity_base > block_capacity_req) ? block_capacity_base : block_capacity_req; size_t block_size = block_capacity + offsetof(xpath_memory_block, data); xpath_memory_block* block = static_cast(xml_memory::allocate(block_size)); if (!block) { if (_error) *_error = true; return NULL; } block->next = _root; block->capacity = block_capacity; _root = block; _root_size = size; return block->data; } } void* reallocate(void* ptr, size_t old_size, size_t new_size) { // round size up to block alignment boundary old_size = (old_size + xpath_memory_block_alignment - 1) & ~(xpath_memory_block_alignment - 1); new_size = (new_size + xpath_memory_block_alignment - 1) & ~(xpath_memory_block_alignment - 1); // we can only reallocate the last object assert(ptr == NULL || static_cast(ptr) + old_size == &_root->data[0] + _root_size); // try to reallocate the object inplace if (ptr && _root_size - old_size + new_size <= _root->capacity) { _root_size = _root_size - old_size + new_size; return ptr; } // allocate a new block void* result = allocate(new_size); if (!result) return NULL; // we have a new block if (ptr) { // copy old data (we only support growing) assert(new_size >= old_size); memcpy(result, ptr, old_size); // free the previous page if it had no other objects assert(_root->data == result); assert(_root->next); if (_root->next->data == ptr) { // deallocate the whole page, unless it was the first one xpath_memory_block* next = _root->next->next; if (next) { xml_memory::deallocate(_root->next); _root->next = next; } } } return result; } void revert(const xpath_allocator& state) { // free all new pages xpath_memory_block* cur = _root; while (cur != state._root) { xpath_memory_block* next = cur->next; xml_memory::deallocate(cur); cur = next; } // restore state _root = state._root; _root_size = state._root_size; } void release() { xpath_memory_block* cur = _root; assert(cur); while (cur->next) { xpath_memory_block* next = cur->next; xml_memory::deallocate(cur); cur = next; } } }; struct xpath_allocator_capture { xpath_allocator_capture(xpath_allocator* alloc): _target(alloc), _state(*alloc) { } ~xpath_allocator_capture() { _target->revert(_state); } xpath_allocator* _target; xpath_allocator _state; }; struct xpath_stack { xpath_allocator* result; xpath_allocator* temp; }; struct xpath_stack_data { xpath_memory_block blocks[2]; xpath_allocator result; xpath_allocator temp; xpath_stack stack; bool oom; xpath_stack_data(): result(blocks + 0, &oom), temp(blocks + 1, &oom), oom(false) { blocks[0].next = blocks[1].next = NULL; blocks[0].capacity = blocks[1].capacity = sizeof(blocks[0].data); stack.result = &result; stack.temp = &temp; } ~xpath_stack_data() { result.release(); temp.release(); } }; PUGI_IMPL_NS_END // String class PUGI_IMPL_NS_BEGIN class xpath_string { const char_t* _buffer; bool _uses_heap; size_t _length_heap; static char_t* duplicate_string(const char_t* string, size_t length, xpath_allocator* alloc) { char_t* result = static_cast(alloc->allocate((length + 1) * sizeof(char_t))); if (!result) return NULL; memcpy(result, string, length * sizeof(char_t)); result[length] = 0; return result; } xpath_string(const char_t* buffer, bool uses_heap_, size_t length_heap): _buffer(buffer), _uses_heap(uses_heap_), _length_heap(length_heap) { } public: static xpath_string from_const(const char_t* str) { return xpath_string(str, false, 0); } static xpath_string from_heap_preallocated(const char_t* begin, const char_t* end) { assert(begin <= end && *end == 0); return xpath_string(begin, true, static_cast(end - begin)); } static xpath_string from_heap(const char_t* begin, const char_t* end, xpath_allocator* alloc) { assert(begin <= end); if (begin == end) return xpath_string(); size_t length = static_cast(end - begin); const char_t* data = duplicate_string(begin, length, alloc); return data ? xpath_string(data, true, length) : xpath_string(); } xpath_string(): _buffer(PUGIXML_TEXT("")), _uses_heap(false), _length_heap(0) { } void append(const xpath_string& o, xpath_allocator* alloc) { // skip empty sources if (!*o._buffer) return; // fast append for constant empty target and constant source if (!*_buffer && !_uses_heap && !o._uses_heap) { _buffer = o._buffer; } else { // need to make heap copy size_t target_length = length(); size_t source_length = o.length(); size_t result_length = target_length + source_length; // allocate new buffer char_t* result = static_cast(alloc->reallocate(_uses_heap ? const_cast(_buffer) : NULL, (target_length + 1) * sizeof(char_t), (result_length + 1) * sizeof(char_t))); if (!result) return; // append first string to the new buffer in case there was no reallocation if (!_uses_heap) memcpy(result, _buffer, target_length * sizeof(char_t)); // append second string to the new buffer memcpy(result + target_length, o._buffer, source_length * sizeof(char_t)); result[result_length] = 0; // finalize _buffer = result; _uses_heap = true; _length_heap = result_length; } } const char_t* c_str() const { return _buffer; } size_t length() const { return _uses_heap ? _length_heap : strlength(_buffer); } char_t* data(xpath_allocator* alloc) { // make private heap copy if (!_uses_heap) { size_t length_ = strlength(_buffer); const char_t* data_ = duplicate_string(_buffer, length_, alloc); if (!data_) return NULL; _buffer = data_; _uses_heap = true; _length_heap = length_; } return const_cast(_buffer); } bool empty() const { return *_buffer == 0; } bool operator==(const xpath_string& o) const { return strequal(_buffer, o._buffer); } bool operator!=(const xpath_string& o) const { return !strequal(_buffer, o._buffer); } bool uses_heap() const { return _uses_heap; } }; PUGI_IMPL_NS_END PUGI_IMPL_NS_BEGIN PUGI_IMPL_FN bool starts_with(const char_t* string, const char_t* pattern) { while (*pattern && *string == *pattern) { string++; pattern++; } return *pattern == 0; } PUGI_IMPL_FN const char_t* find_char(const char_t* s, char_t c) { #ifdef PUGIXML_WCHAR_MODE return wcschr(s, c); #else return strchr(s, c); #endif } PUGI_IMPL_FN const char_t* find_substring(const char_t* s, const char_t* p) { #ifdef PUGIXML_WCHAR_MODE // MSVC6 wcsstr bug workaround (if s is empty it always returns 0) return (*p == 0) ? s : wcsstr(s, p); #else return strstr(s, p); #endif } // Converts symbol to lower case, if it is an ASCII one PUGI_IMPL_FN char_t tolower_ascii(char_t ch) { return static_cast(ch - 'A') < 26 ? static_cast(ch | ' ') : ch; } PUGI_IMPL_FN xpath_string string_value(const xpath_node& na, xpath_allocator* alloc) { if (na.attribute()) return xpath_string::from_const(na.attribute().value()); else { xml_node n = na.node(); switch (n.type()) { case node_pcdata: case node_cdata: case node_comment: case node_pi: return xpath_string::from_const(n.value()); case node_document: case node_element: { xpath_string result; // element nodes can have value if parse_embed_pcdata was used if (n.value()[0]) result.append(xpath_string::from_const(n.value()), alloc); xml_node cur = n.first_child(); while (cur && cur != n) { if (cur.type() == node_pcdata || cur.type() == node_cdata) result.append(xpath_string::from_const(cur.value()), alloc); if (cur.first_child()) cur = cur.first_child(); else if (cur.next_sibling()) cur = cur.next_sibling(); else { while (!cur.next_sibling() && cur != n) cur = cur.parent(); if (cur != n) cur = cur.next_sibling(); } } return result; } default: return xpath_string(); } } } PUGI_IMPL_FN bool node_is_before_sibling(xml_node_struct* ln, xml_node_struct* rn) { assert(ln->parent == rn->parent); // there is no common ancestor (the shared parent is null), nodes are from different documents if (!ln->parent) return ln < rn; // determine sibling order xml_node_struct* ls = ln; xml_node_struct* rs = rn; while (ls && rs) { if (ls == rn) return true; if (rs == ln) return false; ls = ls->next_sibling; rs = rs->next_sibling; } // if rn sibling chain ended ln must be before rn return !rs; } PUGI_IMPL_FN bool node_is_before(xml_node_struct* ln, xml_node_struct* rn) { // find common ancestor at the same depth, if any xml_node_struct* lp = ln; xml_node_struct* rp = rn; while (lp && rp && lp->parent != rp->parent) { lp = lp->parent; rp = rp->parent; } // parents are the same! if (lp && rp) return node_is_before_sibling(lp, rp); // nodes are at different depths, need to normalize heights bool left_higher = !lp; while (lp) { lp = lp->parent; ln = ln->parent; } while (rp) { rp = rp->parent; rn = rn->parent; } // one node is the ancestor of the other if (ln == rn) return left_higher; // find common ancestor... again while (ln->parent != rn->parent) { ln = ln->parent; rn = rn->parent; } return node_is_before_sibling(ln, rn); } PUGI_IMPL_FN bool node_is_ancestor(xml_node_struct* parent, xml_node_struct* node) { while (node && node != parent) node = node->parent; return parent && node == parent; } PUGI_IMPL_FN const void* document_buffer_order(const xpath_node& xnode) { xml_node_struct* node = xnode.node().internal_object(); if (node) { if ((get_document(node).header & xml_memory_page_contents_shared_mask) == 0) { if (node->name && (node->header & impl::xml_memory_page_name_allocated_or_shared_mask) == 0) return node->name; if (node->value && (node->header & impl::xml_memory_page_value_allocated_or_shared_mask) == 0) return node->value; } return NULL; } xml_attribute_struct* attr = xnode.attribute().internal_object(); if (attr) { if ((get_document(attr).header & xml_memory_page_contents_shared_mask) == 0) { if ((attr->header & impl::xml_memory_page_name_allocated_or_shared_mask) == 0) return attr->name; if ((attr->header & impl::xml_memory_page_value_allocated_or_shared_mask) == 0) return attr->value; } return NULL; } return NULL; } struct document_order_comparator { bool operator()(const xpath_node& lhs, const xpath_node& rhs) const { // optimized document order based check const void* lo = document_buffer_order(lhs); const void* ro = document_buffer_order(rhs); if (lo && ro) return lo < ro; // slow comparison xml_node ln = lhs.node(), rn = rhs.node(); // compare attributes if (lhs.attribute() && rhs.attribute()) { // shared parent if (lhs.parent() == rhs.parent()) { // determine sibling order for (xml_attribute a = lhs.attribute(); a; a = a.next_attribute()) if (a == rhs.attribute()) return true; return false; } // compare attribute parents ln = lhs.parent(); rn = rhs.parent(); } else if (lhs.attribute()) { // attributes go after the parent element if (lhs.parent() == rhs.node()) return false; ln = lhs.parent(); } else if (rhs.attribute()) { // attributes go after the parent element if (rhs.parent() == lhs.node()) return true; rn = rhs.parent(); } if (ln == rn) return false; if (!ln || !rn) return ln < rn; return node_is_before(ln.internal_object(), rn.internal_object()); } }; PUGI_IMPL_FN double gen_nan() { #if defined(__STDC_IEC_559__) || ((FLT_RADIX - 0 == 2) && (FLT_MAX_EXP - 0 == 128) && (FLT_MANT_DIG - 0 == 24)) PUGI_IMPL_STATIC_ASSERT(sizeof(float) == sizeof(uint32_t)); typedef uint32_t UI; // BCC5 workaround union { float f; UI i; } u; u.i = 0x7fc00000; return double(u.f); #else // fallback const volatile double zero = 0.0; return zero / zero; #endif } PUGI_IMPL_FN bool is_nan(double value) { #if defined(PUGI_IMPL_MSVC_CRT_VERSION) || defined(__BORLANDC__) return !!_isnan(value); #elif defined(fpclassify) && defined(FP_NAN) return fpclassify(value) == FP_NAN; #else // fallback const volatile double v = value; return v != v; #endif } PUGI_IMPL_FN const char_t* convert_number_to_string_special(double value) { #if defined(PUGI_IMPL_MSVC_CRT_VERSION) || defined(__BORLANDC__) if (_finite(value)) return (value == 0) ? PUGIXML_TEXT("0") : 0; if (_isnan(value)) return PUGIXML_TEXT("NaN"); return value > 0 ? PUGIXML_TEXT("Infinity") : PUGIXML_TEXT("-Infinity"); #elif defined(fpclassify) && defined(FP_NAN) && defined(FP_INFINITE) && defined(FP_ZERO) switch (fpclassify(value)) { case FP_NAN: return PUGIXML_TEXT("NaN"); case FP_INFINITE: return value > 0 ? PUGIXML_TEXT("Infinity") : PUGIXML_TEXT("-Infinity"); case FP_ZERO: return PUGIXML_TEXT("0"); default: return 0; } #else // fallback const volatile double v = value; if (v == 0) return PUGIXML_TEXT("0"); if (v != v) return PUGIXML_TEXT("NaN"); if (v * 2 == v) return value > 0 ? PUGIXML_TEXT("Infinity") : PUGIXML_TEXT("-Infinity"); return NULL; #endif } PUGI_IMPL_FN bool convert_number_to_boolean(double value) { return (value != 0 && !is_nan(value)); } PUGI_IMPL_FN void truncate_zeros(char* begin, char* end) { while (begin != end && end[-1] == '0') end--; *end = 0; } // gets mantissa digits in the form of 0.xxxxx with 0. implied and the exponent #if defined(PUGI_IMPL_MSVC_CRT_VERSION) && PUGI_IMPL_MSVC_CRT_VERSION >= 1400 PUGI_IMPL_FN void convert_number_to_mantissa_exponent(double value, char (&buffer)[32], char** out_mantissa, int* out_exponent) { // get base values int sign, exponent; _ecvt_s(buffer, sizeof(buffer), value, DBL_DIG + 1, &exponent, &sign); // truncate redundant zeros truncate_zeros(buffer, buffer + strlen(buffer)); // fill results *out_mantissa = buffer; *out_exponent = exponent; } #else PUGI_IMPL_FN void convert_number_to_mantissa_exponent(double value, char (&buffer)[32], char** out_mantissa, int* out_exponent) { // get a scientific notation value with IEEE DBL_DIG decimals PUGI_IMPL_SNPRINTF(buffer, "%.*e", DBL_DIG, value); // get the exponent (possibly negative) char* exponent_string = strchr(buffer, 'e'); assert(exponent_string); int exponent = atoi(exponent_string + 1); // extract mantissa string: skip sign char* mantissa = buffer[0] == '-' ? buffer + 1 : buffer; assert(mantissa[0] != '0' && (mantissa[1] == '.' || mantissa[1] == ',')); // divide mantissa by 10 to eliminate integer part mantissa[1] = mantissa[0]; mantissa++; exponent++; // remove extra mantissa digits and zero-terminate mantissa truncate_zeros(mantissa, exponent_string); // fill results *out_mantissa = mantissa; *out_exponent = exponent; } #endif PUGI_IMPL_FN xpath_string convert_number_to_string(double value, xpath_allocator* alloc) { // try special number conversion const char_t* special = convert_number_to_string_special(value); if (special) return xpath_string::from_const(special); // get mantissa + exponent form char mantissa_buffer[32]; char* mantissa; int exponent; convert_number_to_mantissa_exponent(value, mantissa_buffer, &mantissa, &exponent); // allocate a buffer of suitable length for the number size_t result_size = strlen(mantissa_buffer) + (exponent > 0 ? exponent : -exponent) + 4; char_t* result = static_cast(alloc->allocate(sizeof(char_t) * result_size)); if (!result) return xpath_string(); // make the number! char_t* s = result; // sign if (value < 0) *s++ = '-'; // integer part if (exponent <= 0) { *s++ = '0'; } else { while (exponent > 0) { assert(*mantissa == 0 || static_cast(*mantissa - '0') <= 9); *s++ = *mantissa ? *mantissa++ : '0'; exponent--; } } // fractional part if (*mantissa) { // decimal point *s++ = '.'; // extra zeroes from negative exponent while (exponent < 0) { *s++ = '0'; exponent++; } // extra mantissa digits while (*mantissa) { assert(static_cast(*mantissa - '0') <= 9); *s++ = *mantissa++; } } // zero-terminate assert(s < result + result_size); *s = 0; return xpath_string::from_heap_preallocated(result, s); } PUGI_IMPL_FN bool check_string_to_number_format(const char_t* string) { // parse leading whitespace while (PUGI_IMPL_IS_CHARTYPE(*string, ct_space)) ++string; // parse sign if (*string == '-') ++string; if (!*string) return false; // if there is no integer part, there should be a decimal part with at least one digit if (!PUGI_IMPL_IS_CHARTYPEX(string[0], ctx_digit) && (string[0] != '.' || !PUGI_IMPL_IS_CHARTYPEX(string[1], ctx_digit))) return false; // parse integer part while (PUGI_IMPL_IS_CHARTYPEX(*string, ctx_digit)) ++string; // parse decimal part if (*string == '.') { ++string; while (PUGI_IMPL_IS_CHARTYPEX(*string, ctx_digit)) ++string; } // parse trailing whitespace while (PUGI_IMPL_IS_CHARTYPE(*string, ct_space)) ++string; return *string == 0; } PUGI_IMPL_FN double convert_string_to_number(const char_t* string) { // check string format if (!check_string_to_number_format(string)) return gen_nan(); // parse string #ifdef PUGIXML_WCHAR_MODE return wcstod(string, NULL); #else return strtod(string, NULL); #endif } PUGI_IMPL_FN bool convert_string_to_number_scratch(char_t (&buffer)[32], const char_t* begin, const char_t* end, double* out_result) { size_t length = static_cast(end - begin); char_t* scratch = buffer; if (length >= sizeof(buffer) / sizeof(buffer[0])) { // need to make dummy on-heap copy scratch = static_cast(xml_memory::allocate((length + 1) * sizeof(char_t))); if (!scratch) return false; } // copy string to zero-terminated buffer and perform conversion memcpy(scratch, begin, length * sizeof(char_t)); scratch[length] = 0; *out_result = convert_string_to_number(scratch); // free dummy buffer if (scratch != buffer) xml_memory::deallocate(scratch); return true; } PUGI_IMPL_FN double round_nearest(double value) { return floor(value + 0.5); } PUGI_IMPL_FN double round_nearest_nzero(double value) { // same as round_nearest, but returns -0 for [-0.5, -0] // ceil is used to differentiate between +0 and -0 (we return -0 for [-0.5, -0] and +0 for +0) return (value >= -0.5 && value <= 0) ? ceil(value) : floor(value + 0.5); } PUGI_IMPL_FN const char_t* qualified_name(const xpath_node& node) { return node.attribute() ? node.attribute().name() : node.node().name(); } PUGI_IMPL_FN const char_t* local_name(const xpath_node& node) { const char_t* name = qualified_name(node); const char_t* p = find_char(name, ':'); return p ? p + 1 : name; } struct namespace_uri_predicate { const char_t* prefix; size_t prefix_length; namespace_uri_predicate(const char_t* name) { const char_t* pos = find_char(name, ':'); prefix = pos ? name : NULL; prefix_length = pos ? static_cast(pos - name) : 0; } bool operator()(xml_attribute a) const { const char_t* name = a.name(); if (!starts_with(name, PUGIXML_TEXT("xmlns"))) return false; return prefix ? name[5] == ':' && strequalrange(name + 6, prefix, prefix_length) : name[5] == 0; } }; PUGI_IMPL_FN const char_t* namespace_uri(xml_node node) { namespace_uri_predicate pred = node.name(); xml_node p = node; while (p) { xml_attribute a = p.find_attribute(pred); if (a) return a.value(); p = p.parent(); } return PUGIXML_TEXT(""); } PUGI_IMPL_FN const char_t* namespace_uri(xml_attribute attr, xml_node parent) { namespace_uri_predicate pred = attr.name(); // Default namespace does not apply to attributes if (!pred.prefix) return PUGIXML_TEXT(""); xml_node p = parent; while (p) { xml_attribute a = p.find_attribute(pred); if (a) return a.value(); p = p.parent(); } return PUGIXML_TEXT(""); } PUGI_IMPL_FN const char_t* namespace_uri(const xpath_node& node) { return node.attribute() ? namespace_uri(node.attribute(), node.parent()) : namespace_uri(node.node()); } PUGI_IMPL_FN char_t* normalize_space(char_t* buffer) { char_t* write = buffer; for (char_t* it = buffer; *it; ) { char_t ch = *it++; if (PUGI_IMPL_IS_CHARTYPE(ch, ct_space)) { // replace whitespace sequence with single space while (PUGI_IMPL_IS_CHARTYPE(*it, ct_space)) it++; // avoid leading spaces if (write != buffer) *write++ = ' '; } else *write++ = ch; } // remove trailing space if (write != buffer && PUGI_IMPL_IS_CHARTYPE(write[-1], ct_space)) write--; // zero-terminate *write = 0; return write; } PUGI_IMPL_FN char_t* translate(char_t* buffer, const char_t* from, const char_t* to, size_t to_length) { char_t* write = buffer; while (*buffer) { PUGI_IMPL_DMC_VOLATILE char_t ch = *buffer++; const char_t* pos = find_char(from, ch); if (!pos) *write++ = ch; // do not process else if (static_cast(pos - from) < to_length) *write++ = to[pos - from]; // replace } // zero-terminate *write = 0; return write; } PUGI_IMPL_FN unsigned char* translate_table_generate(xpath_allocator* alloc, const char_t* from, const char_t* to) { unsigned char table[128] = {0}; while (*from) { unsigned int fc = static_cast(*from); unsigned int tc = static_cast(*to); if (fc >= 128 || tc >= 128) return NULL; // code=128 means "skip character" if (!table[fc]) table[fc] = static_cast(tc ? tc : 128); from++; if (tc) to++; } for (int i = 0; i < 128; ++i) if (!table[i]) table[i] = static_cast(i); void* result = alloc->allocate(sizeof(table)); if (!result) return NULL; memcpy(result, table, sizeof(table)); return static_cast(result); } PUGI_IMPL_FN char_t* translate_table(char_t* buffer, const unsigned char* table) { char_t* write = buffer; while (*buffer) { char_t ch = *buffer++; unsigned int index = static_cast(ch); if (index < 128) { unsigned char code = table[index]; // code=128 means "skip character" (table size is 128 so 128 can be a special value) // this code skips these characters without extra branches *write = static_cast(code); write += 1 - (code >> 7); } else { *write++ = ch; } } // zero-terminate *write = 0; return write; } inline bool is_xpath_attribute(const char_t* name) { return !(starts_with(name, PUGIXML_TEXT("xmlns")) && (name[5] == 0 || name[5] == ':')); } struct xpath_variable_boolean: xpath_variable { xpath_variable_boolean(): xpath_variable(xpath_type_boolean), value(false) { } bool value; char_t name[1]; }; struct xpath_variable_number: xpath_variable { xpath_variable_number(): xpath_variable(xpath_type_number), value(0) { } double value; char_t name[1]; }; struct xpath_variable_string: xpath_variable { xpath_variable_string(): xpath_variable(xpath_type_string), value(NULL) { } ~xpath_variable_string() { if (value) xml_memory::deallocate(value); } char_t* value; char_t name[1]; }; struct xpath_variable_node_set: xpath_variable { xpath_variable_node_set(): xpath_variable(xpath_type_node_set) { } xpath_node_set value; char_t name[1]; }; static const xpath_node_set dummy_node_set; PUGI_IMPL_FN PUGI_IMPL_UNSIGNED_OVERFLOW unsigned int hash_string(const char_t* str) { // Jenkins one-at-a-time hash (http://en.wikipedia.org/wiki/Jenkins_hash_function#one-at-a-time) unsigned int result = 0; while (*str) { result += static_cast(*str++); result += result << 10; result ^= result >> 6; } result += result << 3; result ^= result >> 11; result += result << 15; return result; } template PUGI_IMPL_FN T* new_xpath_variable(const char_t* name) { size_t length = strlength(name); if (length == 0) return NULL; // empty variable names are invalid // $$ we can't use offsetof(T, name) because T is non-POD, so we just allocate additional length characters void* memory = xml_memory::allocate(sizeof(T) + length * sizeof(char_t)); if (!memory) return NULL; T* result = new (memory) T(); memcpy(result->name, name, (length + 1) * sizeof(char_t)); return result; } PUGI_IMPL_FN xpath_variable* new_xpath_variable(xpath_value_type type, const char_t* name) { switch (type) { case xpath_type_node_set: return new_xpath_variable(name); case xpath_type_number: return new_xpath_variable(name); case xpath_type_string: return new_xpath_variable(name); case xpath_type_boolean: return new_xpath_variable(name); default: return NULL; } } template PUGI_IMPL_FN void delete_xpath_variable(T* var) { var->~T(); xml_memory::deallocate(var); } PUGI_IMPL_FN void delete_xpath_variable(xpath_value_type type, xpath_variable* var) { switch (type) { case xpath_type_node_set: delete_xpath_variable(static_cast(var)); break; case xpath_type_number: delete_xpath_variable(static_cast(var)); break; case xpath_type_string: delete_xpath_variable(static_cast(var)); break; case xpath_type_boolean: delete_xpath_variable(static_cast(var)); break; default: assert(false && "Invalid variable type"); // unreachable } } PUGI_IMPL_FN bool copy_xpath_variable(xpath_variable* lhs, const xpath_variable* rhs) { switch (rhs->type()) { case xpath_type_node_set: return lhs->set(static_cast(rhs)->value); case xpath_type_number: return lhs->set(static_cast(rhs)->value); case xpath_type_string: return lhs->set(static_cast(rhs)->value); case xpath_type_boolean: return lhs->set(static_cast(rhs)->value); default: assert(false && "Invalid variable type"); // unreachable return false; } } PUGI_IMPL_FN bool get_variable_scratch(char_t (&buffer)[32], xpath_variable_set* set, const char_t* begin, const char_t* end, xpath_variable** out_result) { size_t length = static_cast(end - begin); char_t* scratch = buffer; if (length >= sizeof(buffer) / sizeof(buffer[0])) { // need to make dummy on-heap copy scratch = static_cast(xml_memory::allocate((length + 1) * sizeof(char_t))); if (!scratch) return false; } // copy string to zero-terminated buffer and perform lookup memcpy(scratch, begin, length * sizeof(char_t)); scratch[length] = 0; *out_result = set->get(scratch); // free dummy buffer if (scratch != buffer) xml_memory::deallocate(scratch); return true; } PUGI_IMPL_NS_END // Internal node set class PUGI_IMPL_NS_BEGIN PUGI_IMPL_FN xpath_node_set::type_t xpath_get_order(const xpath_node* begin, const xpath_node* end) { if (end - begin < 2) return xpath_node_set::type_sorted; document_order_comparator cmp; bool first = cmp(begin[0], begin[1]); for (const xpath_node* it = begin + 1; it + 1 < end; ++it) if (cmp(it[0], it[1]) != first) return xpath_node_set::type_unsorted; return first ? xpath_node_set::type_sorted : xpath_node_set::type_sorted_reverse; } PUGI_IMPL_FN xpath_node_set::type_t xpath_sort(xpath_node* begin, xpath_node* end, xpath_node_set::type_t type, bool rev) { xpath_node_set::type_t order = rev ? xpath_node_set::type_sorted_reverse : xpath_node_set::type_sorted; if (type == xpath_node_set::type_unsorted) { xpath_node_set::type_t sorted = xpath_get_order(begin, end); if (sorted == xpath_node_set::type_unsorted) { sort(begin, end, document_order_comparator()); type = xpath_node_set::type_sorted; } else type = sorted; } if (type != order) reverse(begin, end); return order; } PUGI_IMPL_FN xpath_node xpath_first(const xpath_node* begin, const xpath_node* end, xpath_node_set::type_t type) { if (begin == end) return xpath_node(); switch (type) { case xpath_node_set::type_sorted: return *begin; case xpath_node_set::type_sorted_reverse: return *(end - 1); case xpath_node_set::type_unsorted: return *min_element(begin, end, document_order_comparator()); default: assert(false && "Invalid node set type"); // unreachable return xpath_node(); } } class xpath_node_set_raw { xpath_node_set::type_t _type; xpath_node* _begin; xpath_node* _end; xpath_node* _eos; public: xpath_node_set_raw(): _type(xpath_node_set::type_unsorted), _begin(NULL), _end(NULL), _eos(NULL) { } xpath_node* begin() const { return _begin; } xpath_node* end() const { return _end; } bool empty() const { return _begin == _end; } size_t size() const { return static_cast(_end - _begin); } xpath_node first() const { return xpath_first(_begin, _end, _type); } void push_back_grow(const xpath_node& node, xpath_allocator* alloc); void push_back(const xpath_node& node, xpath_allocator* alloc) { if (_end != _eos) *_end++ = node; else push_back_grow(node, alloc); } void append(const xpath_node* begin_, const xpath_node* end_, xpath_allocator* alloc) { if (begin_ == end_) return; size_t size_ = static_cast(_end - _begin); size_t capacity = static_cast(_eos - _begin); size_t count = static_cast(end_ - begin_); if (size_ + count > capacity) { // reallocate the old array or allocate a new one xpath_node* data = static_cast(alloc->reallocate(_begin, capacity * sizeof(xpath_node), (size_ + count) * sizeof(xpath_node))); if (!data) return; // finalize _begin = data; _end = data + size_; _eos = data + size_ + count; } memcpy(_end, begin_, count * sizeof(xpath_node)); _end += count; } void sort_do() { _type = xpath_sort(_begin, _end, _type, false); } void truncate(xpath_node* pos) { assert(_begin <= pos && pos <= _end); _end = pos; } void remove_duplicates(xpath_allocator* alloc) { if (_type == xpath_node_set::type_unsorted && _end - _begin > 2) { xpath_allocator_capture cr(alloc); size_t size_ = static_cast(_end - _begin); size_t hash_size = 1; while (hash_size < size_ + size_ / 2) hash_size *= 2; const void** hash_data = static_cast(alloc->allocate(hash_size * sizeof(void**))); if (!hash_data) return; memset(hash_data, 0, hash_size * sizeof(const void**)); xpath_node* write = _begin; for (xpath_node* it = _begin; it != _end; ++it) { const void* attr = it->attribute().internal_object(); const void* node = it->node().internal_object(); const void* key = attr ? attr : node; if (key && hash_insert(hash_data, hash_size, key)) { *write++ = *it; } } _end = write; } else { _end = unique(_begin, _end); } } xpath_node_set::type_t type() const { return _type; } void set_type(xpath_node_set::type_t value) { _type = value; } }; PUGI_IMPL_FN_NO_INLINE void xpath_node_set_raw::push_back_grow(const xpath_node& node, xpath_allocator* alloc) { size_t capacity = static_cast(_eos - _begin); // get new capacity (1.5x rule) size_t new_capacity = capacity + capacity / 2 + 1; // reallocate the old array or allocate a new one xpath_node* data = static_cast(alloc->reallocate(_begin, capacity * sizeof(xpath_node), new_capacity * sizeof(xpath_node))); if (!data) return; // finalize _begin = data; _end = data + capacity; _eos = data + new_capacity; // push *_end++ = node; } PUGI_IMPL_NS_END PUGI_IMPL_NS_BEGIN struct xpath_context { xpath_node n; size_t position, size; xpath_context(const xpath_node& n_, size_t position_, size_t size_): n(n_), position(position_), size(size_) { } }; enum lexeme_t { lex_none = 0, lex_equal, lex_not_equal, lex_less, lex_greater, lex_less_or_equal, lex_greater_or_equal, lex_plus, lex_minus, lex_multiply, lex_union, lex_var_ref, lex_open_brace, lex_close_brace, lex_quoted_string, lex_number, lex_slash, lex_double_slash, lex_open_square_brace, lex_close_square_brace, lex_string, lex_comma, lex_axis_attribute, lex_dot, lex_double_dot, lex_double_colon, lex_eof }; struct xpath_lexer_string { const char_t* begin; const char_t* end; xpath_lexer_string(): begin(NULL), end(NULL) { } bool operator==(const char_t* other) const { size_t length = static_cast(end - begin); return strequalrange(other, begin, length); } }; class xpath_lexer { const char_t* _cur; const char_t* _cur_lexeme_pos; xpath_lexer_string _cur_lexeme_contents; lexeme_t _cur_lexeme; public: explicit xpath_lexer(const char_t* query): _cur(query) { next(); } const char_t* state() const { return _cur; } void next() { const char_t* cur = _cur; while (PUGI_IMPL_IS_CHARTYPE(*cur, ct_space)) ++cur; // save lexeme position for error reporting _cur_lexeme_pos = cur; switch (*cur) { case 0: _cur_lexeme = lex_eof; break; case '>': if (*(cur+1) == '=') { cur += 2; _cur_lexeme = lex_greater_or_equal; } else { cur += 1; _cur_lexeme = lex_greater; } break; case '<': if (*(cur+1) == '=') { cur += 2; _cur_lexeme = lex_less_or_equal; } else { cur += 1; _cur_lexeme = lex_less; } break; case '!': if (*(cur+1) == '=') { cur += 2; _cur_lexeme = lex_not_equal; } else { _cur_lexeme = lex_none; } break; case '=': cur += 1; _cur_lexeme = lex_equal; break; case '+': cur += 1; _cur_lexeme = lex_plus; break; case '-': cur += 1; _cur_lexeme = lex_minus; break; case '*': cur += 1; _cur_lexeme = lex_multiply; break; case '|': cur += 1; _cur_lexeme = lex_union; break; case '$': cur += 1; if (PUGI_IMPL_IS_CHARTYPEX(*cur, ctx_start_symbol)) { _cur_lexeme_contents.begin = cur; while (PUGI_IMPL_IS_CHARTYPEX(*cur, ctx_symbol)) cur++; if (cur[0] == ':' && PUGI_IMPL_IS_CHARTYPEX(cur[1], ctx_symbol)) // qname { cur++; // : while (PUGI_IMPL_IS_CHARTYPEX(*cur, ctx_symbol)) cur++; } _cur_lexeme_contents.end = cur; _cur_lexeme = lex_var_ref; } else { _cur_lexeme = lex_none; } break; case '(': cur += 1; _cur_lexeme = lex_open_brace; break; case ')': cur += 1; _cur_lexeme = lex_close_brace; break; case '[': cur += 1; _cur_lexeme = lex_open_square_brace; break; case ']': cur += 1; _cur_lexeme = lex_close_square_brace; break; case ',': cur += 1; _cur_lexeme = lex_comma; break; case '/': if (*(cur+1) == '/') { cur += 2; _cur_lexeme = lex_double_slash; } else { cur += 1; _cur_lexeme = lex_slash; } break; case '.': if (*(cur+1) == '.') { cur += 2; _cur_lexeme = lex_double_dot; } else if (PUGI_IMPL_IS_CHARTYPEX(*(cur+1), ctx_digit)) { _cur_lexeme_contents.begin = cur; // . ++cur; while (PUGI_IMPL_IS_CHARTYPEX(*cur, ctx_digit)) cur++; _cur_lexeme_contents.end = cur; _cur_lexeme = lex_number; } else { cur += 1; _cur_lexeme = lex_dot; } break; case '@': cur += 1; _cur_lexeme = lex_axis_attribute; break; case '"': case '\'': { char_t terminator = *cur; ++cur; _cur_lexeme_contents.begin = cur; while (*cur && *cur != terminator) cur++; _cur_lexeme_contents.end = cur; if (!*cur) _cur_lexeme = lex_none; else { cur += 1; _cur_lexeme = lex_quoted_string; } break; } case ':': if (*(cur+1) == ':') { cur += 2; _cur_lexeme = lex_double_colon; } else { _cur_lexeme = lex_none; } break; default: if (PUGI_IMPL_IS_CHARTYPEX(*cur, ctx_digit)) { _cur_lexeme_contents.begin = cur; while (PUGI_IMPL_IS_CHARTYPEX(*cur, ctx_digit)) cur++; if (*cur == '.') { cur++; while (PUGI_IMPL_IS_CHARTYPEX(*cur, ctx_digit)) cur++; } _cur_lexeme_contents.end = cur; _cur_lexeme = lex_number; } else if (PUGI_IMPL_IS_CHARTYPEX(*cur, ctx_start_symbol)) { _cur_lexeme_contents.begin = cur; while (PUGI_IMPL_IS_CHARTYPEX(*cur, ctx_symbol)) cur++; if (cur[0] == ':') { if (cur[1] == '*') // namespace test ncname:* { cur += 2; // :* } else if (PUGI_IMPL_IS_CHARTYPEX(cur[1], ctx_symbol)) // namespace test qname { cur++; // : while (PUGI_IMPL_IS_CHARTYPEX(*cur, ctx_symbol)) cur++; } } _cur_lexeme_contents.end = cur; _cur_lexeme = lex_string; } else { _cur_lexeme = lex_none; } } _cur = cur; } lexeme_t current() const { return _cur_lexeme; } const char_t* current_pos() const { return _cur_lexeme_pos; } const xpath_lexer_string& contents() const { assert(_cur_lexeme == lex_var_ref || _cur_lexeme == lex_number || _cur_lexeme == lex_string || _cur_lexeme == lex_quoted_string); return _cur_lexeme_contents; } }; enum ast_type_t { ast_unknown, ast_op_or, // left or right ast_op_and, // left and right ast_op_equal, // left = right ast_op_not_equal, // left != right ast_op_less, // left < right ast_op_greater, // left > right ast_op_less_or_equal, // left <= right ast_op_greater_or_equal, // left >= right ast_op_add, // left + right ast_op_subtract, // left - right ast_op_multiply, // left * right ast_op_divide, // left / right ast_op_mod, // left % right ast_op_negate, // left - right ast_op_union, // left | right ast_predicate, // apply predicate to set; next points to next predicate ast_filter, // select * from left where right ast_string_constant, // string constant ast_number_constant, // number constant ast_variable, // variable ast_func_last, // last() ast_func_position, // position() ast_func_count, // count(left) ast_func_id, // id(left) ast_func_local_name_0, // local-name() ast_func_local_name_1, // local-name(left) ast_func_namespace_uri_0, // namespace-uri() ast_func_namespace_uri_1, // namespace-uri(left) ast_func_name_0, // name() ast_func_name_1, // name(left) ast_func_string_0, // string() ast_func_string_1, // string(left) ast_func_concat, // concat(left, right, siblings) ast_func_starts_with, // starts_with(left, right) ast_func_contains, // contains(left, right) ast_func_substring_before, // substring-before(left, right) ast_func_substring_after, // substring-after(left, right) ast_func_substring_2, // substring(left, right) ast_func_substring_3, // substring(left, right, third) ast_func_string_length_0, // string-length() ast_func_string_length_1, // string-length(left) ast_func_normalize_space_0, // normalize-space() ast_func_normalize_space_1, // normalize-space(left) ast_func_translate, // translate(left, right, third) ast_func_boolean, // boolean(left) ast_func_not, // not(left) ast_func_true, // true() ast_func_false, // false() ast_func_lang, // lang(left) ast_func_number_0, // number() ast_func_number_1, // number(left) ast_func_sum, // sum(left) ast_func_floor, // floor(left) ast_func_ceiling, // ceiling(left) ast_func_round, // round(left) ast_step, // process set left with step ast_step_root, // select root node ast_opt_translate_table, // translate(left, right, third) where right/third are constants ast_opt_compare_attribute // @name = 'string' }; enum axis_t { axis_ancestor, axis_ancestor_or_self, axis_attribute, axis_child, axis_descendant, axis_descendant_or_self, axis_following, axis_following_sibling, axis_namespace, axis_parent, axis_preceding, axis_preceding_sibling, axis_self }; enum nodetest_t { nodetest_none, nodetest_name, nodetest_type_node, nodetest_type_comment, nodetest_type_pi, nodetest_type_text, nodetest_pi, nodetest_all, nodetest_all_in_namespace }; enum predicate_t { predicate_default, predicate_posinv, predicate_constant, predicate_constant_one }; enum nodeset_eval_t { nodeset_eval_all, nodeset_eval_any, nodeset_eval_first }; template struct axis_to_type { static const axis_t axis; }; template const axis_t axis_to_type::axis = N; class xpath_ast_node { private: // node type char _type; char _rettype; // for ast_step char _axis; // for ast_step/ast_predicate/ast_filter char _test; // tree node structure xpath_ast_node* _left; xpath_ast_node* _right; xpath_ast_node* _next; union { // value for ast_string_constant const char_t* string; // value for ast_number_constant double number; // variable for ast_variable xpath_variable* variable; // node test for ast_step (node name/namespace/node type/pi target) const char_t* nodetest; // table for ast_opt_translate_table const unsigned char* table; } _data; xpath_ast_node(const xpath_ast_node&); xpath_ast_node& operator=(const xpath_ast_node&); template static bool compare_eq(xpath_ast_node* lhs, xpath_ast_node* rhs, const xpath_context& c, const xpath_stack& stack, const Comp& comp) { xpath_value_type lt = lhs->rettype(), rt = rhs->rettype(); if (lt != xpath_type_node_set && rt != xpath_type_node_set) { if (lt == xpath_type_boolean || rt == xpath_type_boolean) return comp(lhs->eval_boolean(c, stack), rhs->eval_boolean(c, stack)); else if (lt == xpath_type_number || rt == xpath_type_number) return comp(lhs->eval_number(c, stack), rhs->eval_number(c, stack)); else if (lt == xpath_type_string || rt == xpath_type_string) { xpath_allocator_capture cr(stack.result); xpath_string ls = lhs->eval_string(c, stack); xpath_string rs = rhs->eval_string(c, stack); return comp(ls, rs); } } else if (lt == xpath_type_node_set && rt == xpath_type_node_set) { xpath_allocator_capture cr(stack.result); xpath_node_set_raw ls = lhs->eval_node_set(c, stack, nodeset_eval_all); xpath_node_set_raw rs = rhs->eval_node_set(c, stack, nodeset_eval_all); for (const xpath_node* li = ls.begin(); li != ls.end(); ++li) for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri) { xpath_allocator_capture cri(stack.result); if (comp(string_value(*li, stack.result), string_value(*ri, stack.result))) return true; } return false; } else { if (lt == xpath_type_node_set) { swap(lhs, rhs); swap(lt, rt); } if (lt == xpath_type_boolean) return comp(lhs->eval_boolean(c, stack), rhs->eval_boolean(c, stack)); else if (lt == xpath_type_number) { xpath_allocator_capture cr(stack.result); double l = lhs->eval_number(c, stack); xpath_node_set_raw rs = rhs->eval_node_set(c, stack, nodeset_eval_all); for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri) { xpath_allocator_capture cri(stack.result); if (comp(l, convert_string_to_number(string_value(*ri, stack.result).c_str()))) return true; } return false; } else if (lt == xpath_type_string) { xpath_allocator_capture cr(stack.result); xpath_string l = lhs->eval_string(c, stack); xpath_node_set_raw rs = rhs->eval_node_set(c, stack, nodeset_eval_all); for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri) { xpath_allocator_capture cri(stack.result); if (comp(l, string_value(*ri, stack.result))) return true; } return false; } } assert(false && "Wrong types"); // unreachable return false; } static bool eval_once(xpath_node_set::type_t type, nodeset_eval_t eval) { return type == xpath_node_set::type_sorted ? eval != nodeset_eval_all : eval == nodeset_eval_any; } template static bool compare_rel(xpath_ast_node* lhs, xpath_ast_node* rhs, const xpath_context& c, const xpath_stack& stack, const Comp& comp) { xpath_value_type lt = lhs->rettype(), rt = rhs->rettype(); if (lt != xpath_type_node_set && rt != xpath_type_node_set) return comp(lhs->eval_number(c, stack), rhs->eval_number(c, stack)); else if (lt == xpath_type_node_set && rt == xpath_type_node_set) { xpath_allocator_capture cr(stack.result); xpath_node_set_raw ls = lhs->eval_node_set(c, stack, nodeset_eval_all); xpath_node_set_raw rs = rhs->eval_node_set(c, stack, nodeset_eval_all); for (const xpath_node* li = ls.begin(); li != ls.end(); ++li) { xpath_allocator_capture cri(stack.result); double l = convert_string_to_number(string_value(*li, stack.result).c_str()); for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri) { xpath_allocator_capture crii(stack.result); if (comp(l, convert_string_to_number(string_value(*ri, stack.result).c_str()))) return true; } } return false; } else if (lt != xpath_type_node_set && rt == xpath_type_node_set) { xpath_allocator_capture cr(stack.result); double l = lhs->eval_number(c, stack); xpath_node_set_raw rs = rhs->eval_node_set(c, stack, nodeset_eval_all); for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri) { xpath_allocator_capture cri(stack.result); if (comp(l, convert_string_to_number(string_value(*ri, stack.result).c_str()))) return true; } return false; } else if (lt == xpath_type_node_set && rt != xpath_type_node_set) { xpath_allocator_capture cr(stack.result); xpath_node_set_raw ls = lhs->eval_node_set(c, stack, nodeset_eval_all); double r = rhs->eval_number(c, stack); for (const xpath_node* li = ls.begin(); li != ls.end(); ++li) { xpath_allocator_capture cri(stack.result); if (comp(convert_string_to_number(string_value(*li, stack.result).c_str()), r)) return true; } return false; } else { assert(false && "Wrong types"); // unreachable return false; } } static void apply_predicate_boolean(xpath_node_set_raw& ns, size_t first, xpath_ast_node* expr, const xpath_stack& stack, bool once) { assert(ns.size() >= first); assert(expr->rettype() != xpath_type_number); size_t i = 1; size_t size = ns.size() - first; xpath_node* last = ns.begin() + first; // remove_if... or well, sort of for (xpath_node* it = last; it != ns.end(); ++it, ++i) { xpath_context c(*it, i, size); if (expr->eval_boolean(c, stack)) { *last++ = *it; if (once) break; } } ns.truncate(last); } static void apply_predicate_number(xpath_node_set_raw& ns, size_t first, xpath_ast_node* expr, const xpath_stack& stack, bool once) { assert(ns.size() >= first); assert(expr->rettype() == xpath_type_number); size_t i = 1; size_t size = ns.size() - first; xpath_node* last = ns.begin() + first; // remove_if... or well, sort of for (xpath_node* it = last; it != ns.end(); ++it, ++i) { xpath_context c(*it, i, size); if (expr->eval_number(c, stack) == static_cast(i)) { *last++ = *it; if (once) break; } } ns.truncate(last); } static void apply_predicate_number_const(xpath_node_set_raw& ns, size_t first, xpath_ast_node* expr, const xpath_stack& stack) { assert(ns.size() >= first); assert(expr->rettype() == xpath_type_number); size_t size = ns.size() - first; xpath_node* last = ns.begin() + first; xpath_node cn; xpath_context c(cn, 1, size); double er = expr->eval_number(c, stack); if (er >= 1.0 && er <= static_cast(size)) { size_t eri = static_cast(er); if (er == static_cast(eri)) { xpath_node r = last[eri - 1]; *last++ = r; } } ns.truncate(last); } void apply_predicate(xpath_node_set_raw& ns, size_t first, const xpath_stack& stack, bool once) { if (ns.size() == first) return; assert(_type == ast_filter || _type == ast_predicate); if (_test == predicate_constant || _test == predicate_constant_one) apply_predicate_number_const(ns, first, _right, stack); else if (_right->rettype() == xpath_type_number) apply_predicate_number(ns, first, _right, stack, once); else apply_predicate_boolean(ns, first, _right, stack, once); } void apply_predicates(xpath_node_set_raw& ns, size_t first, const xpath_stack& stack, nodeset_eval_t eval) { if (ns.size() == first) return; bool last_once = eval_once(ns.type(), eval); for (xpath_ast_node* pred = _right; pred; pred = pred->_next) pred->apply_predicate(ns, first, stack, !pred->_next && last_once); } bool step_push(xpath_node_set_raw& ns, xml_attribute_struct* a, xml_node_struct* parent, xpath_allocator* alloc) { assert(a); const char_t* name = a->name ? a->name + 0 : PUGIXML_TEXT(""); switch (_test) { case nodetest_name: if (strequal(name, _data.nodetest) && is_xpath_attribute(name)) { ns.push_back(xpath_node(xml_attribute(a), xml_node(parent)), alloc); return true; } break; case nodetest_type_node: case nodetest_all: if (is_xpath_attribute(name)) { ns.push_back(xpath_node(xml_attribute(a), xml_node(parent)), alloc); return true; } break; case nodetest_all_in_namespace: if (starts_with(name, _data.nodetest) && is_xpath_attribute(name)) { ns.push_back(xpath_node(xml_attribute(a), xml_node(parent)), alloc); return true; } break; default: ; } return false; } bool step_push(xpath_node_set_raw& ns, xml_node_struct* n, xpath_allocator* alloc) { assert(n); xml_node_type type = PUGI_IMPL_NODETYPE(n); switch (_test) { case nodetest_name: if (type == node_element && n->name && strequal(n->name, _data.nodetest)) { ns.push_back(xml_node(n), alloc); return true; } break; case nodetest_type_node: ns.push_back(xml_node(n), alloc); return true; case nodetest_type_comment: if (type == node_comment) { ns.push_back(xml_node(n), alloc); return true; } break; case nodetest_type_text: if (type == node_pcdata || type == node_cdata) { ns.push_back(xml_node(n), alloc); return true; } break; case nodetest_type_pi: if (type == node_pi) { ns.push_back(xml_node(n), alloc); return true; } break; case nodetest_pi: if (type == node_pi && n->name && strequal(n->name, _data.nodetest)) { ns.push_back(xml_node(n), alloc); return true; } break; case nodetest_all: if (type == node_element) { ns.push_back(xml_node(n), alloc); return true; } break; case nodetest_all_in_namespace: if (type == node_element && n->name && starts_with(n->name, _data.nodetest)) { ns.push_back(xml_node(n), alloc); return true; } break; default: assert(false && "Unknown axis"); // unreachable } return false; } template void step_fill(xpath_node_set_raw& ns, xml_node_struct* n, xpath_allocator* alloc, bool once, T) { const axis_t axis = T::axis; switch (axis) { case axis_attribute: { for (xml_attribute_struct* a = n->first_attribute; a; a = a->next_attribute) if (step_push(ns, a, n, alloc) & once) return; break; } case axis_child: { for (xml_node_struct* c = n->first_child; c; c = c->next_sibling) if (step_push(ns, c, alloc) & once) return; break; } case axis_descendant: case axis_descendant_or_self: { if (axis == axis_descendant_or_self) if (step_push(ns, n, alloc) & once) return; xml_node_struct* cur = n->first_child; while (cur) { if (step_push(ns, cur, alloc) & once) return; if (cur->first_child) cur = cur->first_child; else { while (!cur->next_sibling) { cur = cur->parent; if (cur == n) return; } cur = cur->next_sibling; } } break; } case axis_following_sibling: { for (xml_node_struct* c = n->next_sibling; c; c = c->next_sibling) if (step_push(ns, c, alloc) & once) return; break; } case axis_preceding_sibling: { for (xml_node_struct* c = n->prev_sibling_c; c->next_sibling; c = c->prev_sibling_c) if (step_push(ns, c, alloc) & once) return; break; } case axis_following: { xml_node_struct* cur = n; // exit from this node so that we don't include descendants while (!cur->next_sibling) { cur = cur->parent; if (!cur) return; } cur = cur->next_sibling; while (cur) { if (step_push(ns, cur, alloc) & once) return; if (cur->first_child) cur = cur->first_child; else { while (!cur->next_sibling) { cur = cur->parent; if (!cur) return; } cur = cur->next_sibling; } } break; } case axis_preceding: { xml_node_struct* cur = n; // exit from this node so that we don't include descendants while (!cur->prev_sibling_c->next_sibling) { cur = cur->parent; if (!cur) return; } cur = cur->prev_sibling_c; while (cur) { if (cur->first_child) cur = cur->first_child->prev_sibling_c; else { // leaf node, can't be ancestor if (step_push(ns, cur, alloc) & once) return; while (!cur->prev_sibling_c->next_sibling) { cur = cur->parent; if (!cur) return; if (!node_is_ancestor(cur, n)) if (step_push(ns, cur, alloc) & once) return; } cur = cur->prev_sibling_c; } } break; } case axis_ancestor: case axis_ancestor_or_self: { if (axis == axis_ancestor_or_self) if (step_push(ns, n, alloc) & once) return; xml_node_struct* cur = n->parent; while (cur) { if (step_push(ns, cur, alloc) & once) return; cur = cur->parent; } break; } case axis_self: { step_push(ns, n, alloc); break; } case axis_parent: { if (n->parent) step_push(ns, n->parent, alloc); break; } default: assert(false && "Unimplemented axis"); // unreachable } } template void step_fill(xpath_node_set_raw& ns, xml_attribute_struct* a, xml_node_struct* p, xpath_allocator* alloc, bool once, T v) { const axis_t axis = T::axis; switch (axis) { case axis_ancestor: case axis_ancestor_or_self: { if (axis == axis_ancestor_or_self && _test == nodetest_type_node) // reject attributes based on principal node type test if (step_push(ns, a, p, alloc) & once) return; xml_node_struct* cur = p; while (cur) { if (step_push(ns, cur, alloc) & once) return; cur = cur->parent; } break; } case axis_descendant_or_self: case axis_self: { if (_test == nodetest_type_node) // reject attributes based on principal node type test step_push(ns, a, p, alloc); break; } case axis_following: { xml_node_struct* cur = p; while (cur) { if (cur->first_child) cur = cur->first_child; else { while (!cur->next_sibling) { cur = cur->parent; if (!cur) return; } cur = cur->next_sibling; } if (step_push(ns, cur, alloc) & once) return; } break; } case axis_parent: { step_push(ns, p, alloc); break; } case axis_preceding: { // preceding:: axis does not include attribute nodes and attribute ancestors (they are the same as parent's ancestors), so we can reuse node preceding step_fill(ns, p, alloc, once, v); break; } default: assert(false && "Unimplemented axis"); // unreachable } } template void step_fill(xpath_node_set_raw& ns, const xpath_node& xn, xpath_allocator* alloc, bool once, T v) { const axis_t axis = T::axis; const bool axis_has_attributes = (axis == axis_ancestor || axis == axis_ancestor_or_self || axis == axis_descendant_or_self || axis == axis_following || axis == axis_parent || axis == axis_preceding || axis == axis_self); if (xn.node()) step_fill(ns, xn.node().internal_object(), alloc, once, v); else if (axis_has_attributes && xn.attribute() && xn.parent()) step_fill(ns, xn.attribute().internal_object(), xn.parent().internal_object(), alloc, once, v); } template xpath_node_set_raw step_do(const xpath_context& c, const xpath_stack& stack, nodeset_eval_t eval, T v) { const axis_t axis = T::axis; const bool axis_reverse = (axis == axis_ancestor || axis == axis_ancestor_or_self || axis == axis_preceding || axis == axis_preceding_sibling); const xpath_node_set::type_t axis_type = axis_reverse ? xpath_node_set::type_sorted_reverse : xpath_node_set::type_sorted; bool once = (axis == axis_attribute && _test == nodetest_name) || (!_right && eval_once(axis_type, eval)) || // coverity[mixed_enums] (_right && !_right->_next && _right->_test == predicate_constant_one); xpath_node_set_raw ns; ns.set_type(axis_type); if (_left) { xpath_node_set_raw s = _left->eval_node_set(c, stack, nodeset_eval_all); // self axis preserves the original order if (axis == axis_self) ns.set_type(s.type()); for (const xpath_node* it = s.begin(); it != s.end(); ++it) { size_t size = ns.size(); // in general, all axes generate elements in a particular order, but there is no order guarantee if axis is applied to two nodes if (axis != axis_self && size != 0) ns.set_type(xpath_node_set::type_unsorted); step_fill(ns, *it, stack.result, once, v); if (_right) apply_predicates(ns, size, stack, eval); } } else { step_fill(ns, c.n, stack.result, once, v); if (_right) apply_predicates(ns, 0, stack, eval); } // child, attribute and self axes always generate unique set of nodes // for other axis, if the set stayed sorted, it stayed unique because the traversal algorithms do not visit the same node twice if (axis != axis_child && axis != axis_attribute && axis != axis_self && ns.type() == xpath_node_set::type_unsorted) ns.remove_duplicates(stack.temp); return ns; } public: xpath_ast_node(ast_type_t type, xpath_value_type rettype_, const char_t* value): _type(static_cast(type)), _rettype(static_cast(rettype_)), _axis(0), _test(0), _left(NULL), _right(NULL), _next(NULL) { assert(type == ast_string_constant); _data.string = value; } xpath_ast_node(ast_type_t type, xpath_value_type rettype_, double value): _type(static_cast(type)), _rettype(static_cast(rettype_)), _axis(0), _test(0), _left(NULL), _right(NULL), _next(NULL) { assert(type == ast_number_constant); _data.number = value; } xpath_ast_node(ast_type_t type, xpath_value_type rettype_, xpath_variable* value): _type(static_cast(type)), _rettype(static_cast(rettype_)), _axis(0), _test(0), _left(NULL), _right(NULL), _next(NULL) { assert(type == ast_variable); _data.variable = value; } xpath_ast_node(ast_type_t type, xpath_value_type rettype_, xpath_ast_node* left = NULL, xpath_ast_node* right = NULL): _type(static_cast(type)), _rettype(static_cast(rettype_)), _axis(0), _test(0), _left(left), _right(right), _next(NULL) { } xpath_ast_node(ast_type_t type, xpath_ast_node* left, axis_t axis, nodetest_t test, const char_t* contents): _type(static_cast(type)), _rettype(xpath_type_node_set), _axis(static_cast(axis)), _test(static_cast(test)), _left(left), _right(NULL), _next(NULL) { assert(type == ast_step); _data.nodetest = contents; } xpath_ast_node(ast_type_t type, xpath_ast_node* left, xpath_ast_node* right, predicate_t test): _type(static_cast(type)), _rettype(xpath_type_node_set), _axis(0), _test(static_cast(test)), _left(left), _right(right), _next(NULL) { assert(type == ast_filter || type == ast_predicate); } void set_next(xpath_ast_node* value) { _next = value; } void set_right(xpath_ast_node* value) { _right = value; } bool eval_boolean(const xpath_context& c, const xpath_stack& stack) { switch (_type) { case ast_op_or: return _left->eval_boolean(c, stack) || _right->eval_boolean(c, stack); case ast_op_and: return _left->eval_boolean(c, stack) && _right->eval_boolean(c, stack); case ast_op_equal: return compare_eq(_left, _right, c, stack, equal_to()); case ast_op_not_equal: return compare_eq(_left, _right, c, stack, not_equal_to()); case ast_op_less: return compare_rel(_left, _right, c, stack, less()); case ast_op_greater: return compare_rel(_right, _left, c, stack, less()); case ast_op_less_or_equal: return compare_rel(_left, _right, c, stack, less_equal()); case ast_op_greater_or_equal: return compare_rel(_right, _left, c, stack, less_equal()); case ast_func_starts_with: { xpath_allocator_capture cr(stack.result); xpath_string lr = _left->eval_string(c, stack); xpath_string rr = _right->eval_string(c, stack); return starts_with(lr.c_str(), rr.c_str()); } case ast_func_contains: { xpath_allocator_capture cr(stack.result); xpath_string lr = _left->eval_string(c, stack); xpath_string rr = _right->eval_string(c, stack); return find_substring(lr.c_str(), rr.c_str()) != NULL; } case ast_func_boolean: return _left->eval_boolean(c, stack); case ast_func_not: return !_left->eval_boolean(c, stack); case ast_func_true: return true; case ast_func_false: return false; case ast_func_lang: { if (c.n.attribute()) return false; xpath_allocator_capture cr(stack.result); xpath_string lang = _left->eval_string(c, stack); for (xml_node n = c.n.node(); n; n = n.parent()) { xml_attribute a = n.attribute(PUGIXML_TEXT("xml:lang")); if (a) { const char_t* value = a.value(); // strnicmp / strncasecmp is not portable for (const char_t* lit = lang.c_str(); *lit; ++lit) { if (tolower_ascii(*lit) != tolower_ascii(*value)) return false; ++value; } return *value == 0 || *value == '-'; } } return false; } case ast_opt_compare_attribute: { const char_t* value = (_right->_type == ast_string_constant) ? _right->_data.string : _right->_data.variable->get_string(); xml_attribute attr = c.n.node().attribute(_left->_data.nodetest); return attr && strequal(attr.value(), value) && is_xpath_attribute(attr.name()); } case ast_variable: { assert(_rettype == _data.variable->type()); if (_rettype == xpath_type_boolean) return _data.variable->get_boolean(); // variable needs to be converted to the correct type, this is handled by the fallthrough block below break; } default: ; } // none of the ast types that return the value directly matched, we need to perform type conversion switch (_rettype) { case xpath_type_number: return convert_number_to_boolean(eval_number(c, stack)); case xpath_type_string: { xpath_allocator_capture cr(stack.result); return !eval_string(c, stack).empty(); } case xpath_type_node_set: { xpath_allocator_capture cr(stack.result); return !eval_node_set(c, stack, nodeset_eval_any).empty(); } default: assert(false && "Wrong expression for return type boolean"); // unreachable return false; } } double eval_number(const xpath_context& c, const xpath_stack& stack) { switch (_type) { case ast_op_add: return _left->eval_number(c, stack) + _right->eval_number(c, stack); case ast_op_subtract: return _left->eval_number(c, stack) - _right->eval_number(c, stack); case ast_op_multiply: return _left->eval_number(c, stack) * _right->eval_number(c, stack); case ast_op_divide: return _left->eval_number(c, stack) / _right->eval_number(c, stack); case ast_op_mod: return fmod(_left->eval_number(c, stack), _right->eval_number(c, stack)); case ast_op_negate: return -_left->eval_number(c, stack); case ast_number_constant: return _data.number; case ast_func_last: return static_cast(c.size); case ast_func_position: return static_cast(c.position); case ast_func_count: { xpath_allocator_capture cr(stack.result); return static_cast(_left->eval_node_set(c, stack, nodeset_eval_all).size()); } case ast_func_string_length_0: { xpath_allocator_capture cr(stack.result); return static_cast(string_value(c.n, stack.result).length()); } case ast_func_string_length_1: { xpath_allocator_capture cr(stack.result); return static_cast(_left->eval_string(c, stack).length()); } case ast_func_number_0: { xpath_allocator_capture cr(stack.result); return convert_string_to_number(string_value(c.n, stack.result).c_str()); } case ast_func_number_1: return _left->eval_number(c, stack); case ast_func_sum: { xpath_allocator_capture cr(stack.result); double r = 0; xpath_node_set_raw ns = _left->eval_node_set(c, stack, nodeset_eval_all); for (const xpath_node* it = ns.begin(); it != ns.end(); ++it) { xpath_allocator_capture cri(stack.result); r += convert_string_to_number(string_value(*it, stack.result).c_str()); } return r; } case ast_func_floor: { double r = _left->eval_number(c, stack); return r == r ? floor(r) : r; } case ast_func_ceiling: { double r = _left->eval_number(c, stack); return r == r ? ceil(r) : r; } case ast_func_round: return round_nearest_nzero(_left->eval_number(c, stack)); case ast_variable: { assert(_rettype == _data.variable->type()); if (_rettype == xpath_type_number) return _data.variable->get_number(); // variable needs to be converted to the correct type, this is handled by the fallthrough block below break; } default: ; } // none of the ast types that return the value directly matched, we need to perform type conversion switch (_rettype) { case xpath_type_boolean: return eval_boolean(c, stack) ? 1 : 0; case xpath_type_string: { xpath_allocator_capture cr(stack.result); return convert_string_to_number(eval_string(c, stack).c_str()); } case xpath_type_node_set: { xpath_allocator_capture cr(stack.result); return convert_string_to_number(eval_string(c, stack).c_str()); } default: assert(false && "Wrong expression for return type number"); // unreachable return 0; } } xpath_string eval_string_concat(const xpath_context& c, const xpath_stack& stack) { assert(_type == ast_func_concat); xpath_allocator_capture ct(stack.temp); // count the string number size_t count = 1; for (xpath_ast_node* nc = _right; nc; nc = nc->_next) count++; // allocate a buffer for temporary string objects xpath_string* buffer = static_cast(stack.temp->allocate(count * sizeof(xpath_string))); if (!buffer) return xpath_string(); // evaluate all strings to temporary stack xpath_stack swapped_stack = {stack.temp, stack.result}; buffer[0] = _left->eval_string(c, swapped_stack); size_t pos = 1; for (xpath_ast_node* n = _right; n; n = n->_next, ++pos) buffer[pos] = n->eval_string(c, swapped_stack); assert(pos == count); // get total length size_t length = 0; for (size_t i = 0; i < count; ++i) length += buffer[i].length(); // create final string char_t* result = static_cast(stack.result->allocate((length + 1) * sizeof(char_t))); if (!result) return xpath_string(); char_t* ri = result; for (size_t j = 0; j < count; ++j) for (const char_t* bi = buffer[j].c_str(); *bi; ++bi) *ri++ = *bi; *ri = 0; return xpath_string::from_heap_preallocated(result, ri); } xpath_string eval_string(const xpath_context& c, const xpath_stack& stack) { switch (_type) { case ast_string_constant: return xpath_string::from_const(_data.string); case ast_func_local_name_0: { xpath_node na = c.n; return xpath_string::from_const(local_name(na)); } case ast_func_local_name_1: { xpath_allocator_capture cr(stack.result); xpath_node_set_raw ns = _left->eval_node_set(c, stack, nodeset_eval_first); xpath_node na = ns.first(); return xpath_string::from_const(local_name(na)); } case ast_func_name_0: { xpath_node na = c.n; return xpath_string::from_const(qualified_name(na)); } case ast_func_name_1: { xpath_allocator_capture cr(stack.result); xpath_node_set_raw ns = _left->eval_node_set(c, stack, nodeset_eval_first); xpath_node na = ns.first(); return xpath_string::from_const(qualified_name(na)); } case ast_func_namespace_uri_0: { xpath_node na = c.n; return xpath_string::from_const(namespace_uri(na)); } case ast_func_namespace_uri_1: { xpath_allocator_capture cr(stack.result); xpath_node_set_raw ns = _left->eval_node_set(c, stack, nodeset_eval_first); xpath_node na = ns.first(); return xpath_string::from_const(namespace_uri(na)); } case ast_func_string_0: return string_value(c.n, stack.result); case ast_func_string_1: return _left->eval_string(c, stack); case ast_func_concat: return eval_string_concat(c, stack); case ast_func_substring_before: { xpath_allocator_capture cr(stack.temp); xpath_stack swapped_stack = {stack.temp, stack.result}; xpath_string s = _left->eval_string(c, swapped_stack); xpath_string p = _right->eval_string(c, swapped_stack); const char_t* pos = find_substring(s.c_str(), p.c_str()); return pos ? xpath_string::from_heap(s.c_str(), pos, stack.result) : xpath_string(); } case ast_func_substring_after: { xpath_allocator_capture cr(stack.temp); xpath_stack swapped_stack = {stack.temp, stack.result}; xpath_string s = _left->eval_string(c, swapped_stack); xpath_string p = _right->eval_string(c, swapped_stack); const char_t* pos = find_substring(s.c_str(), p.c_str()); if (!pos) return xpath_string(); const char_t* rbegin = pos + p.length(); const char_t* rend = s.c_str() + s.length(); return s.uses_heap() ? xpath_string::from_heap(rbegin, rend, stack.result) : xpath_string::from_const(rbegin); } case ast_func_substring_2: { xpath_allocator_capture cr(stack.temp); xpath_stack swapped_stack = {stack.temp, stack.result}; xpath_string s = _left->eval_string(c, swapped_stack); size_t s_length = s.length(); double first = round_nearest(_right->eval_number(c, stack)); if (is_nan(first)) return xpath_string(); // NaN else if (first >= static_cast(s_length + 1)) return xpath_string(); size_t pos = first < 1 ? 1 : static_cast(first); assert(1 <= pos && pos <= s_length + 1); const char_t* rbegin = s.c_str() + (pos - 1); const char_t* rend = s.c_str() + s.length(); return s.uses_heap() ? xpath_string::from_heap(rbegin, rend, stack.result) : xpath_string::from_const(rbegin); } case ast_func_substring_3: { xpath_allocator_capture cr(stack.temp); xpath_stack swapped_stack = {stack.temp, stack.result}; xpath_string s = _left->eval_string(c, swapped_stack); size_t s_length = s.length(); double first = round_nearest(_right->eval_number(c, stack)); double last = first + round_nearest(_right->_next->eval_number(c, stack)); if (is_nan(first) || is_nan(last)) return xpath_string(); else if (first >= static_cast(s_length + 1)) return xpath_string(); else if (first >= last) return xpath_string(); else if (last < 1) return xpath_string(); size_t pos = first < 1 ? 1 : static_cast(first); size_t end = last >= static_cast(s_length + 1) ? s_length + 1 : static_cast(last); assert(1 <= pos && pos <= end && end <= s_length + 1); const char_t* rbegin = s.c_str() + (pos - 1); const char_t* rend = s.c_str() + (end - 1); return (end == s_length + 1 && !s.uses_heap()) ? xpath_string::from_const(rbegin) : xpath_string::from_heap(rbegin, rend, stack.result); } case ast_func_normalize_space_0: { xpath_string s = string_value(c.n, stack.result); char_t* begin = s.data(stack.result); if (!begin) return xpath_string(); char_t* end = normalize_space(begin); return xpath_string::from_heap_preallocated(begin, end); } case ast_func_normalize_space_1: { xpath_string s = _left->eval_string(c, stack); char_t* begin = s.data(stack.result); if (!begin) return xpath_string(); char_t* end = normalize_space(begin); return xpath_string::from_heap_preallocated(begin, end); } case ast_func_translate: { xpath_allocator_capture cr(stack.temp); xpath_stack swapped_stack = {stack.temp, stack.result}; xpath_string s = _left->eval_string(c, stack); xpath_string from = _right->eval_string(c, swapped_stack); xpath_string to = _right->_next->eval_string(c, swapped_stack); char_t* begin = s.data(stack.result); if (!begin) return xpath_string(); char_t* end = translate(begin, from.c_str(), to.c_str(), to.length()); return xpath_string::from_heap_preallocated(begin, end); } case ast_opt_translate_table: { xpath_string s = _left->eval_string(c, stack); char_t* begin = s.data(stack.result); if (!begin) return xpath_string(); char_t* end = translate_table(begin, _data.table); return xpath_string::from_heap_preallocated(begin, end); } case ast_variable: { assert(_rettype == _data.variable->type()); if (_rettype == xpath_type_string) return xpath_string::from_const(_data.variable->get_string()); // variable needs to be converted to the correct type, this is handled by the fallthrough block below break; } default: ; } // none of the ast types that return the value directly matched, we need to perform type conversion switch (_rettype) { case xpath_type_boolean: return xpath_string::from_const(eval_boolean(c, stack) ? PUGIXML_TEXT("true") : PUGIXML_TEXT("false")); case xpath_type_number: return convert_number_to_string(eval_number(c, stack), stack.result); case xpath_type_node_set: { xpath_allocator_capture cr(stack.temp); xpath_stack swapped_stack = {stack.temp, stack.result}; xpath_node_set_raw ns = eval_node_set(c, swapped_stack, nodeset_eval_first); return ns.empty() ? xpath_string() : string_value(ns.first(), stack.result); } default: assert(false && "Wrong expression for return type string"); // unreachable return xpath_string(); } } xpath_node_set_raw eval_node_set(const xpath_context& c, const xpath_stack& stack, nodeset_eval_t eval) { switch (_type) { case ast_op_union: { xpath_allocator_capture cr(stack.temp); xpath_stack swapped_stack = {stack.temp, stack.result}; xpath_node_set_raw ls = _left->eval_node_set(c, stack, eval); xpath_node_set_raw rs = _right->eval_node_set(c, swapped_stack, eval); // we can optimize merging two sorted sets, but this is a very rare operation, so don't bother ls.set_type(xpath_node_set::type_unsorted); ls.append(rs.begin(), rs.end(), stack.result); ls.remove_duplicates(stack.temp); return ls; } case ast_filter: { xpath_node_set_raw set = _left->eval_node_set(c, stack, _test == predicate_constant_one ? nodeset_eval_first : nodeset_eval_all); // either expression is a number or it contains position() call; sort by document order if (_test != predicate_posinv) set.sort_do(); bool once = eval_once(set.type(), eval); apply_predicate(set, 0, stack, once); return set; } case ast_func_id: return xpath_node_set_raw(); case ast_step: { switch (_axis) { case axis_ancestor: return step_do(c, stack, eval, axis_to_type()); case axis_ancestor_or_self: return step_do(c, stack, eval, axis_to_type()); case axis_attribute: return step_do(c, stack, eval, axis_to_type()); case axis_child: return step_do(c, stack, eval, axis_to_type()); case axis_descendant: return step_do(c, stack, eval, axis_to_type()); case axis_descendant_or_self: return step_do(c, stack, eval, axis_to_type()); case axis_following: return step_do(c, stack, eval, axis_to_type()); case axis_following_sibling: return step_do(c, stack, eval, axis_to_type()); case axis_namespace: // namespaced axis is not supported return xpath_node_set_raw(); case axis_parent: return step_do(c, stack, eval, axis_to_type()); case axis_preceding: return step_do(c, stack, eval, axis_to_type()); case axis_preceding_sibling: return step_do(c, stack, eval, axis_to_type()); case axis_self: return step_do(c, stack, eval, axis_to_type()); default: assert(false && "Unknown axis"); // unreachable return xpath_node_set_raw(); } } case ast_step_root: { assert(!_right); // root step can't have any predicates xpath_node_set_raw ns; ns.set_type(xpath_node_set::type_sorted); if (c.n.node()) ns.push_back(c.n.node().root(), stack.result); else if (c.n.attribute()) ns.push_back(c.n.parent().root(), stack.result); return ns; } case ast_variable: { assert(_rettype == _data.variable->type()); if (_rettype == xpath_type_node_set) { const xpath_node_set& s = _data.variable->get_node_set(); xpath_node_set_raw ns; ns.set_type(s.type()); ns.append(s.begin(), s.end(), stack.result); return ns; } // variable needs to be converted to the correct type, this is handled by the fallthrough block below break; } default: ; } // none of the ast types that return the value directly matched, but conversions to node set are invalid assert(false && "Wrong expression for return type node set"); // unreachable return xpath_node_set_raw(); } void optimize(xpath_allocator* alloc) { if (_left) _left->optimize(alloc); if (_right) _right->optimize(alloc); if (_next) _next->optimize(alloc); // coverity[var_deref_model] optimize_self(alloc); } void optimize_self(xpath_allocator* alloc) { // Rewrite [position()=expr] with [expr] // Note that this step has to go before classification to recognize [position()=1] if ((_type == ast_filter || _type == ast_predicate) && _right && // workaround for clang static analyzer (_right is never null for ast_filter/ast_predicate) _right->_type == ast_op_equal && _right->_left->_type == ast_func_position && _right->_right->_rettype == xpath_type_number) { _right = _right->_right; } // Classify filter/predicate ops to perform various optimizations during evaluation if ((_type == ast_filter || _type == ast_predicate) && _right) // workaround for clang static analyzer (_right is never null for ast_filter/ast_predicate) { assert(_test == predicate_default); if (_right->_type == ast_number_constant && _right->_data.number == 1.0) _test = predicate_constant_one; else if (_right->_rettype == xpath_type_number && (_right->_type == ast_number_constant || _right->_type == ast_variable || _right->_type == ast_func_last)) _test = predicate_constant; else if (_right->_rettype != xpath_type_number && _right->is_posinv_expr()) _test = predicate_posinv; } // Rewrite descendant-or-self::node()/child::foo with descendant::foo // The former is a full form of //foo, the latter is much faster since it executes the node test immediately // Do a similar kind of rewrite for self/descendant/descendant-or-self axes // Note that we only rewrite positionally invariant steps (//foo[1] != /descendant::foo[1]) if (_type == ast_step && (_axis == axis_child || _axis == axis_self || _axis == axis_descendant || _axis == axis_descendant_or_self) && _left && _left->_type == ast_step && _left->_axis == axis_descendant_or_self && _left->_test == nodetest_type_node && !_left->_right && is_posinv_step()) { if (_axis == axis_child || _axis == axis_descendant) _axis = axis_descendant; else _axis = axis_descendant_or_self; _left = _left->_left; } // Use optimized lookup table implementation for translate() with constant arguments if (_type == ast_func_translate && _right && // workaround for clang static analyzer (_right is never null for ast_func_translate) _right->_type == ast_string_constant && _right->_next->_type == ast_string_constant) { unsigned char* table = translate_table_generate(alloc, _right->_data.string, _right->_next->_data.string); if (table) { _type = ast_opt_translate_table; _data.table = table; } } // Use optimized path for @attr = 'value' or @attr = $value if (_type == ast_op_equal && _left && _right && // workaround for clang static analyzer and Coverity (_left and _right are never null for ast_op_equal) // coverity[mixed_enums] _left->_type == ast_step && _left->_axis == axis_attribute && _left->_test == nodetest_name && !_left->_left && !_left->_right && (_right->_type == ast_string_constant || (_right->_type == ast_variable && _right->_rettype == xpath_type_string))) { _type = ast_opt_compare_attribute; } } bool is_posinv_expr() const { switch (_type) { case ast_func_position: case ast_func_last: return false; case ast_string_constant: case ast_number_constant: case ast_variable: return true; case ast_step: case ast_step_root: return true; case ast_predicate: case ast_filter: return true; default: if (_left && !_left->is_posinv_expr()) return false; for (xpath_ast_node* n = _right; n; n = n->_next) if (!n->is_posinv_expr()) return false; return true; } } bool is_posinv_step() const { assert(_type == ast_step); for (xpath_ast_node* n = _right; n; n = n->_next) { assert(n->_type == ast_predicate); if (n->_test != predicate_posinv) return false; } return true; } xpath_value_type rettype() const { return static_cast(_rettype); } }; static const size_t xpath_ast_depth_limit = #ifdef PUGIXML_XPATH_DEPTH_LIMIT PUGIXML_XPATH_DEPTH_LIMIT #else 1024 #endif ; struct xpath_parser { xpath_allocator* _alloc; xpath_lexer _lexer; const char_t* _query; xpath_variable_set* _variables; xpath_parse_result* _result; char_t _scratch[32]; size_t _depth; xpath_ast_node* error(const char* message) { _result->error = message; _result->offset = _lexer.current_pos() - _query; return NULL; } xpath_ast_node* error_oom() { assert(_alloc->_error); *_alloc->_error = true; return NULL; } xpath_ast_node* error_rec() { return error("Exceeded maximum allowed query depth"); } void* alloc_node() { return _alloc->allocate(sizeof(xpath_ast_node)); } xpath_ast_node* alloc_node(ast_type_t type, xpath_value_type rettype, const char_t* value) { void* memory = alloc_node(); return memory ? new (memory) xpath_ast_node(type, rettype, value) : NULL; } xpath_ast_node* alloc_node(ast_type_t type, xpath_value_type rettype, double value) { void* memory = alloc_node(); return memory ? new (memory) xpath_ast_node(type, rettype, value) : NULL; } xpath_ast_node* alloc_node(ast_type_t type, xpath_value_type rettype, xpath_variable* value) { void* memory = alloc_node(); return memory ? new (memory) xpath_ast_node(type, rettype, value) : NULL; } xpath_ast_node* alloc_node(ast_type_t type, xpath_value_type rettype, xpath_ast_node* left = NULL, xpath_ast_node* right = NULL) { void* memory = alloc_node(); return memory ? new (memory) xpath_ast_node(type, rettype, left, right) : NULL; } xpath_ast_node* alloc_node(ast_type_t type, xpath_ast_node* left, axis_t axis, nodetest_t test, const char_t* contents) { void* memory = alloc_node(); return memory ? new (memory) xpath_ast_node(type, left, axis, test, contents) : NULL; } xpath_ast_node* alloc_node(ast_type_t type, xpath_ast_node* left, xpath_ast_node* right, predicate_t test) { void* memory = alloc_node(); return memory ? new (memory) xpath_ast_node(type, left, right, test) : NULL; } const char_t* alloc_string(const xpath_lexer_string& value) { if (!value.begin) return PUGIXML_TEXT(""); size_t length = static_cast(value.end - value.begin); char_t* c = static_cast(_alloc->allocate((length + 1) * sizeof(char_t))); if (!c) return NULL; memcpy(c, value.begin, length * sizeof(char_t)); c[length] = 0; return c; } xpath_ast_node* parse_function(const xpath_lexer_string& name, size_t argc, xpath_ast_node* args[2]) { switch (name.begin[0]) { case 'b': if (name == PUGIXML_TEXT("boolean") && argc == 1) return alloc_node(ast_func_boolean, xpath_type_boolean, args[0]); break; case 'c': if (name == PUGIXML_TEXT("count") && argc == 1) { if (args[0]->rettype() != xpath_type_node_set) return error("Function has to be applied to node set"); return alloc_node(ast_func_count, xpath_type_number, args[0]); } else if (name == PUGIXML_TEXT("contains") && argc == 2) return alloc_node(ast_func_contains, xpath_type_boolean, args[0], args[1]); else if (name == PUGIXML_TEXT("concat") && argc >= 2) return alloc_node(ast_func_concat, xpath_type_string, args[0], args[1]); else if (name == PUGIXML_TEXT("ceiling") && argc == 1) return alloc_node(ast_func_ceiling, xpath_type_number, args[0]); break; case 'f': if (name == PUGIXML_TEXT("false") && argc == 0) return alloc_node(ast_func_false, xpath_type_boolean); else if (name == PUGIXML_TEXT("floor") && argc == 1) return alloc_node(ast_func_floor, xpath_type_number, args[0]); break; case 'i': if (name == PUGIXML_TEXT("id") && argc == 1) return alloc_node(ast_func_id, xpath_type_node_set, args[0]); break; case 'l': if (name == PUGIXML_TEXT("last") && argc == 0) return alloc_node(ast_func_last, xpath_type_number); else if (name == PUGIXML_TEXT("lang") && argc == 1) return alloc_node(ast_func_lang, xpath_type_boolean, args[0]); else if (name == PUGIXML_TEXT("local-name") && argc <= 1) { if (argc == 1 && args[0]->rettype() != xpath_type_node_set) return error("Function has to be applied to node set"); return alloc_node(argc == 0 ? ast_func_local_name_0 : ast_func_local_name_1, xpath_type_string, args[0]); } break; case 'n': if (name == PUGIXML_TEXT("name") && argc <= 1) { if (argc == 1 && args[0]->rettype() != xpath_type_node_set) return error("Function has to be applied to node set"); return alloc_node(argc == 0 ? ast_func_name_0 : ast_func_name_1, xpath_type_string, args[0]); } else if (name == PUGIXML_TEXT("namespace-uri") && argc <= 1) { if (argc == 1 && args[0]->rettype() != xpath_type_node_set) return error("Function has to be applied to node set"); return alloc_node(argc == 0 ? ast_func_namespace_uri_0 : ast_func_namespace_uri_1, xpath_type_string, args[0]); } else if (name == PUGIXML_TEXT("normalize-space") && argc <= 1) return alloc_node(argc == 0 ? ast_func_normalize_space_0 : ast_func_normalize_space_1, xpath_type_string, args[0], args[1]); else if (name == PUGIXML_TEXT("not") && argc == 1) return alloc_node(ast_func_not, xpath_type_boolean, args[0]); else if (name == PUGIXML_TEXT("number") && argc <= 1) return alloc_node(argc == 0 ? ast_func_number_0 : ast_func_number_1, xpath_type_number, args[0]); break; case 'p': if (name == PUGIXML_TEXT("position") && argc == 0) return alloc_node(ast_func_position, xpath_type_number); break; case 'r': if (name == PUGIXML_TEXT("round") && argc == 1) return alloc_node(ast_func_round, xpath_type_number, args[0]); break; case 's': if (name == PUGIXML_TEXT("string") && argc <= 1) return alloc_node(argc == 0 ? ast_func_string_0 : ast_func_string_1, xpath_type_string, args[0]); else if (name == PUGIXML_TEXT("string-length") && argc <= 1) return alloc_node(argc == 0 ? ast_func_string_length_0 : ast_func_string_length_1, xpath_type_number, args[0]); else if (name == PUGIXML_TEXT("starts-with") && argc == 2) return alloc_node(ast_func_starts_with, xpath_type_boolean, args[0], args[1]); else if (name == PUGIXML_TEXT("substring-before") && argc == 2) return alloc_node(ast_func_substring_before, xpath_type_string, args[0], args[1]); else if (name == PUGIXML_TEXT("substring-after") && argc == 2) return alloc_node(ast_func_substring_after, xpath_type_string, args[0], args[1]); else if (name == PUGIXML_TEXT("substring") && (argc == 2 || argc == 3)) return alloc_node(argc == 2 ? ast_func_substring_2 : ast_func_substring_3, xpath_type_string, args[0], args[1]); else if (name == PUGIXML_TEXT("sum") && argc == 1) { if (args[0]->rettype() != xpath_type_node_set) return error("Function has to be applied to node set"); return alloc_node(ast_func_sum, xpath_type_number, args[0]); } break; case 't': if (name == PUGIXML_TEXT("translate") && argc == 3) return alloc_node(ast_func_translate, xpath_type_string, args[0], args[1]); else if (name == PUGIXML_TEXT("true") && argc == 0) return alloc_node(ast_func_true, xpath_type_boolean); break; default: break; } return error("Unrecognized function or wrong parameter count"); } axis_t parse_axis_name(const xpath_lexer_string& name, bool& specified) { specified = true; switch (name.begin[0]) { case 'a': if (name == PUGIXML_TEXT("ancestor")) return axis_ancestor; else if (name == PUGIXML_TEXT("ancestor-or-self")) return axis_ancestor_or_self; else if (name == PUGIXML_TEXT("attribute")) return axis_attribute; break; case 'c': if (name == PUGIXML_TEXT("child")) return axis_child; break; case 'd': if (name == PUGIXML_TEXT("descendant")) return axis_descendant; else if (name == PUGIXML_TEXT("descendant-or-self")) return axis_descendant_or_self; break; case 'f': if (name == PUGIXML_TEXT("following")) return axis_following; else if (name == PUGIXML_TEXT("following-sibling")) return axis_following_sibling; break; case 'n': if (name == PUGIXML_TEXT("namespace")) return axis_namespace; break; case 'p': if (name == PUGIXML_TEXT("parent")) return axis_parent; else if (name == PUGIXML_TEXT("preceding")) return axis_preceding; else if (name == PUGIXML_TEXT("preceding-sibling")) return axis_preceding_sibling; break; case 's': if (name == PUGIXML_TEXT("self")) return axis_self; break; default: break; } specified = false; return axis_child; } nodetest_t parse_node_test_type(const xpath_lexer_string& name) { switch (name.begin[0]) { case 'c': if (name == PUGIXML_TEXT("comment")) return nodetest_type_comment; break; case 'n': if (name == PUGIXML_TEXT("node")) return nodetest_type_node; break; case 'p': if (name == PUGIXML_TEXT("processing-instruction")) return nodetest_type_pi; break; case 't': if (name == PUGIXML_TEXT("text")) return nodetest_type_text; break; default: break; } return nodetest_none; } // PrimaryExpr ::= VariableReference | '(' Expr ')' | Literal | Number | FunctionCall xpath_ast_node* parse_primary_expression() { switch (_lexer.current()) { case lex_var_ref: { xpath_lexer_string name = _lexer.contents(); if (!_variables) return error("Unknown variable: variable set is not provided"); xpath_variable* var = NULL; if (!get_variable_scratch(_scratch, _variables, name.begin, name.end, &var)) return error_oom(); if (!var) return error("Unknown variable: variable set does not contain the given name"); _lexer.next(); return alloc_node(ast_variable, var->type(), var); } case lex_open_brace: { _lexer.next(); xpath_ast_node* n = parse_expression(); if (!n) return NULL; if (_lexer.current() != lex_close_brace) return error("Expected ')' to match an opening '('"); _lexer.next(); return n; } case lex_quoted_string: { const char_t* value = alloc_string(_lexer.contents()); if (!value) return NULL; _lexer.next(); return alloc_node(ast_string_constant, xpath_type_string, value); } case lex_number: { double value = 0; if (!convert_string_to_number_scratch(_scratch, _lexer.contents().begin, _lexer.contents().end, &value)) return error_oom(); _lexer.next(); return alloc_node(ast_number_constant, xpath_type_number, value); } case lex_string: { xpath_ast_node* args[2] = {NULL}; size_t argc = 0; xpath_lexer_string function = _lexer.contents(); _lexer.next(); xpath_ast_node* last_arg = NULL; if (_lexer.current() != lex_open_brace) return error("Unrecognized function call"); _lexer.next(); size_t old_depth = _depth; while (_lexer.current() != lex_close_brace) { if (argc > 0) { if (_lexer.current() != lex_comma) return error("No comma between function arguments"); _lexer.next(); } if (++_depth > xpath_ast_depth_limit) return error_rec(); xpath_ast_node* n = parse_expression(); if (!n) return NULL; if (argc < 2) args[argc] = n; else last_arg->set_next(n); argc++; last_arg = n; } _lexer.next(); _depth = old_depth; return parse_function(function, argc, args); } default: return error("Unrecognizable primary expression"); } } // FilterExpr ::= PrimaryExpr | FilterExpr Predicate // Predicate ::= '[' PredicateExpr ']' // PredicateExpr ::= Expr xpath_ast_node* parse_filter_expression() { xpath_ast_node* n = parse_primary_expression(); if (!n) return NULL; size_t old_depth = _depth; while (_lexer.current() == lex_open_square_brace) { _lexer.next(); if (++_depth > xpath_ast_depth_limit) return error_rec(); if (n->rettype() != xpath_type_node_set) return error("Predicate has to be applied to node set"); xpath_ast_node* expr = parse_expression(); if (!expr) return NULL; n = alloc_node(ast_filter, n, expr, predicate_default); if (!n) return NULL; if (_lexer.current() != lex_close_square_brace) return error("Expected ']' to match an opening '['"); _lexer.next(); } _depth = old_depth; return n; } // Step ::= AxisSpecifier NodeTest Predicate* | AbbreviatedStep // AxisSpecifier ::= AxisName '::' | '@'? // NodeTest ::= NameTest | NodeType '(' ')' | 'processing-instruction' '(' Literal ')' // NameTest ::= '*' | NCName ':' '*' | QName // AbbreviatedStep ::= '.' | '..' xpath_ast_node* parse_step(xpath_ast_node* set) { if (set && set->rettype() != xpath_type_node_set) return error("Step has to be applied to node set"); bool axis_specified = false; axis_t axis = axis_child; // implied child axis if (_lexer.current() == lex_axis_attribute) { axis = axis_attribute; axis_specified = true; _lexer.next(); } else if (_lexer.current() == lex_dot) { _lexer.next(); if (_lexer.current() == lex_open_square_brace) return error("Predicates are not allowed after an abbreviated step"); return alloc_node(ast_step, set, axis_self, nodetest_type_node, NULL); } else if (_lexer.current() == lex_double_dot) { _lexer.next(); if (_lexer.current() == lex_open_square_brace) return error("Predicates are not allowed after an abbreviated step"); return alloc_node(ast_step, set, axis_parent, nodetest_type_node, NULL); } nodetest_t nt_type = nodetest_none; xpath_lexer_string nt_name; if (_lexer.current() == lex_string) { // node name test nt_name = _lexer.contents(); _lexer.next(); // was it an axis name? if (_lexer.current() == lex_double_colon) { // parse axis name if (axis_specified) return error("Two axis specifiers in one step"); axis = parse_axis_name(nt_name, axis_specified); if (!axis_specified) return error("Unknown axis"); // read actual node test _lexer.next(); if (_lexer.current() == lex_multiply) { nt_type = nodetest_all; nt_name = xpath_lexer_string(); _lexer.next(); } else if (_lexer.current() == lex_string) { nt_name = _lexer.contents(); _lexer.next(); } else { return error("Unrecognized node test"); } } if (nt_type == nodetest_none) { // node type test or processing-instruction if (_lexer.current() == lex_open_brace) { _lexer.next(); if (_lexer.current() == lex_close_brace) { _lexer.next(); nt_type = parse_node_test_type(nt_name); if (nt_type == nodetest_none) return error("Unrecognized node type"); nt_name = xpath_lexer_string(); } else if (nt_name == PUGIXML_TEXT("processing-instruction")) { if (_lexer.current() != lex_quoted_string) return error("Only literals are allowed as arguments to processing-instruction()"); nt_type = nodetest_pi; nt_name = _lexer.contents(); _lexer.next(); if (_lexer.current() != lex_close_brace) return error("Unmatched brace near processing-instruction()"); _lexer.next(); } else { return error("Unmatched brace near node type test"); } } // QName or NCName:* else { if (nt_name.end - nt_name.begin > 2 && nt_name.end[-2] == ':' && nt_name.end[-1] == '*') // NCName:* { nt_name.end--; // erase * nt_type = nodetest_all_in_namespace; } else { nt_type = nodetest_name; } } } } else if (_lexer.current() == lex_multiply) { nt_type = nodetest_all; _lexer.next(); } else { return error("Unrecognized node test"); } const char_t* nt_name_copy = alloc_string(nt_name); if (!nt_name_copy) return NULL; xpath_ast_node* n = alloc_node(ast_step, set, axis, nt_type, nt_name_copy); if (!n) return NULL; size_t old_depth = _depth; xpath_ast_node* last = NULL; while (_lexer.current() == lex_open_square_brace) { _lexer.next(); if (++_depth > xpath_ast_depth_limit) return error_rec(); xpath_ast_node* expr = parse_expression(); if (!expr) return NULL; xpath_ast_node* pred = alloc_node(ast_predicate, NULL, expr, predicate_default); if (!pred) return NULL; if (_lexer.current() != lex_close_square_brace) return error("Expected ']' to match an opening '['"); _lexer.next(); if (last) last->set_next(pred); else n->set_right(pred); last = pred; } _depth = old_depth; return n; } // RelativeLocationPath ::= Step | RelativeLocationPath '/' Step | RelativeLocationPath '//' Step xpath_ast_node* parse_relative_location_path(xpath_ast_node* set) { xpath_ast_node* n = parse_step(set); if (!n) return NULL; size_t old_depth = _depth; while (_lexer.current() == lex_slash || _lexer.current() == lex_double_slash) { lexeme_t l = _lexer.current(); _lexer.next(); if (l == lex_double_slash) { n = alloc_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, NULL); if (!n) return NULL; ++_depth; } if (++_depth > xpath_ast_depth_limit) return error_rec(); n = parse_step(n); if (!n) return NULL; } _depth = old_depth; return n; } // LocationPath ::= RelativeLocationPath | AbsoluteLocationPath // AbsoluteLocationPath ::= '/' RelativeLocationPath? | '//' RelativeLocationPath xpath_ast_node* parse_location_path() { if (_lexer.current() == lex_slash) { _lexer.next(); xpath_ast_node* n = alloc_node(ast_step_root, xpath_type_node_set); if (!n) return NULL; // relative location path can start from axis_attribute, dot, double_dot, multiply and string lexemes; any other lexeme means standalone root path lexeme_t l = _lexer.current(); if (l == lex_string || l == lex_axis_attribute || l == lex_dot || l == lex_double_dot || l == lex_multiply) return parse_relative_location_path(n); else return n; } else if (_lexer.current() == lex_double_slash) { _lexer.next(); xpath_ast_node* n = alloc_node(ast_step_root, xpath_type_node_set); if (!n) return NULL; n = alloc_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, NULL); if (!n) return NULL; return parse_relative_location_path(n); } // else clause moved outside of if because of bogus warning 'control may reach end of non-void function being inlined' in gcc 4.0.1 return parse_relative_location_path(NULL); } // PathExpr ::= LocationPath // | FilterExpr // | FilterExpr '/' RelativeLocationPath // | FilterExpr '//' RelativeLocationPath // UnionExpr ::= PathExpr | UnionExpr '|' PathExpr // UnaryExpr ::= UnionExpr | '-' UnaryExpr xpath_ast_node* parse_path_or_unary_expression() { // Clarification. // PathExpr begins with either LocationPath or FilterExpr. // FilterExpr begins with PrimaryExpr // PrimaryExpr begins with '$' in case of it being a variable reference, // '(' in case of it being an expression, string literal, number constant or // function call. if (_lexer.current() == lex_var_ref || _lexer.current() == lex_open_brace || _lexer.current() == lex_quoted_string || _lexer.current() == lex_number || _lexer.current() == lex_string) { if (_lexer.current() == lex_string) { // This is either a function call, or not - if not, we shall proceed with location path const char_t* state = _lexer.state(); while (PUGI_IMPL_IS_CHARTYPE(*state, ct_space)) ++state; if (*state != '(') return parse_location_path(); // This looks like a function call; however this still can be a node-test. Check it. if (parse_node_test_type(_lexer.contents()) != nodetest_none) return parse_location_path(); } xpath_ast_node* n = parse_filter_expression(); if (!n) return NULL; if (_lexer.current() == lex_slash || _lexer.current() == lex_double_slash) { lexeme_t l = _lexer.current(); _lexer.next(); if (l == lex_double_slash) { if (n->rettype() != xpath_type_node_set) return error("Step has to be applied to node set"); n = alloc_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, NULL); if (!n) return NULL; } // select from location path return parse_relative_location_path(n); } return n; } else if (_lexer.current() == lex_minus) { _lexer.next(); // precedence 7+ - only parses union expressions xpath_ast_node* n = parse_expression(7); if (!n) return NULL; return alloc_node(ast_op_negate, xpath_type_number, n); } else { return parse_location_path(); } } struct binary_op_t { ast_type_t asttype; xpath_value_type rettype; int precedence; binary_op_t(): asttype(ast_unknown), rettype(xpath_type_none), precedence(0) { } binary_op_t(ast_type_t asttype_, xpath_value_type rettype_, int precedence_): asttype(asttype_), rettype(rettype_), precedence(precedence_) { } static binary_op_t parse(xpath_lexer& lexer) { switch (lexer.current()) { case lex_string: if (lexer.contents() == PUGIXML_TEXT("or")) return binary_op_t(ast_op_or, xpath_type_boolean, 1); else if (lexer.contents() == PUGIXML_TEXT("and")) return binary_op_t(ast_op_and, xpath_type_boolean, 2); else if (lexer.contents() == PUGIXML_TEXT("div")) return binary_op_t(ast_op_divide, xpath_type_number, 6); else if (lexer.contents() == PUGIXML_TEXT("mod")) return binary_op_t(ast_op_mod, xpath_type_number, 6); else return binary_op_t(); case lex_equal: return binary_op_t(ast_op_equal, xpath_type_boolean, 3); case lex_not_equal: return binary_op_t(ast_op_not_equal, xpath_type_boolean, 3); case lex_less: return binary_op_t(ast_op_less, xpath_type_boolean, 4); case lex_greater: return binary_op_t(ast_op_greater, xpath_type_boolean, 4); case lex_less_or_equal: return binary_op_t(ast_op_less_or_equal, xpath_type_boolean, 4); case lex_greater_or_equal: return binary_op_t(ast_op_greater_or_equal, xpath_type_boolean, 4); case lex_plus: return binary_op_t(ast_op_add, xpath_type_number, 5); case lex_minus: return binary_op_t(ast_op_subtract, xpath_type_number, 5); case lex_multiply: return binary_op_t(ast_op_multiply, xpath_type_number, 6); case lex_union: return binary_op_t(ast_op_union, xpath_type_node_set, 7); default: return binary_op_t(); } } }; xpath_ast_node* parse_expression_rec(xpath_ast_node* lhs, int limit) { binary_op_t op = binary_op_t::parse(_lexer); while (op.asttype != ast_unknown && op.precedence >= limit) { _lexer.next(); if (++_depth > xpath_ast_depth_limit) return error_rec(); xpath_ast_node* rhs = parse_path_or_unary_expression(); if (!rhs) return NULL; binary_op_t nextop = binary_op_t::parse(_lexer); while (nextop.asttype != ast_unknown && nextop.precedence > op.precedence) { rhs = parse_expression_rec(rhs, nextop.precedence); if (!rhs) return NULL; nextop = binary_op_t::parse(_lexer); } if (op.asttype == ast_op_union && (lhs->rettype() != xpath_type_node_set || rhs->rettype() != xpath_type_node_set)) return error("Union operator has to be applied to node sets"); lhs = alloc_node(op.asttype, op.rettype, lhs, rhs); if (!lhs) return NULL; op = binary_op_t::parse(_lexer); } return lhs; } // Expr ::= OrExpr // OrExpr ::= AndExpr | OrExpr 'or' AndExpr // AndExpr ::= EqualityExpr | AndExpr 'and' EqualityExpr // EqualityExpr ::= RelationalExpr // | EqualityExpr '=' RelationalExpr // | EqualityExpr '!=' RelationalExpr // RelationalExpr ::= AdditiveExpr // | RelationalExpr '<' AdditiveExpr // | RelationalExpr '>' AdditiveExpr // | RelationalExpr '<=' AdditiveExpr // | RelationalExpr '>=' AdditiveExpr // AdditiveExpr ::= MultiplicativeExpr // | AdditiveExpr '+' MultiplicativeExpr // | AdditiveExpr '-' MultiplicativeExpr // MultiplicativeExpr ::= UnaryExpr // | MultiplicativeExpr '*' UnaryExpr // | MultiplicativeExpr 'div' UnaryExpr // | MultiplicativeExpr 'mod' UnaryExpr xpath_ast_node* parse_expression(int limit = 0) { size_t old_depth = _depth; if (++_depth > xpath_ast_depth_limit) return error_rec(); xpath_ast_node* n = parse_path_or_unary_expression(); if (!n) return NULL; n = parse_expression_rec(n, limit); _depth = old_depth; return n; } xpath_parser(const char_t* query, xpath_variable_set* variables, xpath_allocator* alloc, xpath_parse_result* result): _alloc(alloc), _lexer(query), _query(query), _variables(variables), _result(result), _depth(0) { } xpath_ast_node* parse() { xpath_ast_node* n = parse_expression(); if (!n) return NULL; assert(_depth == 0); // check if there are unparsed tokens left if (_lexer.current() != lex_eof) return error("Incorrect query"); return n; } static xpath_ast_node* parse(const char_t* query, xpath_variable_set* variables, xpath_allocator* alloc, xpath_parse_result* result) { xpath_parser parser(query, variables, alloc, result); return parser.parse(); } }; struct xpath_query_impl { static xpath_query_impl* create() { void* memory = xml_memory::allocate(sizeof(xpath_query_impl)); if (!memory) return NULL; return new (memory) xpath_query_impl(); } static void destroy(xpath_query_impl* impl) { // free all allocated pages impl->alloc.release(); // free allocator memory (with the first page) xml_memory::deallocate(impl); } xpath_query_impl(): root(NULL), alloc(&block, &oom), oom(false) { block.next = NULL; block.capacity = sizeof(block.data); } xpath_ast_node* root; xpath_allocator alloc; xpath_memory_block block; bool oom; }; PUGI_IMPL_FN impl::xpath_ast_node* evaluate_node_set_prepare(xpath_query_impl* impl) { if (!impl) return NULL; if (impl->root->rettype() != xpath_type_node_set) { #ifdef PUGIXML_NO_EXCEPTIONS return 0; #else xpath_parse_result res; res.error = "Expression does not evaluate to node set"; throw xpath_exception(res); #endif } return impl->root; } PUGI_IMPL_NS_END namespace pugi { #ifndef PUGIXML_NO_EXCEPTIONS PUGI_IMPL_FN xpath_exception::xpath_exception(const xpath_parse_result& result_): _result(result_) { assert(_result.error); } PUGI_IMPL_FN const char* xpath_exception::what() const PUGIXML_NOEXCEPT { return _result.error; } PUGI_IMPL_FN const xpath_parse_result& xpath_exception::result() const { return _result; } #endif PUGI_IMPL_FN xpath_node::xpath_node() { } PUGI_IMPL_FN xpath_node::xpath_node(const xml_node& node_): _node(node_) { } PUGI_IMPL_FN xpath_node::xpath_node(const xml_attribute& attribute_, const xml_node& parent_): _node(attribute_ ? parent_ : xml_node()), _attribute(attribute_) { } PUGI_IMPL_FN xml_node xpath_node::node() const { return _attribute ? xml_node() : _node; } PUGI_IMPL_FN xml_attribute xpath_node::attribute() const { return _attribute; } PUGI_IMPL_FN xml_node xpath_node::parent() const { return _attribute ? _node : _node.parent(); } PUGI_IMPL_FN static void unspecified_bool_xpath_node(xpath_node***) { } PUGI_IMPL_FN xpath_node::operator xpath_node::unspecified_bool_type() const { return (_node || _attribute) ? unspecified_bool_xpath_node : NULL; } PUGI_IMPL_FN bool xpath_node::operator!() const { return !(_node || _attribute); } PUGI_IMPL_FN bool xpath_node::operator==(const xpath_node& n) const { return _node == n._node && _attribute == n._attribute; } PUGI_IMPL_FN bool xpath_node::operator!=(const xpath_node& n) const { return _node != n._node || _attribute != n._attribute; } #ifdef __BORLANDC__ PUGI_IMPL_FN bool operator&&(const xpath_node& lhs, bool rhs) { return (bool)lhs && rhs; } PUGI_IMPL_FN bool operator||(const xpath_node& lhs, bool rhs) { return (bool)lhs || rhs; } #endif PUGI_IMPL_FN void xpath_node_set::_assign(const_iterator begin_, const_iterator end_, type_t type_) { assert(begin_ <= end_); size_t size_ = static_cast(end_ - begin_); // use internal buffer for 0 or 1 elements, heap buffer otherwise xpath_node* storage = (size_ <= 1) ? _storage : static_cast(impl::xml_memory::allocate(size_ * sizeof(xpath_node))); if (!storage) { #ifdef PUGIXML_NO_EXCEPTIONS return; #else throw std::bad_alloc(); #endif } // deallocate old buffer if (_begin != _storage) impl::xml_memory::deallocate(_begin); // size check is necessary because for begin_ = end_ = nullptr, memcpy is UB if (size_) memcpy(storage, begin_, size_ * sizeof(xpath_node)); _begin = storage; _end = storage + size_; _type = type_; } #ifdef PUGIXML_HAS_MOVE PUGI_IMPL_FN void xpath_node_set::_move(xpath_node_set& rhs) PUGIXML_NOEXCEPT { _type = rhs._type; _storage[0] = rhs._storage[0]; _begin = (rhs._begin == rhs._storage) ? _storage : rhs._begin; _end = _begin + (rhs._end - rhs._begin); rhs._type = type_unsorted; rhs._begin = rhs._storage; rhs._end = rhs._storage; } #endif PUGI_IMPL_FN xpath_node_set::xpath_node_set(): _type(type_unsorted), _begin(_storage), _end(_storage) { } PUGI_IMPL_FN xpath_node_set::xpath_node_set(const_iterator begin_, const_iterator end_, type_t type_): _type(type_unsorted), _begin(_storage), _end(_storage) { _assign(begin_, end_, type_); } PUGI_IMPL_FN xpath_node_set::~xpath_node_set() { if (_begin != _storage) impl::xml_memory::deallocate(_begin); } PUGI_IMPL_FN xpath_node_set::xpath_node_set(const xpath_node_set& ns): _type(type_unsorted), _begin(_storage), _end(_storage) { _assign(ns._begin, ns._end, ns._type); } PUGI_IMPL_FN xpath_node_set& xpath_node_set::operator=(const xpath_node_set& ns) { if (this == &ns) return *this; _assign(ns._begin, ns._end, ns._type); return *this; } #ifdef PUGIXML_HAS_MOVE PUGI_IMPL_FN xpath_node_set::xpath_node_set(xpath_node_set&& rhs) PUGIXML_NOEXCEPT: _type(type_unsorted), _begin(_storage), _end(_storage) { _move(rhs); } PUGI_IMPL_FN xpath_node_set& xpath_node_set::operator=(xpath_node_set&& rhs) PUGIXML_NOEXCEPT { if (this == &rhs) return *this; if (_begin != _storage) impl::xml_memory::deallocate(_begin); _move(rhs); return *this; } #endif PUGI_IMPL_FN xpath_node_set::type_t xpath_node_set::type() const { return _type; } PUGI_IMPL_FN size_t xpath_node_set::size() const { return _end - _begin; } PUGI_IMPL_FN bool xpath_node_set::empty() const { return _begin == _end; } PUGI_IMPL_FN const xpath_node& xpath_node_set::operator[](size_t index) const { assert(index < size()); return _begin[index]; } PUGI_IMPL_FN xpath_node_set::const_iterator xpath_node_set::begin() const { return _begin; } PUGI_IMPL_FN xpath_node_set::const_iterator xpath_node_set::end() const { return _end; } PUGI_IMPL_FN void xpath_node_set::sort(bool reverse) { _type = impl::xpath_sort(_begin, _end, _type, reverse); } PUGI_IMPL_FN xpath_node xpath_node_set::first() const { return impl::xpath_first(_begin, _end, _type); } PUGI_IMPL_FN xpath_parse_result::xpath_parse_result(): error("Internal error"), offset(0) { } PUGI_IMPL_FN xpath_parse_result::operator bool() const { return error == NULL; } PUGI_IMPL_FN const char* xpath_parse_result::description() const { return error ? error : "No error"; } PUGI_IMPL_FN xpath_variable::xpath_variable(xpath_value_type type_): _type(type_), _next(NULL) { } PUGI_IMPL_FN const char_t* xpath_variable::name() const { switch (_type) { case xpath_type_node_set: return static_cast(this)->name; case xpath_type_number: return static_cast(this)->name; case xpath_type_string: return static_cast(this)->name; case xpath_type_boolean: return static_cast(this)->name; default: assert(false && "Invalid variable type"); // unreachable return NULL; } } PUGI_IMPL_FN xpath_value_type xpath_variable::type() const { return _type; } PUGI_IMPL_FN bool xpath_variable::get_boolean() const { return (_type == xpath_type_boolean) ? static_cast(this)->value : false; } PUGI_IMPL_FN double xpath_variable::get_number() const { return (_type == xpath_type_number) ? static_cast(this)->value : impl::gen_nan(); } PUGI_IMPL_FN const char_t* xpath_variable::get_string() const { const char_t* value = (_type == xpath_type_string) ? static_cast(this)->value : NULL; return value ? value : PUGIXML_TEXT(""); } PUGI_IMPL_FN const xpath_node_set& xpath_variable::get_node_set() const { return (_type == xpath_type_node_set) ? static_cast(this)->value : impl::dummy_node_set; } PUGI_IMPL_FN bool xpath_variable::set(bool value) { if (_type != xpath_type_boolean) return false; static_cast(this)->value = value; return true; } PUGI_IMPL_FN bool xpath_variable::set(double value) { if (_type != xpath_type_number) return false; static_cast(this)->value = value; return true; } PUGI_IMPL_FN bool xpath_variable::set(const char_t* value) { if (_type != xpath_type_string) return false; impl::xpath_variable_string* var = static_cast(this); // duplicate string size_t size = (impl::strlength(value) + 1) * sizeof(char_t); char_t* copy = static_cast(impl::xml_memory::allocate(size)); if (!copy) return false; memcpy(copy, value, size); // replace old string if (var->value) impl::xml_memory::deallocate(var->value); var->value = copy; return true; } PUGI_IMPL_FN bool xpath_variable::set(const xpath_node_set& value) { if (_type != xpath_type_node_set) return false; static_cast(this)->value = value; return true; } PUGI_IMPL_FN xpath_variable_set::xpath_variable_set() { for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i) _data[i] = NULL; } PUGI_IMPL_FN xpath_variable_set::~xpath_variable_set() { for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i) _destroy(_data[i]); } PUGI_IMPL_FN xpath_variable_set::xpath_variable_set(const xpath_variable_set& rhs) { for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i) _data[i] = NULL; _assign(rhs); } PUGI_IMPL_FN xpath_variable_set& xpath_variable_set::operator=(const xpath_variable_set& rhs) { if (this == &rhs) return *this; _assign(rhs); return *this; } #ifdef PUGIXML_HAS_MOVE PUGI_IMPL_FN xpath_variable_set::xpath_variable_set(xpath_variable_set&& rhs) PUGIXML_NOEXCEPT { for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i) { _data[i] = rhs._data[i]; rhs._data[i] = NULL; } } PUGI_IMPL_FN xpath_variable_set& xpath_variable_set::operator=(xpath_variable_set&& rhs) PUGIXML_NOEXCEPT { for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i) { _destroy(_data[i]); _data[i] = rhs._data[i]; rhs._data[i] = NULL; } return *this; } #endif PUGI_IMPL_FN void xpath_variable_set::_assign(const xpath_variable_set& rhs) { xpath_variable_set temp; for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i) if (rhs._data[i] && !_clone(rhs._data[i], &temp._data[i])) return; _swap(temp); } PUGI_IMPL_FN void xpath_variable_set::_swap(xpath_variable_set& rhs) { for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i) { xpath_variable* chain = _data[i]; _data[i] = rhs._data[i]; rhs._data[i] = chain; } } PUGI_IMPL_FN xpath_variable* xpath_variable_set::_find(const char_t* name) const { const size_t hash_size = sizeof(_data) / sizeof(_data[0]); size_t hash = impl::hash_string(name) % hash_size; // look for existing variable for (xpath_variable* var = _data[hash]; var; var = var->_next) if (impl::strequal(var->name(), name)) return var; return NULL; } PUGI_IMPL_FN bool xpath_variable_set::_clone(xpath_variable* var, xpath_variable** out_result) { xpath_variable* last = NULL; while (var) { // allocate storage for new variable xpath_variable* nvar = impl::new_xpath_variable(var->_type, var->name()); if (!nvar) return false; // link the variable to the result immediately to handle failures gracefully if (last) last->_next = nvar; else *out_result = nvar; last = nvar; // copy the value; this can fail due to out-of-memory conditions if (!impl::copy_xpath_variable(nvar, var)) return false; var = var->_next; } return true; } PUGI_IMPL_FN void xpath_variable_set::_destroy(xpath_variable* var) { while (var) { xpath_variable* next = var->_next; impl::delete_xpath_variable(var->_type, var); var = next; } } PUGI_IMPL_FN xpath_variable* xpath_variable_set::add(const char_t* name, xpath_value_type type) { const size_t hash_size = sizeof(_data) / sizeof(_data[0]); size_t hash = impl::hash_string(name) % hash_size; // look for existing variable for (xpath_variable* var = _data[hash]; var; var = var->_next) if (impl::strequal(var->name(), name)) return var->type() == type ? var : NULL; // add new variable xpath_variable* result = impl::new_xpath_variable(type, name); if (result) { result->_next = _data[hash]; _data[hash] = result; } return result; } PUGI_IMPL_FN bool xpath_variable_set::set(const char_t* name, bool value) { xpath_variable* var = add(name, xpath_type_boolean); return var ? var->set(value) : false; } PUGI_IMPL_FN bool xpath_variable_set::set(const char_t* name, double value) { xpath_variable* var = add(name, xpath_type_number); return var ? var->set(value) : false; } PUGI_IMPL_FN bool xpath_variable_set::set(const char_t* name, const char_t* value) { xpath_variable* var = add(name, xpath_type_string); return var ? var->set(value) : false; } PUGI_IMPL_FN bool xpath_variable_set::set(const char_t* name, const xpath_node_set& value) { xpath_variable* var = add(name, xpath_type_node_set); return var ? var->set(value) : false; } PUGI_IMPL_FN xpath_variable* xpath_variable_set::get(const char_t* name) { return _find(name); } PUGI_IMPL_FN const xpath_variable* xpath_variable_set::get(const char_t* name) const { return _find(name); } PUGI_IMPL_FN xpath_query::xpath_query(const char_t* query, xpath_variable_set* variables): _impl(NULL) { impl::xpath_query_impl* qimpl = impl::xpath_query_impl::create(); if (!qimpl) { #ifdef PUGIXML_NO_EXCEPTIONS _result.error = "Out of memory"; #else throw std::bad_alloc(); #endif } else { using impl::auto_deleter; // MSVC7 workaround auto_deleter impl(qimpl, impl::xpath_query_impl::destroy); qimpl->root = impl::xpath_parser::parse(query, variables, &qimpl->alloc, &_result); if (qimpl->root) { qimpl->root->optimize(&qimpl->alloc); _impl = impl.release(); _result.error = NULL; } else { #ifdef PUGIXML_NO_EXCEPTIONS if (qimpl->oom) _result.error = "Out of memory"; #else if (qimpl->oom) throw std::bad_alloc(); throw xpath_exception(_result); #endif } } } PUGI_IMPL_FN xpath_query::xpath_query(): _impl(NULL) { } PUGI_IMPL_FN xpath_query::~xpath_query() { if (_impl) impl::xpath_query_impl::destroy(static_cast(_impl)); } #ifdef PUGIXML_HAS_MOVE PUGI_IMPL_FN xpath_query::xpath_query(xpath_query&& rhs) PUGIXML_NOEXCEPT { _impl = rhs._impl; _result = rhs._result; rhs._impl = NULL; rhs._result = xpath_parse_result(); } PUGI_IMPL_FN xpath_query& xpath_query::operator=(xpath_query&& rhs) PUGIXML_NOEXCEPT { if (this == &rhs) return *this; if (_impl) impl::xpath_query_impl::destroy(static_cast(_impl)); _impl = rhs._impl; _result = rhs._result; rhs._impl = NULL; rhs._result = xpath_parse_result(); return *this; } #endif PUGI_IMPL_FN xpath_value_type xpath_query::return_type() const { if (!_impl) return xpath_type_none; return static_cast(_impl)->root->rettype(); } PUGI_IMPL_FN bool xpath_query::evaluate_boolean(const xpath_node& n) const { if (!_impl) return false; impl::xpath_context c(n, 1, 1); impl::xpath_stack_data sd; bool r = static_cast(_impl)->root->eval_boolean(c, sd.stack); if (sd.oom) { #ifdef PUGIXML_NO_EXCEPTIONS return false; #else throw std::bad_alloc(); #endif } return r; } PUGI_IMPL_FN double xpath_query::evaluate_number(const xpath_node& n) const { if (!_impl) return impl::gen_nan(); impl::xpath_context c(n, 1, 1); impl::xpath_stack_data sd; double r = static_cast(_impl)->root->eval_number(c, sd.stack); if (sd.oom) { #ifdef PUGIXML_NO_EXCEPTIONS return impl::gen_nan(); #else throw std::bad_alloc(); #endif } return r; } #ifndef PUGIXML_NO_STL PUGI_IMPL_FN string_t xpath_query::evaluate_string(const xpath_node& n) const { if (!_impl) return string_t(); impl::xpath_context c(n, 1, 1); impl::xpath_stack_data sd; impl::xpath_string r = static_cast(_impl)->root->eval_string(c, sd.stack); if (sd.oom) { #ifdef PUGIXML_NO_EXCEPTIONS return string_t(); #else throw std::bad_alloc(); #endif } return string_t(r.c_str(), r.length()); } #endif PUGI_IMPL_FN size_t xpath_query::evaluate_string(char_t* buffer, size_t capacity, const xpath_node& n) const { impl::xpath_context c(n, 1, 1); impl::xpath_stack_data sd; impl::xpath_string r = _impl ? static_cast(_impl)->root->eval_string(c, sd.stack) : impl::xpath_string(); if (sd.oom) { #ifdef PUGIXML_NO_EXCEPTIONS r = impl::xpath_string(); #else throw std::bad_alloc(); #endif } size_t full_size = r.length() + 1; if (capacity > 0) { size_t size = (full_size < capacity) ? full_size : capacity; assert(size > 0); memcpy(buffer, r.c_str(), (size - 1) * sizeof(char_t)); buffer[size - 1] = 0; } return full_size; } PUGI_IMPL_FN xpath_node_set xpath_query::evaluate_node_set(const xpath_node& n) const { impl::xpath_ast_node* root = impl::evaluate_node_set_prepare(static_cast(_impl)); if (!root) return xpath_node_set(); impl::xpath_context c(n, 1, 1); impl::xpath_stack_data sd; impl::xpath_node_set_raw r = root->eval_node_set(c, sd.stack, impl::nodeset_eval_all); if (sd.oom) { #ifdef PUGIXML_NO_EXCEPTIONS return xpath_node_set(); #else throw std::bad_alloc(); #endif } return xpath_node_set(r.begin(), r.end(), r.type()); } PUGI_IMPL_FN xpath_node xpath_query::evaluate_node(const xpath_node& n) const { impl::xpath_ast_node* root = impl::evaluate_node_set_prepare(static_cast(_impl)); if (!root) return xpath_node(); impl::xpath_context c(n, 1, 1); impl::xpath_stack_data sd; impl::xpath_node_set_raw r = root->eval_node_set(c, sd.stack, impl::nodeset_eval_first); if (sd.oom) { #ifdef PUGIXML_NO_EXCEPTIONS return xpath_node(); #else throw std::bad_alloc(); #endif } return r.first(); } PUGI_IMPL_FN const xpath_parse_result& xpath_query::result() const { return _result; } PUGI_IMPL_FN static void unspecified_bool_xpath_query(xpath_query***) { } PUGI_IMPL_FN xpath_query::operator xpath_query::unspecified_bool_type() const { return _impl ? unspecified_bool_xpath_query : NULL; } PUGI_IMPL_FN bool xpath_query::operator!() const { return !_impl; } PUGI_IMPL_FN xpath_node xml_node::select_node(const char_t* query, xpath_variable_set* variables) const { xpath_query q(query, variables); return q.evaluate_node(*this); } PUGI_IMPL_FN xpath_node xml_node::select_node(const xpath_query& query) const { return query.evaluate_node(*this); } PUGI_IMPL_FN xpath_node_set xml_node::select_nodes(const char_t* query, xpath_variable_set* variables) const { xpath_query q(query, variables); return q.evaluate_node_set(*this); } PUGI_IMPL_FN xpath_node_set xml_node::select_nodes(const xpath_query& query) const { return query.evaluate_node_set(*this); } PUGI_IMPL_FN xpath_node xml_node::select_single_node(const char_t* query, xpath_variable_set* variables) const { xpath_query q(query, variables); return q.evaluate_node(*this); } PUGI_IMPL_FN xpath_node xml_node::select_single_node(const xpath_query& query) const { return query.evaluate_node(*this); } } #endif #ifdef __BORLANDC__ # pragma option pop #endif #if defined(_MSC_VER) && defined(__c2__) # pragma clang diagnostic pop #endif #if defined(__clang__) # pragma clang diagnostic pop #endif // Intel C++ does not properly keep warning state for function templates, // so popping warning state at the end of translation unit leads to warnings in the middle. #if defined(_MSC_VER) && !defined(__INTEL_COMPILER) # pragma warning(pop) #endif // Undefine all local macros (makes sure we're not leaking macros in header-only mode) #undef PUGI_IMPL_NO_INLINE #undef PUGI_IMPL_UNLIKELY #undef PUGI_IMPL_STATIC_ASSERT #undef PUGI_IMPL_DMC_VOLATILE #undef PUGI_IMPL_UNSIGNED_OVERFLOW #undef PUGI_IMPL_MSVC_CRT_VERSION #undef PUGI_IMPL_SNPRINTF #undef PUGI_IMPL_NS_BEGIN #undef PUGI_IMPL_NS_END #undef PUGI_IMPL_FN #undef PUGI_IMPL_FN_NO_INLINE #undef PUGI_IMPL_GETHEADER_IMPL #undef PUGI_IMPL_GETPAGE_IMPL #undef PUGI_IMPL_GETPAGE #undef PUGI_IMPL_NODETYPE #undef PUGI_IMPL_IS_CHARTYPE_IMPL #undef PUGI_IMPL_IS_CHARTYPE #undef PUGI_IMPL_IS_CHARTYPEX #undef PUGI_IMPL_ENDSWITH #undef PUGI_IMPL_SKIPWS #undef PUGI_IMPL_OPTSET #undef PUGI_IMPL_PUSHNODE #undef PUGI_IMPL_POPNODE #undef PUGI_IMPL_SCANFOR #undef PUGI_IMPL_SCANWHILE #undef PUGI_IMPL_SCANWHILE_UNROLL #undef PUGI_IMPL_ENDSEG #undef PUGI_IMPL_THROW_ERROR #undef PUGI_IMPL_CHECK_ERROR #endif /** * Copyright (c) 2006-2025 Arseny Kapoulkine * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ ================================================ FILE: external/pugixml/src/pugixml.hpp ================================================ /** * pugixml parser - version 1.15 * -------------------------------------------------------- * Copyright (C) 2006-2025, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) * Report bugs and download new versions at https://pugixml.org/ * * This library is distributed under the MIT License. See notice at the end * of this file. * * This work is based on the pugxml parser, which is: * Copyright (C) 2003, by Kristen Wegner (kristen@tima.net) */ // Define version macro; evaluates to major * 1000 + minor * 10 + patch so that it's safe to use in less-than comparisons // Note: pugixml used major * 100 + minor * 10 + patch format up until 1.9 (which had version identifier 190); starting from pugixml 1.10, the minor version number is two digits #ifndef PUGIXML_VERSION # define PUGIXML_VERSION 1150 // 1.15 #endif // Include user configuration file (this can define various configuration macros) #include "pugiconfig.hpp" #ifndef HEADER_PUGIXML_HPP #define HEADER_PUGIXML_HPP // Include stddef.h for size_t and ptrdiff_t #include // Include exception header for XPath #if !defined(PUGIXML_NO_XPATH) && !defined(PUGIXML_NO_EXCEPTIONS) # include #endif // Include STL headers #ifndef PUGIXML_NO_STL # include # include # include #endif // Check if std::string_view is available #if !defined(PUGIXML_HAS_STRING_VIEW) && !defined(PUGIXML_NO_STL) # if __cplusplus >= 201703L # define PUGIXML_HAS_STRING_VIEW # elif defined(_MSVC_LANG) && _MSVC_LANG >= 201703L # define PUGIXML_HAS_STRING_VIEW # endif #endif // Include string_view if appropriate #ifdef PUGIXML_HAS_STRING_VIEW # include #endif // Macro for deprecated features #ifndef PUGIXML_DEPRECATED # if defined(__GNUC__) # define PUGIXML_DEPRECATED __attribute__((deprecated)) # elif defined(_MSC_VER) && _MSC_VER >= 1300 # define PUGIXML_DEPRECATED __declspec(deprecated) # else # define PUGIXML_DEPRECATED # endif #endif // If no API is defined, assume default #ifndef PUGIXML_API # define PUGIXML_API #endif // If no API for classes is defined, assume default #ifndef PUGIXML_CLASS # define PUGIXML_CLASS PUGIXML_API #endif // If no API for functions is defined, assume default #ifndef PUGIXML_FUNCTION # define PUGIXML_FUNCTION PUGIXML_API #endif // If the platform is known to have long long support, enable long long functions #ifndef PUGIXML_HAS_LONG_LONG # if __cplusplus >= 201103 # define PUGIXML_HAS_LONG_LONG # elif defined(_MSC_VER) && _MSC_VER >= 1400 # define PUGIXML_HAS_LONG_LONG # endif #endif // If the platform is known to have move semantics support, compile move ctor/operator implementation #ifndef PUGIXML_HAS_MOVE # if __cplusplus >= 201103 # define PUGIXML_HAS_MOVE # elif defined(_MSC_VER) && _MSC_VER >= 1600 # define PUGIXML_HAS_MOVE # endif #endif // If C++ is 2011 or higher, use 'noexcept' specifiers #ifndef PUGIXML_NOEXCEPT # if __cplusplus >= 201103 # define PUGIXML_NOEXCEPT noexcept # elif defined(_MSC_VER) && _MSC_VER >= 1900 # define PUGIXML_NOEXCEPT noexcept # else # define PUGIXML_NOEXCEPT throw() # endif #endif // Some functions can not be noexcept in compact mode #ifdef PUGIXML_COMPACT # define PUGIXML_NOEXCEPT_IF_NOT_COMPACT #else # define PUGIXML_NOEXCEPT_IF_NOT_COMPACT PUGIXML_NOEXCEPT #endif // If C++ is 2011 or higher, add 'override' qualifiers #ifndef PUGIXML_OVERRIDE # if __cplusplus >= 201103 # define PUGIXML_OVERRIDE override # elif defined(_MSC_VER) && _MSC_VER >= 1700 # define PUGIXML_OVERRIDE override # else # define PUGIXML_OVERRIDE # endif #endif // If C++ is 2011 or higher, use 'nullptr' #ifndef PUGIXML_NULL # if __cplusplus >= 201103 # define PUGIXML_NULL nullptr # elif defined(_MSC_VER) && _MSC_VER >= 1600 # define PUGIXML_NULL nullptr # else # define PUGIXML_NULL 0 # endif #endif // Character interface macros #ifdef PUGIXML_WCHAR_MODE # define PUGIXML_TEXT(t) L ## t # define PUGIXML_CHAR wchar_t #else # define PUGIXML_TEXT(t) t # define PUGIXML_CHAR char #endif namespace pugi { // Character type used for all internal storage and operations; depends on PUGIXML_WCHAR_MODE typedef PUGIXML_CHAR char_t; #ifndef PUGIXML_NO_STL // String type used for operations that work with STL string; depends on PUGIXML_WCHAR_MODE typedef std::basic_string string_t; #endif #ifdef PUGIXML_HAS_STRING_VIEW // String view type used for operations that can work with a length delimited string; depends on PUGIXML_WCHAR_MODE typedef std::basic_string_view string_view_t; #endif } // The PugiXML namespace namespace pugi { // Tree node types enum xml_node_type { node_null, // Empty (null) node handle node_document, // A document tree's absolute root node_element, // Element tag, i.e. '' node_pcdata, // Plain character data, i.e. 'text' node_cdata, // Character data, i.e. '' node_comment, // Comment tag, i.e. '' node_pi, // Processing instruction, i.e. '' node_declaration, // Document declaration, i.e. '' node_doctype // Document type declaration, i.e. '' }; // Parsing options // Minimal parsing mode (equivalent to turning all other flags off). // Only elements and PCDATA sections are added to the DOM tree, no text conversions are performed. const unsigned int parse_minimal = 0x0000; // This flag determines if processing instructions (node_pi) are added to the DOM tree. This flag is off by default. const unsigned int parse_pi = 0x0001; // This flag determines if comments (node_comment) are added to the DOM tree. This flag is off by default. const unsigned int parse_comments = 0x0002; // This flag determines if CDATA sections (node_cdata) are added to the DOM tree. This flag is on by default. const unsigned int parse_cdata = 0x0004; // This flag determines if plain character data (node_pcdata) that consist only of whitespace are added to the DOM tree. // This flag is off by default; turning it on usually results in slower parsing and more memory consumption. const unsigned int parse_ws_pcdata = 0x0008; // This flag determines if character and entity references are expanded during parsing. This flag is on by default. const unsigned int parse_escapes = 0x0010; // This flag determines if EOL characters are normalized (converted to #xA) during parsing. This flag is on by default. const unsigned int parse_eol = 0x0020; // This flag determines if attribute values are normalized using CDATA normalization rules during parsing. This flag is on by default. const unsigned int parse_wconv_attribute = 0x0040; // This flag determines if attribute values are normalized using NMTOKENS normalization rules during parsing. This flag is off by default. const unsigned int parse_wnorm_attribute = 0x0080; // This flag determines if document declaration (node_declaration) is added to the DOM tree. This flag is off by default. const unsigned int parse_declaration = 0x0100; // This flag determines if document type declaration (node_doctype) is added to the DOM tree. This flag is off by default. const unsigned int parse_doctype = 0x0200; // This flag determines if plain character data (node_pcdata) that is the only child of the parent node and that consists only // of whitespace is added to the DOM tree. // This flag is off by default; turning it on may result in slower parsing and more memory consumption. const unsigned int parse_ws_pcdata_single = 0x0400; // This flag determines if leading and trailing whitespace is to be removed from plain character data. This flag is off by default. const unsigned int parse_trim_pcdata = 0x0800; // This flag determines if plain character data that does not have a parent node is added to the DOM tree, and if an empty document // is a valid document. This flag is off by default. const unsigned int parse_fragment = 0x1000; // This flag determines if plain character data is be stored in the parent element's value. This significantly changes the structure of // the document; this flag is only recommended for parsing documents with many PCDATA nodes in memory-constrained environments. // This flag is off by default. const unsigned int parse_embed_pcdata = 0x2000; // This flag determines whether determines whether the the two pcdata should be merged or not, if no intermediatory data are parsed in the document. // This flag is off by default. const unsigned int parse_merge_pcdata = 0x4000; // The default parsing mode. // Elements, PCDATA and CDATA sections are added to the DOM tree, character/reference entities are expanded, // End-of-Line characters are normalized, attribute values are normalized using CDATA normalization rules. const unsigned int parse_default = parse_cdata | parse_escapes | parse_wconv_attribute | parse_eol; // The full parsing mode. // Nodes of all types are added to the DOM tree, character/reference entities are expanded, // End-of-Line characters are normalized, attribute values are normalized using CDATA normalization rules. const unsigned int parse_full = parse_default | parse_pi | parse_comments | parse_declaration | parse_doctype; // These flags determine the encoding of input data for XML document enum xml_encoding { encoding_auto, // Auto-detect input encoding using BOM or < / class xml_object_range { public: typedef It const_iterator; typedef It iterator; xml_object_range(It b, It e): _begin(b), _end(e) { } It begin() const { return _begin; } It end() const { return _end; } bool empty() const { return _begin == _end; } private: It _begin, _end; }; // Writer interface for node printing (see xml_node::print) class PUGIXML_CLASS xml_writer { public: virtual ~xml_writer(); // Write memory chunk into stream/file/whatever virtual void write(const void* data, size_t size) = 0; }; // xml_writer implementation for FILE* class PUGIXML_CLASS xml_writer_file: public xml_writer { public: // Construct writer from a FILE* object; void* is used to avoid header dependencies on stdio xml_writer_file(void* file); virtual void write(const void* data, size_t size) PUGIXML_OVERRIDE; private: void* file; }; #ifndef PUGIXML_NO_STL // xml_writer implementation for streams class PUGIXML_CLASS xml_writer_stream: public xml_writer { public: // Construct writer from an output stream object xml_writer_stream(std::basic_ostream& stream); xml_writer_stream(std::basic_ostream& stream); virtual void write(const void* data, size_t size) PUGIXML_OVERRIDE; private: std::basic_ostream* narrow_stream; std::basic_ostream* wide_stream; }; #endif // A light-weight handle for manipulating attributes in DOM tree class PUGIXML_CLASS xml_attribute { friend class xml_attribute_iterator; friend class xml_node; private: xml_attribute_struct* _attr; typedef void (*unspecified_bool_type)(xml_attribute***); public: // Default constructor. Constructs an empty attribute. xml_attribute(); // Constructs attribute from internal pointer explicit xml_attribute(xml_attribute_struct* attr); // Safe bool conversion operator operator unspecified_bool_type() const; // Borland C++ workaround bool operator!() const; // Comparison operators (compares wrapped attribute pointers) bool operator==(const xml_attribute& r) const; bool operator!=(const xml_attribute& r) const; bool operator<(const xml_attribute& r) const; bool operator>(const xml_attribute& r) const; bool operator<=(const xml_attribute& r) const; bool operator>=(const xml_attribute& r) const; // Check if attribute is empty (null) bool empty() const; // Get attribute name/value, or "" if attribute is empty const char_t* name() const; const char_t* value() const; // Get attribute value, or the default value if attribute is empty const char_t* as_string(const char_t* def = PUGIXML_TEXT("")) const; // Get attribute value as a number, or the default value if conversion did not succeed or attribute is empty int as_int(int def = 0) const; unsigned int as_uint(unsigned int def = 0) const; double as_double(double def = 0) const; float as_float(float def = 0) const; #ifdef PUGIXML_HAS_LONG_LONG long long as_llong(long long def = 0) const; unsigned long long as_ullong(unsigned long long def = 0) const; #endif // Get attribute value as bool (returns true if first character is in '1tTyY' set), or the default value if attribute is empty bool as_bool(bool def = false) const; // Set attribute name/value (returns false if attribute is empty or there is not enough memory) bool set_name(const char_t* rhs); bool set_name(const char_t* rhs, size_t size); #ifdef PUGIXML_HAS_STRING_VIEW bool set_name(string_view_t rhs); #endif bool set_value(const char_t* rhs); bool set_value(const char_t* rhs, size_t size); #ifdef PUGIXML_HAS_STRING_VIEW bool set_value(string_view_t rhs); #endif // Set attribute value with type conversion (numbers are converted to strings, boolean is converted to "true"/"false") bool set_value(int rhs); bool set_value(unsigned int rhs); bool set_value(long rhs); bool set_value(unsigned long rhs); bool set_value(double rhs); bool set_value(double rhs, int precision); bool set_value(float rhs); bool set_value(float rhs, int precision); bool set_value(bool rhs); #ifdef PUGIXML_HAS_LONG_LONG bool set_value(long long rhs); bool set_value(unsigned long long rhs); #endif // Set attribute value (equivalent to set_value without error checking) xml_attribute& operator=(const char_t* rhs); xml_attribute& operator=(int rhs); xml_attribute& operator=(unsigned int rhs); xml_attribute& operator=(long rhs); xml_attribute& operator=(unsigned long rhs); xml_attribute& operator=(double rhs); xml_attribute& operator=(float rhs); xml_attribute& operator=(bool rhs); #ifdef PUGIXML_HAS_STRING_VIEW xml_attribute& operator=(string_view_t rhs); #endif #ifdef PUGIXML_HAS_LONG_LONG xml_attribute& operator=(long long rhs); xml_attribute& operator=(unsigned long long rhs); #endif // Get next/previous attribute in the attribute list of the parent node xml_attribute next_attribute() const; xml_attribute previous_attribute() const; // Get hash value (unique for handles to the same object) size_t hash_value() const; // Get internal pointer xml_attribute_struct* internal_object() const; }; #ifdef __BORLANDC__ // Borland C++ workaround bool PUGIXML_FUNCTION operator&&(const xml_attribute& lhs, bool rhs); bool PUGIXML_FUNCTION operator||(const xml_attribute& lhs, bool rhs); #endif // A light-weight handle for manipulating nodes in DOM tree class PUGIXML_CLASS xml_node { friend class xml_attribute_iterator; friend class xml_node_iterator; friend class xml_named_node_iterator; protected: xml_node_struct* _root; typedef void (*unspecified_bool_type)(xml_node***); public: // Default constructor. Constructs an empty node. xml_node(); // Constructs node from internal pointer explicit xml_node(xml_node_struct* p); // Safe bool conversion operator operator unspecified_bool_type() const; // Borland C++ workaround bool operator!() const; // Comparison operators (compares wrapped node pointers) bool operator==(const xml_node& r) const; bool operator!=(const xml_node& r) const; bool operator<(const xml_node& r) const; bool operator>(const xml_node& r) const; bool operator<=(const xml_node& r) const; bool operator>=(const xml_node& r) const; // Check if node is empty (null) bool empty() const; // Get node type xml_node_type type() const; // Get node name, or "" if node is empty or it has no name const char_t* name() const; // Get node value, or "" if node is empty or it has no value // Note: For text node.value() does not return "text"! Use child_value() or text() methods to access text inside nodes. const char_t* value() const; // Get attribute list xml_attribute first_attribute() const; xml_attribute last_attribute() const; // Get children list xml_node first_child() const; xml_node last_child() const; // Get next/previous sibling in the children list of the parent node xml_node next_sibling() const; xml_node previous_sibling() const; // Get parent node xml_node parent() const; // Get root of DOM tree this node belongs to xml_node root() const; // Get text object for the current node xml_text text() const; // Get child, attribute or next/previous sibling with the specified name xml_node child(const char_t* name) const; xml_attribute attribute(const char_t* name) const; xml_node next_sibling(const char_t* name) const; xml_node previous_sibling(const char_t* name) const; #ifdef PUGIXML_HAS_STRING_VIEW xml_node child(string_view_t name) const; xml_attribute attribute(string_view_t name) const; xml_node next_sibling(string_view_t name) const; xml_node previous_sibling(string_view_t name) const; #endif // Get attribute, starting the search from a hint (and updating hint so that searching for a sequence of attributes is fast) xml_attribute attribute(const char_t* name, xml_attribute& hint) const; #ifdef PUGIXML_HAS_STRING_VIEW xml_attribute attribute(string_view_t name, xml_attribute& hint) const; #endif // Get child value of current node; that is, value of the first child node of type PCDATA/CDATA const char_t* child_value() const; // Get child value of child with specified name. Equivalent to child(name).child_value(). const char_t* child_value(const char_t* name) const; // Set node name/value (returns false if node is empty, there is not enough memory, or node can not have name/value) bool set_name(const char_t* rhs); bool set_name(const char_t* rhs, size_t size); #ifdef PUGIXML_HAS_STRING_VIEW bool set_name(string_view_t rhs); #endif bool set_value(const char_t* rhs); bool set_value(const char_t* rhs, size_t size); #ifdef PUGIXML_HAS_STRING_VIEW bool set_value(string_view_t rhs); #endif // Add attribute with specified name. Returns added attribute, or empty attribute on errors. xml_attribute append_attribute(const char_t* name); xml_attribute prepend_attribute(const char_t* name); xml_attribute insert_attribute_after(const char_t* name, const xml_attribute& attr); xml_attribute insert_attribute_before(const char_t* name, const xml_attribute& attr); #ifdef PUGIXML_HAS_STRING_VIEW xml_attribute append_attribute(string_view_t name); xml_attribute prepend_attribute(string_view_t name); xml_attribute insert_attribute_after(string_view_t name, const xml_attribute& attr); xml_attribute insert_attribute_before(string_view_t name, const xml_attribute& attr); #endif // Add a copy of the specified attribute. Returns added attribute, or empty attribute on errors. xml_attribute append_copy(const xml_attribute& proto); xml_attribute prepend_copy(const xml_attribute& proto); xml_attribute insert_copy_after(const xml_attribute& proto, const xml_attribute& attr); xml_attribute insert_copy_before(const xml_attribute& proto, const xml_attribute& attr); // Add child node with specified type. Returns added node, or empty node on errors. xml_node append_child(xml_node_type type = node_element); xml_node prepend_child(xml_node_type type = node_element); xml_node insert_child_after(xml_node_type type, const xml_node& node); xml_node insert_child_before(xml_node_type type, const xml_node& node); // Add child element with specified name. Returns added node, or empty node on errors. xml_node append_child(const char_t* name); xml_node prepend_child(const char_t* name); xml_node insert_child_after(const char_t* name, const xml_node& node); xml_node insert_child_before(const char_t* name, const xml_node& node); #ifdef PUGIXML_HAS_STRING_VIEW xml_node append_child(string_view_t name); xml_node prepend_child(string_view_t name); xml_node insert_child_after(string_view_t, const xml_node& node); xml_node insert_child_before(string_view_t name, const xml_node& node); #endif // Add a copy of the specified node as a child. Returns added node, or empty node on errors. xml_node append_copy(const xml_node& proto); xml_node prepend_copy(const xml_node& proto); xml_node insert_copy_after(const xml_node& proto, const xml_node& node); xml_node insert_copy_before(const xml_node& proto, const xml_node& node); // Move the specified node to become a child of this node. Returns moved node, or empty node on errors. xml_node append_move(const xml_node& moved); xml_node prepend_move(const xml_node& moved); xml_node insert_move_after(const xml_node& moved, const xml_node& node); xml_node insert_move_before(const xml_node& moved, const xml_node& node); // Remove specified attribute bool remove_attribute(const xml_attribute& a); bool remove_attribute(const char_t* name); #ifdef PUGIXML_HAS_STRING_VIEW bool remove_attribute(string_view_t name); #endif // Remove all attributes bool remove_attributes(); // Remove specified child bool remove_child(const xml_node& n); bool remove_child(const char_t* name); #ifdef PUGIXML_HAS_STRING_VIEW bool remove_child(string_view_t name); #endif // Remove all children bool remove_children(); // Parses buffer as an XML document fragment and appends all nodes as children of the current node. // Copies/converts the buffer, so it may be deleted or changed after the function returns. // Note: append_buffer allocates memory that has the lifetime of the owning document; removing the appended nodes does not immediately reclaim that memory. xml_parse_result append_buffer(const void* contents, size_t size, unsigned int options = parse_default, xml_encoding encoding = encoding_auto); // Find attribute using predicate. Returns first attribute for which predicate returned true. template xml_attribute find_attribute(Predicate pred) const { if (!_root) return xml_attribute(); for (xml_attribute attrib = first_attribute(); attrib; attrib = attrib.next_attribute()) if (pred(attrib)) return attrib; return xml_attribute(); } // Find child node using predicate. Returns first child for which predicate returned true. template xml_node find_child(Predicate pred) const { if (!_root) return xml_node(); for (xml_node node = first_child(); node; node = node.next_sibling()) if (pred(node)) return node; return xml_node(); } // Find node from subtree using predicate. Returns first node from subtree (depth-first), for which predicate returned true. template xml_node find_node(Predicate pred) const { if (!_root) return xml_node(); xml_node cur = first_child(); while (cur._root && cur._root != _root) { if (pred(cur)) return cur; if (cur.first_child()) cur = cur.first_child(); else if (cur.next_sibling()) cur = cur.next_sibling(); else { while (!cur.next_sibling() && cur._root != _root) cur = cur.parent(); if (cur._root != _root) cur = cur.next_sibling(); } } return xml_node(); } // Find child node by attribute name/value xml_node find_child_by_attribute(const char_t* name, const char_t* attr_name, const char_t* attr_value) const; xml_node find_child_by_attribute(const char_t* attr_name, const char_t* attr_value) const; #ifndef PUGIXML_NO_STL // Get the absolute node path from root as a text string. string_t path(char_t delimiter = '/') const; #endif // Search for a node by path consisting of node names and . or .. elements. xml_node first_element_by_path(const char_t* path, char_t delimiter = '/') const; // Recursively traverse subtree with xml_tree_walker bool traverse(xml_tree_walker& walker); #ifndef PUGIXML_NO_XPATH // Select single node by evaluating XPath query. Returns first node from the resulting node set. xpath_node select_node(const char_t* query, xpath_variable_set* variables = PUGIXML_NULL) const; xpath_node select_node(const xpath_query& query) const; // Select node set by evaluating XPath query xpath_node_set select_nodes(const char_t* query, xpath_variable_set* variables = PUGIXML_NULL) const; xpath_node_set select_nodes(const xpath_query& query) const; // (deprecated: use select_node instead) Select single node by evaluating XPath query. PUGIXML_DEPRECATED xpath_node select_single_node(const char_t* query, xpath_variable_set* variables = PUGIXML_NULL) const; PUGIXML_DEPRECATED xpath_node select_single_node(const xpath_query& query) const; #endif // Print subtree using a writer object void print(xml_writer& writer, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto, unsigned int depth = 0) const; #ifndef PUGIXML_NO_STL // Print subtree to stream void print(std::basic_ostream& os, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto, unsigned int depth = 0) const; void print(std::basic_ostream& os, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, unsigned int depth = 0) const; #endif // Child nodes iterators typedef xml_node_iterator iterator; iterator begin() const; iterator end() const; // Attribute iterators typedef xml_attribute_iterator attribute_iterator; attribute_iterator attributes_begin() const; attribute_iterator attributes_end() const; // Range-based for support xml_object_range children() const; xml_object_range attributes() const; // Range-based for support for all children with the specified name // Note: name pointer must have a longer lifetime than the returned object; be careful with passing temporaries! xml_object_range children(const char_t* name) const; // Get node offset in parsed file/string (in char_t units) for debugging purposes ptrdiff_t offset_debug() const; // Get hash value (unique for handles to the same object) size_t hash_value() const; // Get internal pointer xml_node_struct* internal_object() const; }; #ifdef __BORLANDC__ // Borland C++ workaround bool PUGIXML_FUNCTION operator&&(const xml_node& lhs, bool rhs); bool PUGIXML_FUNCTION operator||(const xml_node& lhs, bool rhs); #endif // A helper for working with text inside PCDATA nodes class PUGIXML_CLASS xml_text { friend class xml_node; xml_node_struct* _root; typedef void (*unspecified_bool_type)(xml_text***); explicit xml_text(xml_node_struct* root); xml_node_struct* _data_new(); xml_node_struct* _data() const; public: // Default constructor. Constructs an empty object. xml_text(); // Safe bool conversion operator operator unspecified_bool_type() const; // Borland C++ workaround bool operator!() const; // Check if text object is empty (null) bool empty() const; // Get text, or "" if object is empty const char_t* get() const; // Get text, or the default value if object is empty const char_t* as_string(const char_t* def = PUGIXML_TEXT("")) const; // Get text as a number, or the default value if conversion did not succeed or object is empty int as_int(int def = 0) const; unsigned int as_uint(unsigned int def = 0) const; double as_double(double def = 0) const; float as_float(float def = 0) const; #ifdef PUGIXML_HAS_LONG_LONG long long as_llong(long long def = 0) const; unsigned long long as_ullong(unsigned long long def = 0) const; #endif // Get text as bool (returns true if first character is in '1tTyY' set), or the default value if object is empty bool as_bool(bool def = false) const; // Set text (returns false if object is empty or there is not enough memory) bool set(const char_t* rhs); bool set(const char_t* rhs, size_t size); #ifdef PUGIXML_HAS_STRING_VIEW bool set(string_view_t rhs); #endif // Set text with type conversion (numbers are converted to strings, boolean is converted to "true"/"false") bool set(int rhs); bool set(unsigned int rhs); bool set(long rhs); bool set(unsigned long rhs); bool set(double rhs); bool set(double rhs, int precision); bool set(float rhs); bool set(float rhs, int precision); bool set(bool rhs); #ifdef PUGIXML_HAS_LONG_LONG bool set(long long rhs); bool set(unsigned long long rhs); #endif // Set text (equivalent to set without error checking) xml_text& operator=(const char_t* rhs); xml_text& operator=(int rhs); xml_text& operator=(unsigned int rhs); xml_text& operator=(long rhs); xml_text& operator=(unsigned long rhs); xml_text& operator=(double rhs); xml_text& operator=(float rhs); xml_text& operator=(bool rhs); #ifdef PUGIXML_HAS_STRING_VIEW xml_text& operator=(string_view_t rhs); #endif #ifdef PUGIXML_HAS_LONG_LONG xml_text& operator=(long long rhs); xml_text& operator=(unsigned long long rhs); #endif // Get the data node (node_pcdata or node_cdata) for this object xml_node data() const; }; #ifdef __BORLANDC__ // Borland C++ workaround bool PUGIXML_FUNCTION operator&&(const xml_text& lhs, bool rhs); bool PUGIXML_FUNCTION operator||(const xml_text& lhs, bool rhs); #endif // Child node iterator (a bidirectional iterator over a collection of xml_node) class PUGIXML_CLASS xml_node_iterator { friend class xml_node; private: mutable xml_node _wrap; xml_node _parent; xml_node_iterator(xml_node_struct* ref, xml_node_struct* parent); public: // Iterator traits typedef ptrdiff_t difference_type; typedef xml_node value_type; typedef xml_node* pointer; typedef xml_node& reference; #ifndef PUGIXML_NO_STL typedef std::bidirectional_iterator_tag iterator_category; #endif // Default constructor xml_node_iterator(); // Construct an iterator which points to the specified node xml_node_iterator(const xml_node& node); // Iterator operators bool operator==(const xml_node_iterator& rhs) const; bool operator!=(const xml_node_iterator& rhs) const; xml_node& operator*() const; xml_node* operator->() const; xml_node_iterator& operator++(); xml_node_iterator operator++(int); xml_node_iterator& operator--(); xml_node_iterator operator--(int); }; // Attribute iterator (a bidirectional iterator over a collection of xml_attribute) class PUGIXML_CLASS xml_attribute_iterator { friend class xml_node; private: mutable xml_attribute _wrap; xml_node _parent; xml_attribute_iterator(xml_attribute_struct* ref, xml_node_struct* parent); public: // Iterator traits typedef ptrdiff_t difference_type; typedef xml_attribute value_type; typedef xml_attribute* pointer; typedef xml_attribute& reference; #ifndef PUGIXML_NO_STL typedef std::bidirectional_iterator_tag iterator_category; #endif // Default constructor xml_attribute_iterator(); // Construct an iterator which points to the specified attribute xml_attribute_iterator(const xml_attribute& attr, const xml_node& parent); // Iterator operators bool operator==(const xml_attribute_iterator& rhs) const; bool operator!=(const xml_attribute_iterator& rhs) const; xml_attribute& operator*() const; xml_attribute* operator->() const; xml_attribute_iterator& operator++(); xml_attribute_iterator operator++(int); xml_attribute_iterator& operator--(); xml_attribute_iterator operator--(int); }; // Named node range helper class PUGIXML_CLASS xml_named_node_iterator { friend class xml_node; public: // Iterator traits typedef ptrdiff_t difference_type; typedef xml_node value_type; typedef xml_node* pointer; typedef xml_node& reference; #ifndef PUGIXML_NO_STL typedef std::bidirectional_iterator_tag iterator_category; #endif // Default constructor xml_named_node_iterator(); // Construct an iterator which points to the specified node // Note: name pointer is stored in the iterator and must have a longer lifetime than iterator itself xml_named_node_iterator(const xml_node& node, const char_t* name); // Iterator operators bool operator==(const xml_named_node_iterator& rhs) const; bool operator!=(const xml_named_node_iterator& rhs) const; xml_node& operator*() const; xml_node* operator->() const; xml_named_node_iterator& operator++(); xml_named_node_iterator operator++(int); xml_named_node_iterator& operator--(); xml_named_node_iterator operator--(int); private: mutable xml_node _wrap; xml_node _parent; const char_t* _name; xml_named_node_iterator(xml_node_struct* ref, xml_node_struct* parent, const char_t* name); }; // Abstract tree walker class (see xml_node::traverse) class PUGIXML_CLASS xml_tree_walker { friend class xml_node; private: int _depth; protected: // Get current traversal depth int depth() const; public: xml_tree_walker(); virtual ~xml_tree_walker(); // Callback that is called when traversal begins virtual bool begin(xml_node& node); // Callback that is called for each node traversed virtual bool for_each(xml_node& node) = 0; // Callback that is called when traversal ends virtual bool end(xml_node& node); }; // Parsing status, returned as part of xml_parse_result object enum xml_parse_status { status_ok = 0, // No error status_file_not_found, // File was not found during load_file() status_io_error, // Error reading from file/stream status_out_of_memory, // Could not allocate memory status_internal_error, // Internal error occurred status_unrecognized_tag, // Parser could not determine tag type status_bad_pi, // Parsing error occurred while parsing document declaration/processing instruction status_bad_comment, // Parsing error occurred while parsing comment status_bad_cdata, // Parsing error occurred while parsing CDATA section status_bad_doctype, // Parsing error occurred while parsing document type declaration status_bad_pcdata, // Parsing error occurred while parsing PCDATA section status_bad_start_element, // Parsing error occurred while parsing start element tag status_bad_attribute, // Parsing error occurred while parsing element attribute status_bad_end_element, // Parsing error occurred while parsing end element tag status_end_element_mismatch,// There was a mismatch of start-end tags (closing tag had incorrect name, some tag was not closed or there was an excessive closing tag) status_append_invalid_root, // Unable to append nodes since root type is not node_element or node_document (exclusive to xml_node::append_buffer) status_no_document_element // Parsing resulted in a document without element nodes }; // Parsing result struct PUGIXML_CLASS xml_parse_result { // Parsing status (see xml_parse_status) xml_parse_status status; // Last parsed offset (in char_t units from start of input data) ptrdiff_t offset; // Source document encoding xml_encoding encoding; // Default constructor, initializes object to failed state xml_parse_result(); // Cast to bool operator operator bool() const; // Get error description const char* description() const; }; // Document class (DOM tree root) class PUGIXML_CLASS xml_document: public xml_node { private: char_t* _buffer; char _memory[192]; // Non-copyable semantics xml_document(const xml_document&); xml_document& operator=(const xml_document&); void _create(); void _destroy(); void _move(xml_document& rhs) PUGIXML_NOEXCEPT_IF_NOT_COMPACT; public: // Default constructor, makes empty document xml_document(); // Destructor, invalidates all node/attribute handles to this document ~xml_document(); #ifdef PUGIXML_HAS_MOVE // Move semantics support xml_document(xml_document&& rhs) PUGIXML_NOEXCEPT_IF_NOT_COMPACT; xml_document& operator=(xml_document&& rhs) PUGIXML_NOEXCEPT_IF_NOT_COMPACT; #endif // Removes all nodes, leaving the empty document void reset(); // Removes all nodes, then copies the entire contents of the specified document void reset(const xml_document& proto); #ifndef PUGIXML_NO_STL // Load document from stream. xml_parse_result load(std::basic_istream& stream, unsigned int options = parse_default, xml_encoding encoding = encoding_auto); xml_parse_result load(std::basic_istream& stream, unsigned int options = parse_default); #endif // (deprecated: use load_string instead) Load document from zero-terminated string. No encoding conversions are applied. PUGIXML_DEPRECATED xml_parse_result load(const char_t* contents, unsigned int options = parse_default); // Load document from zero-terminated string. No encoding conversions are applied. xml_parse_result load_string(const char_t* contents, unsigned int options = parse_default); // Load document from file xml_parse_result load_file(const char* path, unsigned int options = parse_default, xml_encoding encoding = encoding_auto); xml_parse_result load_file(const wchar_t* path, unsigned int options = parse_default, xml_encoding encoding = encoding_auto); // Load document from buffer. Copies/converts the buffer, so it may be deleted or changed after the function returns. xml_parse_result load_buffer(const void* contents, size_t size, unsigned int options = parse_default, xml_encoding encoding = encoding_auto); // Load document from buffer, using the buffer for in-place parsing (the buffer is modified and used for storage of document data). // You should ensure that buffer data will persist throughout the document's lifetime, and free the buffer memory manually once document is destroyed. xml_parse_result load_buffer_inplace(void* contents, size_t size, unsigned int options = parse_default, xml_encoding encoding = encoding_auto); // Load document from buffer, using the buffer for in-place parsing (the buffer is modified and used for storage of document data). // You should allocate the buffer with pugixml allocation function; document will free the buffer when it is no longer needed (you can't use it anymore). xml_parse_result load_buffer_inplace_own(void* contents, size_t size, unsigned int options = parse_default, xml_encoding encoding = encoding_auto); // Save XML document to writer (semantics is slightly different from xml_node::print, see documentation for details). void save(xml_writer& writer, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto) const; #ifndef PUGIXML_NO_STL // Save XML document to stream (semantics is slightly different from xml_node::print, see documentation for details). void save(std::basic_ostream& stream, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto) const; void save(std::basic_ostream& stream, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default) const; #endif // Save XML to file bool save_file(const char* path, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto) const; bool save_file(const wchar_t* path, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto) const; // Get document element xml_node document_element() const; }; #ifndef PUGIXML_NO_XPATH // XPath query return type enum xpath_value_type { xpath_type_none, // Unknown type (query failed to compile) xpath_type_node_set, // Node set (xpath_node_set) xpath_type_number, // Number xpath_type_string, // String xpath_type_boolean // Boolean }; // XPath parsing result struct PUGIXML_CLASS xpath_parse_result { // Error message (0 if no error) const char* error; // Last parsed offset (in char_t units from string start) ptrdiff_t offset; // Default constructor, initializes object to failed state xpath_parse_result(); // Cast to bool operator operator bool() const; // Get error description const char* description() const; }; // A single XPath variable class PUGIXML_CLASS xpath_variable { friend class xpath_variable_set; protected: xpath_value_type _type; xpath_variable* _next; xpath_variable(xpath_value_type type); // Non-copyable semantics xpath_variable(const xpath_variable&); xpath_variable& operator=(const xpath_variable&); public: // Get variable name const char_t* name() const; // Get variable type xpath_value_type type() const; // Get variable value; no type conversion is performed, default value (false, NaN, empty string, empty node set) is returned on type mismatch error bool get_boolean() const; double get_number() const; const char_t* get_string() const; const xpath_node_set& get_node_set() const; // Set variable value; no type conversion is performed, false is returned on type mismatch error bool set(bool value); bool set(double value); bool set(const char_t* value); bool set(const xpath_node_set& value); }; // A set of XPath variables class PUGIXML_CLASS xpath_variable_set { private: xpath_variable* _data[64]; void _assign(const xpath_variable_set& rhs); void _swap(xpath_variable_set& rhs); xpath_variable* _find(const char_t* name) const; static bool _clone(xpath_variable* var, xpath_variable** out_result); static void _destroy(xpath_variable* var); public: // Default constructor/destructor xpath_variable_set(); ~xpath_variable_set(); // Copy constructor/assignment operator xpath_variable_set(const xpath_variable_set& rhs); xpath_variable_set& operator=(const xpath_variable_set& rhs); #ifdef PUGIXML_HAS_MOVE // Move semantics support xpath_variable_set(xpath_variable_set&& rhs) PUGIXML_NOEXCEPT; xpath_variable_set& operator=(xpath_variable_set&& rhs) PUGIXML_NOEXCEPT; #endif // Add a new variable or get the existing one, if the types match xpath_variable* add(const char_t* name, xpath_value_type type); // Set value of an existing variable; no type conversion is performed, false is returned if there is no such variable or if types mismatch bool set(const char_t* name, bool value); bool set(const char_t* name, double value); bool set(const char_t* name, const char_t* value); bool set(const char_t* name, const xpath_node_set& value); // Get existing variable by name xpath_variable* get(const char_t* name); const xpath_variable* get(const char_t* name) const; }; // A compiled XPath query object class PUGIXML_CLASS xpath_query { private: void* _impl; xpath_parse_result _result; typedef void (*unspecified_bool_type)(xpath_query***); // Non-copyable semantics xpath_query(const xpath_query&); xpath_query& operator=(const xpath_query&); public: // Construct a compiled object from XPath expression. // If PUGIXML_NO_EXCEPTIONS is not defined, throws xpath_exception on compilation errors. explicit xpath_query(const char_t* query, xpath_variable_set* variables = PUGIXML_NULL); // Constructor xpath_query(); // Destructor ~xpath_query(); #ifdef PUGIXML_HAS_MOVE // Move semantics support xpath_query(xpath_query&& rhs) PUGIXML_NOEXCEPT; xpath_query& operator=(xpath_query&& rhs) PUGIXML_NOEXCEPT; #endif // Get query expression return type xpath_value_type return_type() const; // Evaluate expression as boolean value in the specified context; performs type conversion if necessary. // If PUGIXML_NO_EXCEPTIONS is not defined, throws std::bad_alloc on out of memory errors. bool evaluate_boolean(const xpath_node& n) const; // Evaluate expression as double value in the specified context; performs type conversion if necessary. // If PUGIXML_NO_EXCEPTIONS is not defined, throws std::bad_alloc on out of memory errors. double evaluate_number(const xpath_node& n) const; #ifndef PUGIXML_NO_STL // Evaluate expression as string value in the specified context; performs type conversion if necessary. // If PUGIXML_NO_EXCEPTIONS is not defined, throws std::bad_alloc on out of memory errors. string_t evaluate_string(const xpath_node& n) const; #endif // Evaluate expression as string value in the specified context; performs type conversion if necessary. // At most capacity characters are written to the destination buffer, full result size is returned (includes terminating zero). // If PUGIXML_NO_EXCEPTIONS is not defined, throws std::bad_alloc on out of memory errors. // If PUGIXML_NO_EXCEPTIONS is defined, returns empty set instead. size_t evaluate_string(char_t* buffer, size_t capacity, const xpath_node& n) const; // Evaluate expression as node set in the specified context. // If PUGIXML_NO_EXCEPTIONS is not defined, throws xpath_exception on type mismatch and std::bad_alloc on out of memory errors. // If PUGIXML_NO_EXCEPTIONS is defined, returns empty node set instead. xpath_node_set evaluate_node_set(const xpath_node& n) const; // Evaluate expression as node set in the specified context. // Return first node in document order, or empty node if node set is empty. // If PUGIXML_NO_EXCEPTIONS is not defined, throws xpath_exception on type mismatch and std::bad_alloc on out of memory errors. // If PUGIXML_NO_EXCEPTIONS is defined, returns empty node instead. xpath_node evaluate_node(const xpath_node& n) const; // Get parsing result (used to get compilation errors in PUGIXML_NO_EXCEPTIONS mode) const xpath_parse_result& result() const; // Safe bool conversion operator operator unspecified_bool_type() const; // Borland C++ workaround bool operator!() const; }; #ifndef PUGIXML_NO_EXCEPTIONS #if defined(_MSC_VER) // C4275 can be ignored in Visual C++ if you are deriving // from a type in the Standard C++ Library #pragma warning(push) #pragma warning(disable: 4275) #endif // XPath exception class class PUGIXML_CLASS xpath_exception: public std::exception { private: xpath_parse_result _result; public: // Construct exception from parse result explicit xpath_exception(const xpath_parse_result& result); // Get error message virtual const char* what() const PUGIXML_NOEXCEPT PUGIXML_OVERRIDE; // Get parse result const xpath_parse_result& result() const; }; #if defined(_MSC_VER) #pragma warning(pop) #endif #endif // XPath node class (either xml_node or xml_attribute) class PUGIXML_CLASS xpath_node { private: xml_node _node; xml_attribute _attribute; typedef void (*unspecified_bool_type)(xpath_node***); public: // Default constructor; constructs empty XPath node xpath_node(); // Construct XPath node from XML node/attribute xpath_node(const xml_node& node); xpath_node(const xml_attribute& attribute, const xml_node& parent); // Get node/attribute, if any xml_node node() const; xml_attribute attribute() const; // Get parent of contained node/attribute xml_node parent() const; // Safe bool conversion operator operator unspecified_bool_type() const; // Borland C++ workaround bool operator!() const; // Comparison operators bool operator==(const xpath_node& n) const; bool operator!=(const xpath_node& n) const; }; #ifdef __BORLANDC__ // Borland C++ workaround bool PUGIXML_FUNCTION operator&&(const xpath_node& lhs, bool rhs); bool PUGIXML_FUNCTION operator||(const xpath_node& lhs, bool rhs); #endif // A fixed-size collection of XPath nodes class PUGIXML_CLASS xpath_node_set { public: // Collection type enum type_t { type_unsorted, // Not ordered type_sorted, // Sorted by document order (ascending) type_sorted_reverse // Sorted by document order (descending) }; // Constant iterator type typedef const xpath_node* const_iterator; // We define non-constant iterator to be the same as constant iterator so that various generic algorithms (i.e. boost foreach) work typedef const xpath_node* iterator; // Default constructor. Constructs empty set. xpath_node_set(); // Constructs a set from iterator range; data is not checked for duplicates and is not sorted according to provided type, so be careful xpath_node_set(const_iterator begin, const_iterator end, type_t type = type_unsorted); // Destructor ~xpath_node_set(); // Copy constructor/assignment operator xpath_node_set(const xpath_node_set& ns); xpath_node_set& operator=(const xpath_node_set& ns); #ifdef PUGIXML_HAS_MOVE // Move semantics support xpath_node_set(xpath_node_set&& rhs) PUGIXML_NOEXCEPT; xpath_node_set& operator=(xpath_node_set&& rhs) PUGIXML_NOEXCEPT; #endif // Get collection type type_t type() const; // Get collection size size_t size() const; // Indexing operator const xpath_node& operator[](size_t index) const; // Collection iterators const_iterator begin() const; const_iterator end() const; // Sort the collection in ascending/descending order by document order void sort(bool reverse = false); // Get first node in the collection by document order xpath_node first() const; // Check if collection is empty bool empty() const; private: type_t _type; xpath_node _storage[1]; xpath_node* _begin; xpath_node* _end; void _assign(const_iterator begin, const_iterator end, type_t type); void _move(xpath_node_set& rhs) PUGIXML_NOEXCEPT; }; #endif #ifndef PUGIXML_NO_STL // Convert wide string to UTF8 std::basic_string PUGIXML_FUNCTION as_utf8(const wchar_t* str); std::basic_string PUGIXML_FUNCTION as_utf8(const std::basic_string& str); // Convert UTF8 to wide string std::basic_string PUGIXML_FUNCTION as_wide(const char* str); std::basic_string PUGIXML_FUNCTION as_wide(const std::basic_string& str); #endif // Memory allocation function interface; returns pointer to allocated memory or NULL on failure typedef void* (*allocation_function)(size_t size); // Memory deallocation function interface typedef void (*deallocation_function)(void* ptr); // Override default memory management functions. All subsequent allocations/deallocations will be performed via supplied functions. void PUGIXML_FUNCTION set_memory_management_functions(allocation_function allocate, deallocation_function deallocate); // Get current memory management functions allocation_function PUGIXML_FUNCTION get_memory_allocation_function(); deallocation_function PUGIXML_FUNCTION get_memory_deallocation_function(); } #if !defined(PUGIXML_NO_STL) && (defined(_MSC_VER) || defined(__ICC)) namespace std { // Workarounds for (non-standard) iterator category detection for older versions (MSVC7/IC8 and earlier) std::bidirectional_iterator_tag PUGIXML_FUNCTION _Iter_cat(const pugi::xml_node_iterator&); std::bidirectional_iterator_tag PUGIXML_FUNCTION _Iter_cat(const pugi::xml_attribute_iterator&); std::bidirectional_iterator_tag PUGIXML_FUNCTION _Iter_cat(const pugi::xml_named_node_iterator&); } #endif #if !defined(PUGIXML_NO_STL) && defined(__SUNPRO_CC) namespace std { // Workarounds for (non-standard) iterator category detection std::bidirectional_iterator_tag PUGIXML_FUNCTION __iterator_category(const pugi::xml_node_iterator&); std::bidirectional_iterator_tag PUGIXML_FUNCTION __iterator_category(const pugi::xml_attribute_iterator&); std::bidirectional_iterator_tag PUGIXML_FUNCTION __iterator_category(const pugi::xml_named_node_iterator&); } #endif #endif // Make sure implementation is included in header-only mode // Use macro expansion in #include to work around QMake (QTBUG-11923) #if defined(PUGIXML_HEADER_ONLY) && !defined(PUGIXML_SOURCE) # define PUGIXML_SOURCE "pugixml.cpp" # include PUGIXML_SOURCE #endif /** * Copyright (c) 2006-2025 Arseny Kapoulkine * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ ================================================ FILE: tests/.gitignore ================================================ build/ ================================================ FILE: tests/run_all_tests.sh ================================================ #!/usr/bin/env bash set -euo pipefail ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" declare -a TEST_SCRIPTS=( "$ROOT_DIR/tests/run_database_tests.sh" "$ROOT_DIR/tests/run_translation_tests.sh" ) echo "Running AI File Sorter test suite" echo "=================================" for script in "${TEST_SCRIPTS[@]}"; do if [[ ! -x "$script" ]]; then echo "ERROR: Test script '$script' is missing or not executable." >&2 exit 1 fi name="$(basename "$script")" echo "" echo ">>> $name" "$script" done echo "" echo "All tests completed successfully." ================================================ FILE: tests/run_database_tests.sh ================================================ #!/usr/bin/env bash set -euo pipefail ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" BUILD_DIR="$ROOT_DIR/tests/build" mkdir -p "$BUILD_DIR" mkdir -p "$BUILD_DIR/spdlog/sinks" mkdir -p "$BUILD_DIR/spdlog/fmt" TEST_SRC="$BUILD_DIR/database_manager_test.cpp" STUB_SRC="$BUILD_DIR/logger_stub.cpp" OUTPUT="$BUILD_DIR/database_manager_test" cat > "$TEST_SRC" <<'CPP' #include "DatabaseManager.hpp" #include "Types.hpp" #include #include #include #include #include #include #include namespace { struct TempDir { explicit TempDir(std::filesystem::path p) : path(std::move(p)) {} ~TempDir() { std::error_code ec; std::filesystem::remove_all(path, ec); } std::filesystem::path path; }; [[noreturn]] void fail(const std::string& message) { std::cerr << message << '\n'; std::exit(1); } } // namespace int main() { const auto unique_dir = std::filesystem::temp_directory_path() / ("aifs-dbtest-" + std::to_string(std::chrono::steady_clock::now().time_since_epoch().count())); std::filesystem::create_directories(unique_dir); TempDir guard(unique_dir); DatabaseManager manager(unique_dir.string()); const std::string test_dir = "/sample"; DatabaseManager::ResolvedCategory valid{0, "Docs", "Manuals"}; DatabaseManager::ResolvedCategory empty_cat{0, "", ""}; DatabaseManager::ResolvedCategory whitespace_cat{0, " ", " "}; if (!manager.insert_or_update_file_with_categorization("valid.txt", "F", test_dir, valid, false, "")) { fail("Failed to insert valid row"); } if (!manager.insert_or_update_file_with_categorization("empty.txt", "F", test_dir, empty_cat, false, "")) { fail("Failed to insert empty row"); } if (!manager.insert_or_update_file_with_categorization("space.txt", "F", test_dir, whitespace_cat, false, "")) { fail("Failed to insert whitespace row"); } auto removed = manager.remove_empty_categorizations(test_dir); if (removed.size() != 2) { fail("Expected 2 entries removed, got " + std::to_string(removed.size())); } std::set removed_names; for (const auto& entry : removed) { removed_names.insert(entry.file_name); } if (!removed_names.contains("empty.txt") || !removed_names.contains("space.txt")) { fail("Unexpected entries removed"); } if (!manager.remove_empty_categorizations(test_dir).empty()) { fail("Subsequent cleanup should find no additional entries"); } auto empty_lookup = manager.get_categorization_from_db(test_dir, "empty.txt", FileType::File); if (!empty_lookup.empty()) { fail("Empty entry still present after cleanup"); } auto whitespace_lookup = manager.get_categorization_from_db(test_dir, "space.txt", FileType::File); if (!whitespace_lookup.empty()) { fail("Whitespace entry still present after cleanup"); } auto remaining = manager.get_categorized_files(test_dir); if (remaining.size() != 1 || remaining.front().file_name != "valid.txt" || remaining.front().category != "Docs" || remaining.front().subcategory != "Manuals") { fail("Valid entry was not preserved during cleanup"); } std::cout << "Database manager cleanup test passed" << std::endl; return 0; } CPP cat > "$STUB_SRC" <<'CPP' #include "Logger.hpp" #include std::string Logger::get_log_directory() { return std::filesystem::temp_directory_path().string(); } void Logger::setup_loggers() {} std::shared_ptr Logger::get_logger(const std::string&) { return nullptr; } std::string Logger::get_log_file_path(const std::string& log_dir, const std::string& log_name) { return log_dir + "/" + log_name; } CPP cat > "$BUILD_DIR/spdlog/spdlog.h" <<'CPP' #pragma once #include #include #include namespace spdlog { namespace level { enum level_enum { trace, debug, info, warn, err, critical, off }; } class logger { public: template void log(level::level_enum, const std::string&, Args&&...) {} template void info(const std::string&, Args&&...) {} template void warn(const std::string&, Args&&...) {} template void error(const std::string&, Args&&...) {} void flush_on(level::level_enum) {} void set_level(level::level_enum) {} }; inline std::shared_ptr get(const std::string&) { return nullptr; } inline void register_logger(std::shared_ptr) {} inline void flush_every(std::chrono::seconds) {} inline void set_level(level::level_enum) {} inline void info(const std::string&) {} } // namespace spdlog CPP cat > "$BUILD_DIR/spdlog/sinks/stdout_color_sinks.h" <<'CPP' #pragma once namespace spdlog { namespace sinks { class stdout_color_sink_mt {}; }} // namespace spdlog::sinks CPP cat > "$BUILD_DIR/spdlog/sinks/basic_file_sink.h" <<'CPP' #pragma once namespace spdlog { namespace sinks { class basic_file_sink_mt {}; }} // namespace spdlog::sinks CPP cat > "$BUILD_DIR/spdlog/sinks/rotating_file_sink.h" <<'CPP' #pragma once namespace spdlog { namespace sinks { class rotating_file_sink_mt {}; }} // namespace spdlog::sinks CPP cat > "$BUILD_DIR/spdlog/fmt/fmt.h" <<'CPP' #pragma once #include namespace fmt { inline const std::string& runtime(const std::string& value) { return value; } template std::string format(const std::string& fmt_str, Args&&...) { return fmt_str; } } // namespace fmt CPP INCLUDES=( -I"$BUILD_DIR" -I"$ROOT_DIR/app/include" ) LIBS=( -lsqlite3 -pthread ) g++ -std=c++20 -fPIC "${INCLUDES[@]}" \ "$TEST_SRC" "$STUB_SRC" \ "$ROOT_DIR/app/lib/DatabaseManager.cpp" \ -o "$OUTPUT" "${LIBS[@]}" "$OUTPUT" ================================================ FILE: tests/run_translation_tests.sh ================================================ #!/usr/bin/env bash set -euo pipefail ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" BUILD_DIR="$ROOT_DIR/tests/build" mkdir -p "$BUILD_DIR" mkdir -p "$BUILD_DIR/i18n" if rg -n '/dev/null; then echo "Unfinished translations remain in app/resources/i18n" >&2 rg -n '&2 exit 1 fi SRC="$BUILD_DIR/translation_manager_test.cpp" cat > "$SRC" <<'CPP' #include "TranslationManager.hpp" #include #include #include int main(int argc, char** argv) { QApplication app(argc, argv); TranslationManager::instance().initialize(qApp); TranslationManager::instance().set_language(Language::French); const QString french = QCoreApplication::translate("UiTranslator", "Analyze folder"); if (french != QStringLiteral("Analyser le dossier")) { std::cerr << "Expected French translation, got: " << french.toStdString() << "\n"; return 1; } TranslationManager::instance().set_language(Language::English); const QString english = QCoreApplication::translate("UiTranslator", "Analyze folder"); if (english != QStringLiteral("Analyze folder")) { std::cerr << "Expected English fallback, got: " << english.toStdString() << "\n"; return 2; } std::cout << "Translation manager test passed" << std::endl; return 0; } CPP OUTPUT="$BUILD_DIR/translation_manager_test" find_qt6_path_tool() { local tool_name="$1" local fallback_path="$2" if command -v "$tool_name" >/dev/null 2>&1; then command -v "$tool_name" return 0 fi if [[ -x "$fallback_path" ]]; then printf '%s\n' "$fallback_path" return 0 fi return 1 } find_qt6_lrelease() { local candidate qt_host_dir for candidate in lrelease6 lrelease-qt6; do if command -v "$candidate" >/dev/null 2>&1; then command -v "$candidate" return 0 fi done if [[ -n "${QTPATHS6:-}" ]]; then while IFS= read -r qt_host_dir; do if [[ -n "$qt_host_dir" && -x "$qt_host_dir/lrelease" ]]; then printf '%s\n' "$qt_host_dir/lrelease" return 0 fi done < <( "$QTPATHS6" --query QT_HOST_LIBEXECS 2>/dev/null || true "$QTPATHS6" --query QT_HOST_BINS 2>/dev/null || true ) fi if [[ -n "${QMAKE6:-}" ]]; then while IFS= read -r qt_host_dir; do if [[ -n "$qt_host_dir" && -x "$qt_host_dir/lrelease" ]]; then printf '%s\n' "$qt_host_dir/lrelease" return 0 fi done < <( "$QMAKE6" -query QT_HOST_LIBEXECS 2>/dev/null || true "$QMAKE6" -query QT_HOST_BINS 2>/dev/null || true "$QMAKE6" -query QT_INSTALL_BINS 2>/dev/null || true ) fi for candidate in \ /usr/lib/qt6/libexec/lrelease \ /usr/lib/qt6/bin/lrelease \ /opt/homebrew/bin/lrelease \ /opt/homebrew/opt/qt/share/qt/libexec/lrelease \ /opt/homebrew/opt/qtbase/share/qt/libexec/lrelease \ /usr/local/opt/qtbase/share/qt/libexec/lrelease; do if [[ -x "$candidate" ]]; then printf '%s\n' "$candidate" return 0 fi done if command -v lrelease >/dev/null 2>&1; then candidate="$(command -v lrelease)" if "$candidate" -version 2>&1 | grep -Eq 'Qt[^0-9]*6|version 6'; then printf '%s\n' "$candidate" return 0 fi fi return 1 } QMAKE6="$(find_qt6_path_tool qmake6 /usr/lib/qt6/bin/qmake6 || true)" QTPATHS6="$(find_qt6_path_tool qtpaths6 /usr/lib/qt6/bin/qtpaths6 || true)" pkg_includes="$(pkg-config --cflags Qt6Core Qt6Gui Qt6Widgets 2>/dev/null || true)" pkg_libs="$(pkg-config --libs Qt6Core Qt6Gui Qt6Widgets 2>/dev/null || true)" if [[ -n "$pkg_includes" && -n "$pkg_libs" ]]; then QT_FLAGS="$pkg_includes -I$ROOT_DIR/app/include" QT_LIB_FLAGS="$pkg_libs" else qt_headers="" qt_libs="" if [[ -n "$QMAKE6" ]]; then qt_headers="$("$QMAKE6" -query QT_INSTALL_HEADERS 2>/dev/null || true)" qt_libs="$("$QMAKE6" -query QT_INSTALL_LIBS 2>/dev/null || true)" elif command -v qmake >/dev/null 2>&1; then qt_headers="$(qmake -query QT_INSTALL_HEADERS 2>/dev/null || true)" qt_libs="$(qmake -query QT_INSTALL_LIBS 2>/dev/null || true)" elif [[ -n "$QTPATHS6" ]]; then prefix="$("$QTPATHS6" --install-prefix 2>/dev/null || true)" if [[ -n "$prefix" ]]; then qt_headers="$prefix/include" qt_libs="$prefix/lib" fi elif command -v brew >/dev/null 2>&1; then prefix="$(brew --prefix qt 2>/dev/null || brew --prefix qt6 2>/dev/null || true)" if [[ -n "$prefix" ]]; then qt_headers="$prefix/include" qt_libs="$prefix/lib" fi fi if [[ -n "$qt_headers" ]]; then QT_FLAGS="-I$ROOT_DIR/app/include -I$qt_headers -I$qt_headers/QtCore -I$qt_headers/QtGui -I$qt_headers/QtWidgets" if [[ -n "$qt_libs" ]]; then for fw in QtCore QtGui QtWidgets; do fw_headers="$qt_libs/$fw.framework/Headers" if [[ -d "$fw_headers" ]]; then QT_FLAGS="$QT_FLAGS -I$fw_headers" fi done fi else QT_FLAGS="-I$ROOT_DIR/app/include -I/usr/include/x86_64-linux-gnu/qt6 -I/usr/include/x86_64-linux-gnu/qt6/QtCore -I/usr/include/x86_64-linux-gnu/qt6/QtGui -I/usr/include/x86_64-linux-gnu/qt6/QtWidgets -I/opt/homebrew/include -I/opt/homebrew/include/QtCore -I/opt/homebrew/include/QtGui -I/opt/homebrew/include/QtWidgets" fi if [[ -n "$qt_libs" ]]; then if [[ -d "$qt_libs/QtCore.framework" ]]; then QT_LIB_FLAGS="-F$qt_libs -framework QtCore -framework QtGui -framework QtWidgets" else QT_LIB_FLAGS="-L$qt_libs -lQt6Core -lQt6Gui -lQt6Widgets" fi else QT_LIB_FLAGS="-L/opt/homebrew/lib -lQt6Core -lQt6Gui -lQt6Widgets" fi fi LRELEASE="$(find_qt6_lrelease || true)" if [[ -z "$LRELEASE" ]]; then echo "Could not find a Qt 6 lrelease binary. Install qt6-l10n-tools or set LRELEASE=/path/to/qt6/lrelease" >&2 exit 1 fi "$LRELEASE" "$ROOT_DIR/app/resources/i18n/aifilesorter_fr.ts" -qm "$BUILD_DIR/i18n/aifilesorter_fr.qm" # shellcheck disable=SC2086 g++ -std=c++20 -fPIC $QT_FLAGS "$SRC" "$ROOT_DIR/app/lib/TranslationManager.cpp" -o "$OUTPUT" $QT_LIB_FLAGS QT_QPA_PLATFORM=offscreen "$OUTPUT" ================================================ FILE: tests/unit/TestHelpers.hpp ================================================ /** * @file TestHelpers.hpp * @brief Common utilities for unit tests (temp paths, env guards, Qt context). */ #pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include "TranslationManager.hpp" #include "Language.hpp" /** * @brief Build a unique token string with the given prefix. * @param prefix Prefix to include in the token. * @return Unique token string that is safe for filenames. */ inline std::string make_unique_token(std::string_view prefix) { static std::atomic counter{0}; const uint64_t value = counter.fetch_add(1, std::memory_order_relaxed); const auto now = std::chrono::high_resolution_clock::now().time_since_epoch().count(); return std::string(prefix) + std::to_string(now) + "-" + std::to_string(value); } /** * @brief RAII helper that sets and restores environment variables. */ class EnvVarGuard { public: /** * @brief Set or unset an environment variable for the guard lifetime. * @param key Environment variable name. * @param value New value; unset when std::nullopt. */ EnvVarGuard(std::string key, std::optional value) : key_(std::move(key)) { if (const char* existing = std::getenv(key_.c_str())) { original_ = existing; } apply(value); } /** * @brief Restore the original environment variable state. */ ~EnvVarGuard() { apply(original_); } EnvVarGuard(const EnvVarGuard&) = delete; EnvVarGuard& operator=(const EnvVarGuard&) = delete; private: static void set_env(const std::string& key, const std::string& value) { #ifdef _WIN32 _putenv_s(key.c_str(), value.c_str()); #else setenv(key.c_str(), value.c_str(), 1); #endif } static void unset_env(const std::string& key) { #ifdef _WIN32 _putenv_s(key.c_str(), ""); #else unsetenv(key.c_str()); #endif } void apply(const std::optional& value) { if (value.has_value()) { set_env(key_, *value); } else { unset_env(key_); } } std::string key_; std::optional original_; }; /** * @brief Creates a temporary directory and cleans it up on destruction. */ class TempDir { public: /** * @brief Create a unique temporary directory. */ TempDir() : path_(std::filesystem::temp_directory_path() / make_unique_token("aifs-test-")) { std::filesystem::create_directories(path_); } /** * @brief Remove the temporary directory and its contents. */ ~TempDir() { std::error_code ec; std::filesystem::remove_all(path_, ec); } TempDir(const TempDir&) = delete; TempDir& operator=(const TempDir&) = delete; /** * @brief Return the temporary directory path. * @return Reference to the directory path. */ const std::filesystem::path& path() const { return path_; } private: std::filesystem::path path_; }; /** * @brief Creates a temporary GGUF-like file for model-related tests. */ class TempModelFile { public: /** * @brief Create a temporary model file with minimal GGUF metadata. * @param block_count GGUF block count to encode. * @param file_size Total file size in bytes. */ explicit TempModelFile(std::uint32_t block_count = 32, std::size_t file_size = 4 * 1024 * 1024) { if (file_size < 32) { file_size = 32; } path_ = std::filesystem::temp_directory_path() / (make_unique_token("aifs-model-") + ".gguf"); std::vector buffer(file_size, 0); const std::string key = "llama.block_count"; const std::uint64_t len = static_cast(key.size()); const std::uint32_t type = 4; // GGUF_TYPE_UINT32 const std::uint32_t value = block_count; const std::size_t required = sizeof(len) + key.size() + sizeof(type) + sizeof(value); if (buffer.size() < required) { buffer.resize(required); } std::size_t offset = 0; std::memcpy(&buffer[offset], &len, sizeof(len)); offset += sizeof(len); std::memcpy(&buffer[offset], key.data(), key.size()); offset += key.size(); std::memcpy(&buffer[offset], &type, sizeof(type)); offset += sizeof(type); std::memcpy(&buffer[offset], &value, sizeof(value)); std::ofstream out(path_, std::ios::binary); out.write(buffer.data(), static_cast(buffer.size())); out.close(); } /** * @brief Remove the temporary model file. */ ~TempModelFile() { std::error_code ec; std::filesystem::remove(path_, ec); } /** * @brief Return the temporary model file path. * @return Reference to the file path. */ const std::filesystem::path& path() const { return path_; } private: std::filesystem::path path_; }; /** * @brief Ensures a QApplication and translation manager are initialized. */ class QtAppContext { public: /** * @brief Initialize QApplication (if needed) and load translations. */ QtAppContext() { if (!QApplication::instance()) { static int argc = 1; static char arg0[] = "tests"; static char* argv[] = {arg0, nullptr}; static QApplication* app = new QApplication(argc, argv); Q_UNUSED(app); } TranslationManager::instance().initialize(qApp); TranslationManager::instance().set_language(Language::English); } }; ================================================ FILE: tests/unit/test_cache_interactions.cpp ================================================ #include #include "CategorizationService.hpp" #include "DatabaseManager.hpp" #include "FileScanner.hpp" #include "ILLMClient.hpp" #include "ResultsCoordinator.hpp" #include "Settings.hpp" #include "TestHelpers.hpp" #include #include #include #include #include #include #include namespace { void write_file(const std::filesystem::path& path) { std::filesystem::create_directories(path.parent_path()); std::ofstream out(path); out << "data"; } class CountingLLM : public ILLMClient { public: CountingLLM(std::shared_ptr calls, std::string response) : calls_(std::move(calls)), response_(std::move(response)) {} std::string categorize_file(const std::string&, const std::string&, FileType, const std::string&) override { ++(*calls_); return response_; } std::string complete_prompt(const std::string&, int) override { return std::string(); } void set_prompt_logging_enabled(bool) override { } private: std::shared_ptr calls_; std::string response_; }; } // namespace TEST_CASE("CategorizationService uses cached categorization without calling LLM") { TempDir config_dir; EnvVarGuard config_guard("AI_FILE_SORTER_CONFIG_DIR", config_dir.path().string()); Settings settings; DatabaseManager db(settings.get_config_dir()); TempDir data_dir; const std::string dir_path = data_dir.path().string(); const std::string file_name = "cached.png"; const auto resolved = db.resolve_category("Images", "Photos"); REQUIRE(resolved.taxonomy_id > 0); REQUIRE(db.insert_or_update_file_with_categorization( file_name, "F", dir_path, resolved, false, std::string(), false)); CategorizationService service(settings, db, nullptr); std::atomic stop_flag{false}; auto calls = std::make_shared(0); auto factory = [calls]() { return std::make_unique(calls, "Documents : Reports"); }; const auto full_path = (data_dir.path() / file_name).string(); const std::vector files = {FileEntry{full_path, file_name, FileType::File}}; const auto categorized = service.categorize_entries( files, true, stop_flag, {}, {}, {}, {}, factory); REQUIRE(categorized.size() == 1); CHECK(categorized.front().category == "Images"); CHECK(categorized.front().subcategory == "Photos"); CHECK(*calls == 0); } TEST_CASE("CategorizationService falls back to LLM when cache is empty") { TempDir config_dir; EnvVarGuard config_guard("AI_FILE_SORTER_CONFIG_DIR", config_dir.path().string()); Settings settings; DatabaseManager db(settings.get_config_dir()); TempDir data_dir; const std::string dir_path = data_dir.path().string(); const std::string file_name = "uncached.txt"; DatabaseManager::ResolvedCategory empty{0, "", ""}; REQUIRE(db.insert_or_update_file_with_categorization( file_name, "F", dir_path, empty, false, std::string(), false)); CategorizationService service(settings, db, nullptr); std::atomic stop_flag{false}; auto calls = std::make_shared(0); auto factory = [calls]() { return std::make_unique(calls, "Images : Photos"); }; const auto full_path = (data_dir.path() / file_name).string(); const std::vector files = {FileEntry{full_path, file_name, FileType::File}}; const auto categorized = service.categorize_entries( files, true, stop_flag, {}, {}, {}, {}, factory); REQUIRE(categorized.size() == 1); CHECK(categorized.front().category == "Images"); CHECK(categorized.front().subcategory == "Photos"); CHECK(*calls == 1); const auto cached = db.get_categorization_from_db(dir_path, file_name, FileType::File); REQUIRE(cached.size() == 2); CHECK(cached[0] == "Images"); CHECK(cached[1] == "Photos"); } TEST_CASE("CategorizationService invokes completion callback per entry") { TempDir config_dir; EnvVarGuard config_guard("AI_FILE_SORTER_CONFIG_DIR", config_dir.path().string()); Settings settings; DatabaseManager db(settings.get_config_dir()); CategorizationService service(settings, db, nullptr); TempDir data_dir; const auto first_path = (data_dir.path() / "first.txt").string(); const auto second_path = (data_dir.path() / "second.txt").string(); const std::vector files = { FileEntry{first_path, "first.txt", FileType::File}, FileEntry{second_path, "second.txt", FileType::File} }; std::atomic stop_flag{false}; auto calls = std::make_shared(0); auto factory = [calls]() { return std::make_unique(calls, "Documents : Reports"); }; std::size_t queued_count = 0; std::size_t completed_count = 0; const auto categorized = service.categorize_entries( files, true, stop_flag, {}, [&queued_count](const FileEntry&) { ++queued_count; }, [&completed_count](const FileEntry&) { ++completed_count; }, {}, factory); REQUIRE(categorized.size() == files.size()); CHECK(queued_count == files.size()); CHECK(completed_count == files.size()); CHECK(*calls == static_cast(files.size())); } TEST_CASE("CategorizationService loads cached entries recursively for analysis") { TempDir config_dir; EnvVarGuard config_guard("AI_FILE_SORTER_CONFIG_DIR", config_dir.path().string()); Settings settings; DatabaseManager db(settings.get_config_dir()); CategorizationService service(settings, db, nullptr); TempDir data_dir; const std::string root_path = data_dir.path().string(); const std::string child_path = (data_dir.path() / "child").string(); const auto resolved = db.resolve_category("Images", "Photos"); REQUIRE(resolved.taxonomy_id > 0); REQUIRE(db.insert_or_update_file_with_categorization( "root.png", "F", root_path, resolved, false, std::string(), false)); DatabaseManager::ResolvedCategory empty{0, "", ""}; REQUIRE(db.insert_or_update_file_with_categorization( "suggested.png", "F", child_path, empty, false, "rename_me.png", true)); settings.set_include_subdirectories(false); auto cached_root_only = service.load_cached_entries(root_path); REQUIRE(cached_root_only.size() == 1); CHECK(cached_root_only.front().file_name == "root.png"); settings.set_include_subdirectories(true); auto cached_recursive = service.load_cached_entries(root_path); REQUIRE(cached_recursive.size() == 2); const auto it = std::find_if(cached_recursive.begin(), cached_recursive.end(), [](const CategorizedFile& entry) { return entry.file_name == "suggested.png"; }); REQUIRE(it != cached_recursive.end()); CHECK(it->suggested_name == "rename_me.png"); CHECK(it->file_path == child_path); } TEST_CASE("Recursive recategorization clears stale subtree cache entries") { TempDir config_dir; EnvVarGuard config_guard("AI_FILE_SORTER_CONFIG_DIR", config_dir.path().string()); Settings settings; DatabaseManager db(settings.get_config_dir()); CategorizationService service(settings, db, nullptr); TempDir data_dir; const std::string root_path = data_dir.path().string(); const std::string child_path = (data_dir.path() / "child").string(); const auto resolved = db.resolve_category("Documents", "Reports"); REQUIRE(resolved.taxonomy_id > 0); // Simulate a partially re-categorized subtree: the root entry already uses the // new style while a nested entry is still cached with the old style. REQUIRE(db.insert_or_update_file_with_categorization( "root.txt", "F", root_path, resolved, true, std::string(), false)); REQUIRE(db.insert_or_update_file_with_categorization( "child.txt", "F", child_path, resolved, false, std::string(), false)); CHECK(db.has_categorization_style_conflict(root_path, true, true)); REQUIRE(db.clear_directory_categorizations(root_path, true)); settings.set_include_subdirectories(true); CHECK(service.load_cached_entries(root_path).empty()); } TEST_CASE("ResultsCoordinator respects full-path cache keys for recursive scans") { TempDir data_dir; const auto root_file = data_dir.path() / "sample.txt"; const auto nested_file = data_dir.path() / "nested" / "sample.txt"; write_file(root_file); write_file(nested_file); FileScanner scanner; ResultsCoordinator coordinator(scanner); const auto options = FileScanOptions::Files | FileScanOptions::Recursive; std::unordered_set cached_by_name{"sample.txt"}; auto uncached_by_name = coordinator.find_files_to_categorize( data_dir.path().string(), options, cached_by_name, false); CHECK(uncached_by_name.empty()); std::unordered_set cached_by_path{root_file.string()}; auto uncached_by_path = coordinator.find_files_to_categorize( data_dir.path().string(), options, cached_by_path, true); REQUIRE(uncached_by_path.size() == 1); CHECK(uncached_by_path.front().full_path == nested_file.string()); } ================================================ FILE: tests/unit/test_categorization_dialog.cpp ================================================ #include #include "CategorizationDialog.hpp" #include "DatabaseManager.hpp" #include "TestHooks.hpp" #include "TestHelpers.hpp" #include #include #include #include #include #ifndef _WIN32 namespace { struct MoveProbeGuard { ~MoveProbeGuard() { TestHooks::reset_categorization_move_probe(); } }; CategorizedFile sample_file() { CategorizedFile file; file.file_path = "/tmp"; file.file_name = "example.txt"; file.type = FileType::File; file.category = "Docs"; file.subcategory = "Reports"; return file; } } // namespace TEST_CASE("CategorizationDialog uses subcategory toggle when moving files") { EnvVarGuard platform_guard("QT_QPA_PLATFORM", "offscreen"); QtAppContext qt_context; const std::vector files = {sample_file()}; auto verify_toggle = [&](bool initial_state, bool toggled_state) { TempDir undo_dir; CategorizationDialog dialog(nullptr, initial_state, undo_dir.path().string()); dialog.test_set_entries(files); bool probe_called = false; bool recorded_flag = !toggled_state; MoveProbeGuard guard; TestHooks::set_categorization_move_probe( [&](const TestHooks::CategorizationMoveInfo& info) { probe_called = true; recorded_flag = info.show_subcategory_folders; }); dialog.set_show_subcategory_column(toggled_state); dialog.test_trigger_confirm(); REQUIRE(probe_called); CHECK(recorded_flag == toggled_state); }; SECTION("Enabled state honored") { verify_toggle(true, true); } SECTION("Disabling hides subcategory folders") { verify_toggle(true, false); } SECTION("Enabling from disabled state works") { verify_toggle(false, true); } } #ifndef _WIN32 TEST_CASE("CategorizationDialog supports sorting by columns") { EnvVarGuard platform_guard("QT_QPA_PLATFORM", "offscreen"); QtAppContext qt_context; CategorizedFile alpha; alpha.file_path = "/tmp"; alpha.file_name = "b.txt"; alpha.type = FileType::File; alpha.category = "Alpha"; alpha.subcategory = "One"; CategorizedFile beta; beta.file_path = "/tmp"; beta.file_name = "a.txt"; beta.type = FileType::File; beta.category = "Beta"; beta.subcategory = "Two"; TempDir undo_dir; CategorizationDialog dialog(nullptr, true, undo_dir.path().string()); dialog.test_set_entries({alpha, beta}); auto* table = dialog.findChild(); REQUIRE(table != nullptr); auto* model = qobject_cast(table->model()); REQUIRE(model != nullptr); SECTION("Sorts by file name ascending") { table->sortByColumn(1, Qt::AscendingOrder); // file name column REQUIRE(model->item(0, 1)->text() == QStringLiteral("a.txt")); REQUIRE(model->item(1, 1)->text() == QStringLiteral("b.txt")); } SECTION("Sorts by category descending") { table->sortByColumn(4, Qt::DescendingOrder); // category column REQUIRE(model->item(0, 4)->text() == QStringLiteral("Beta")); REQUIRE(model->item(1, 4)->text() == QStringLiteral("Alpha")); } } #endif #ifndef _WIN32 TEST_CASE("CategorizationDialog undo restores moved files") { EnvVarGuard platform_guard("QT_QPA_PLATFORM", "offscreen"); QtAppContext qt_context; TempDir temp_dir; const std::filesystem::path base = temp_dir.path(); const std::string file_name = "alpha.txt"; const std::filesystem::path source = base / file_name; std::ofstream(source).put('x'); CategorizedFile file; file.file_path = base.string(); file.file_name = file_name; file.type = FileType::File; file.category = "Docs"; file.subcategory = "Reports"; TempDir undo_dir_for_dialog; CategorizationDialog dialog(nullptr, true, undo_dir_for_dialog.path().string()); dialog.test_set_entries({file}); REQUIRE_FALSE(dialog.test_undo_enabled()); dialog.test_trigger_confirm(); const std::filesystem::path destination = base / file.category / file.subcategory / file_name; REQUIRE_FALSE(std::filesystem::exists(source)); REQUIRE(std::filesystem::exists(destination)); REQUIRE(dialog.test_undo_enabled()); dialog.test_trigger_undo(); REQUIRE(std::filesystem::exists(source)); REQUIRE_FALSE(std::filesystem::exists(destination)); REQUIRE_FALSE(dialog.test_undo_enabled()); } TEST_CASE("CategorizationDialog undo allows renaming again") { EnvVarGuard platform_guard("QT_QPA_PLATFORM", "offscreen"); QtAppContext qt_context; TempDir temp_dir; const std::filesystem::path base = temp_dir.path(); const std::string file_name = "photo.jpg"; const std::string renamed = "sunset.jpg"; const std::filesystem::path source = base / file_name; const std::filesystem::path destination = base / renamed; std::ofstream(source).put('x'); CategorizedFile file; file.file_path = base.string(); file.file_name = file_name; file.type = FileType::File; file.rename_only = true; file.suggested_name = renamed; TempDir undo_dir_for_dialog; CategorizationDialog dialog(nullptr, true, undo_dir_for_dialog.path().string()); dialog.test_set_entries({file}); dialog.test_trigger_confirm(); REQUIRE_FALSE(std::filesystem::exists(source)); REQUIRE(std::filesystem::exists(destination)); dialog.test_trigger_undo(); REQUIRE(std::filesystem::exists(source)); REQUIRE_FALSE(std::filesystem::exists(destination)); dialog.test_trigger_confirm(); REQUIRE_FALSE(std::filesystem::exists(source)); REQUIRE(std::filesystem::exists(destination)); } TEST_CASE("CategorizationDialog rename-only updates cached filename") { EnvVarGuard platform_guard("QT_QPA_PLATFORM", "offscreen"); QtAppContext qt_context; TempDir config_dir; EnvVarGuard config_guard("AI_FILE_SORTER_CONFIG_DIR", config_dir.path().string()); DatabaseManager db(config_dir.path().string()); TempDir temp_dir; const std::filesystem::path base = temp_dir.path(); const std::string file_name = "photo.jpg"; const std::string renamed = "sunset.jpg"; const std::filesystem::path source = base / file_name; const std::filesystem::path destination = base / renamed; std::ofstream(source).put('x'); CategorizedFile file; file.file_path = base.string(); file.file_name = file_name; file.type = FileType::File; file.rename_only = true; file.suggested_name = renamed; TempDir undo_dir_for_dialog; CategorizationDialog dialog(&db, true, undo_dir_for_dialog.path().string()); dialog.test_set_entries({file}); dialog.test_trigger_confirm(); REQUIRE_FALSE(std::filesystem::exists(source)); REQUIRE(std::filesystem::exists(destination)); const auto old_cache = db.get_categorization_from_db(base.string(), file_name, FileType::File); REQUIRE(old_cache.empty()); const auto cached = db.get_categorized_files(base.string()); REQUIRE(cached.size() == 1); CHECK(cached.front().file_name == renamed); CHECK(cached.front().rename_only); CHECK(cached.front().suggested_name == renamed); } TEST_CASE("CategorizationDialog allows editing when rename-only checkbox is off") { EnvVarGuard platform_guard("QT_QPA_PLATFORM", "offscreen"); QtAppContext qt_context; CategorizedFile rename_only_entry; rename_only_entry.file_path = "/tmp"; rename_only_entry.file_name = "a.png"; rename_only_entry.type = FileType::File; rename_only_entry.rename_only = true; rename_only_entry.suggested_name = "example.png"; CategorizedFile categorized_entry; categorized_entry.file_path = "/tmp"; categorized_entry.file_name = "b.png"; categorized_entry.type = FileType::File; categorized_entry.category = "Images"; categorized_entry.subcategory = "Screens"; TempDir undo_dir_for_dialog; CategorizationDialog dialog(nullptr, false, undo_dir_for_dialog.path().string()); dialog.test_set_entries({rename_only_entry, categorized_entry}); auto* table = dialog.findChild(); REQUIRE(table != nullptr); auto* model = qobject_cast(table->model()); REQUIRE(model != nullptr); CHECK(model->item(0, 4)->isEditable()); CHECK(model->item(1, 4)->isEditable()); } TEST_CASE("CategorizationDialog deduplicates suggested names when rename-only is toggled") { EnvVarGuard platform_guard("QT_QPA_PLATFORM", "offscreen"); QtAppContext qt_context; CategorizedFile first; first.file_path = "/tmp"; first.file_name = "a.png"; first.type = FileType::File; first.category = "Images"; first.subcategory = "Screens"; first.suggested_name = "computer_screen_youtube.png"; CategorizedFile second = first; second.file_name = "b.png"; second.category = "Media"; TempDir undo_dir_for_dialog; CategorizationDialog dialog(nullptr, true, undo_dir_for_dialog.path().string()); dialog.test_set_entries({first, second}); QCheckBox* rename_checkbox = nullptr; const auto checkboxes = dialog.findChildren(); for (auto* checkbox : checkboxes) { if (checkbox && checkbox->text() == QStringLiteral("Do not categorize picture files (only rename)")) { rename_checkbox = checkbox; break; } } REQUIRE(rename_checkbox != nullptr); rename_checkbox->setChecked(true); auto* table = dialog.findChild(); REQUIRE(table != nullptr); auto* model = qobject_cast(table->model()); REQUIRE(model != nullptr); const QString first_suggestion = model->item(0, 3)->text(); const QString second_suggestion = model->item(1, 3)->text(); CHECK(first_suggestion == QStringLiteral("computer_screen_youtube_1.png")); CHECK(second_suggestion == QStringLiteral("computer_screen_youtube_2.png")); } TEST_CASE("CategorizationDialog avoids double suffixes for numbered suggestions") { EnvVarGuard platform_guard("QT_QPA_PLATFORM", "offscreen"); QtAppContext qt_context; CategorizedFile first; first.file_path = "/tmp"; first.file_name = "a.png"; first.type = FileType::File; first.rename_only = true; first.suggested_name = "computer_screen_youtube_1.png"; CategorizedFile second = first; second.file_name = "b.png"; TempDir undo_dir_for_dialog; CategorizationDialog dialog(nullptr, false, undo_dir_for_dialog.path().string()); dialog.test_set_entries({first, second}); auto* table = dialog.findChild(); REQUIRE(table != nullptr); auto* model = qobject_cast(table->model()); REQUIRE(model != nullptr); const QString first_suggestion = model->item(0, 3)->text(); const QString second_suggestion = model->item(1, 3)->text(); CHECK(first_suggestion == QStringLiteral("computer_screen_youtube_1.png")); CHECK(second_suggestion == QStringLiteral("computer_screen_youtube_2.png")); } TEST_CASE("CategorizationDialog hides suggested names for renamed entries") { EnvVarGuard platform_guard("QT_QPA_PLATFORM", "offscreen"); QtAppContext qt_context; CategorizedFile entry; entry.file_path = "/tmp"; entry.file_name = "already_renamed.png"; entry.type = FileType::File; entry.suggested_name = "new_name.png"; entry.rename_applied = true; TempDir undo_dir_for_dialog; CategorizationDialog dialog(nullptr, false, undo_dir_for_dialog.path().string()); dialog.test_set_entries({entry}); auto* table = dialog.findChild(); REQUIRE(table != nullptr); auto* model = qobject_cast(table->model()); REQUIRE(model != nullptr); CHECK(model->item(0, 3)->text().isEmpty()); CHECK_FALSE(model->item(0, 3)->isEditable()); } TEST_CASE("CategorizationDialog hides already renamed rows when rename-only is on") { EnvVarGuard platform_guard("QT_QPA_PLATFORM", "offscreen"); QtAppContext qt_context; CategorizedFile renamed; renamed.file_path = "/tmp"; renamed.file_name = "renamed.png"; renamed.type = FileType::File; renamed.category = "Images"; renamed.subcategory = "Screens"; renamed.rename_applied = true; CategorizedFile pending; pending.file_path = "/tmp"; pending.file_name = "pending.png"; pending.type = FileType::File; pending.category = "Images"; pending.subcategory = "Screens"; pending.suggested_name = "pending_new.png"; TempDir undo_dir_for_dialog; CategorizationDialog dialog(nullptr, true, undo_dir_for_dialog.path().string()); dialog.test_set_entries({renamed, pending}); auto* table = dialog.findChild(); REQUIRE(table != nullptr); auto* model = qobject_cast(table->model()); REQUIRE(model != nullptr); auto find_row = [&](const QString& name) -> int { for (int row = 0; row < model->rowCount(); ++row) { if (model->item(row, 1)->text() == name) { return row; } } return -1; }; const int renamed_row = find_row(QStringLiteral("renamed.png")); const int pending_row = find_row(QStringLiteral("pending.png")); REQUIRE(renamed_row >= 0); REQUIRE(pending_row >= 0); CHECK_FALSE(table->isRowHidden(renamed_row)); CHECK_FALSE(table->isRowHidden(pending_row)); QCheckBox* rename_checkbox = nullptr; const auto checkboxes = dialog.findChildren(); for (auto* checkbox : checkboxes) { if (checkbox && checkbox->text() == QStringLiteral("Do not categorize picture files (only rename)")) { rename_checkbox = checkbox; break; } } REQUIRE(rename_checkbox != nullptr); rename_checkbox->setChecked(true); CHECK(table->isRowHidden(renamed_row)); } TEST_CASE("CategorizationDialog deduplicates suggested picture filenames") { EnvVarGuard platform_guard("QT_QPA_PLATFORM", "offscreen"); QtAppContext qt_context; TempDir temp_dir; const std::filesystem::path base = temp_dir.path(); CategorizedFile first; first.file_path = base.string(); first.file_name = "a.png"; first.type = FileType::File; first.suggested_name = "sunny_barbeque_dinner.png"; first.rename_only = true; CategorizedFile second = first; second.file_name = "b.png"; TempDir undo_dir_for_dialog; CategorizationDialog dialog(nullptr, false, undo_dir_for_dialog.path().string()); dialog.test_set_entries({first, second}); auto* table = dialog.findChild(); REQUIRE(table != nullptr); auto* model = qobject_cast(table->model()); REQUIRE(model != nullptr); const QString first_suggestion = model->item(0, 3)->text(); const QString second_suggestion = model->item(1, 3)->text(); CHECK(first_suggestion == QStringLiteral("sunny_barbeque_dinner_1.png")); CHECK(second_suggestion == QStringLiteral("sunny_barbeque_dinner_2.png")); } TEST_CASE("CategorizationDialog avoids existing picture filename collisions") { EnvVarGuard platform_guard("QT_QPA_PLATFORM", "offscreen"); QtAppContext qt_context; TempDir temp_dir; const std::filesystem::path base = temp_dir.path(); const std::string existing_name = "sunny_barbeque_dinner.png"; std::ofstream(base / existing_name).put('x'); CategorizedFile entry; entry.file_path = base.string(); entry.file_name = "c.png"; entry.type = FileType::File; entry.suggested_name = existing_name; entry.rename_only = true; TempDir undo_dir_for_dialog; CategorizationDialog dialog(nullptr, false, undo_dir_for_dialog.path().string()); dialog.test_set_entries({entry}); auto* table = dialog.findChild(); REQUIRE(table != nullptr); auto* model = qobject_cast(table->model()); REQUIRE(model != nullptr); const QString suggestion = model->item(0, 3)->text(); CHECK(suggestion == QStringLiteral("sunny_barbeque_dinner_1.png")); } TEST_CASE("CategorizationDialog rename-only preserves cached categories without renaming") { EnvVarGuard platform_guard("QT_QPA_PLATFORM", "offscreen"); QtAppContext qt_context; TempDir config_dir; EnvVarGuard config_guard("AI_FILE_SORTER_CONFIG_DIR", config_dir.path().string()); DatabaseManager db(config_dir.path().string()); TempDir temp_dir; const std::filesystem::path base = temp_dir.path(); const std::string file_name = "photo.jpg"; std::ofstream(base / file_name).put('x'); auto resolved = db.resolve_category("Images", "Screens"); REQUIRE(db.insert_or_update_file_with_categorization( file_name, "F", base.string(), resolved, false, std::string(), false)); CategorizedFile file; file.file_path = base.string(); file.file_name = file_name; file.type = FileType::File; file.rename_only = true; TempDir undo_dir_for_dialog; CategorizationDialog dialog(&db, true, undo_dir_for_dialog.path().string()); dialog.test_set_entries({file}); dialog.test_trigger_confirm(); const auto cached = db.get_categorized_file(base.string(), file_name, FileType::File); REQUIRE(cached.has_value()); CHECK(cached->category == resolved.category); CHECK(cached->subcategory == resolved.subcategory); CHECK(cached->rename_only); } TEST_CASE("CategorizationDialog rename-only preserves cached categories when renaming") { EnvVarGuard platform_guard("QT_QPA_PLATFORM", "offscreen"); QtAppContext qt_context; TempDir config_dir; EnvVarGuard config_guard("AI_FILE_SORTER_CONFIG_DIR", config_dir.path().string()); DatabaseManager db(config_dir.path().string()); TempDir temp_dir; const std::filesystem::path base = temp_dir.path(); const std::string file_name = "photo.jpg"; const std::string renamed = "sunset.jpg"; const std::filesystem::path source = base / file_name; const std::filesystem::path destination = base / renamed; std::ofstream(source).put('x'); auto resolved = db.resolve_category("Images", "Screens"); REQUIRE(db.insert_or_update_file_with_categorization( file_name, "F", base.string(), resolved, false, std::string(), false)); CategorizedFile file; file.file_path = base.string(); file.file_name = file_name; file.type = FileType::File; file.rename_only = true; file.suggested_name = renamed; TempDir undo_dir_for_dialog; CategorizationDialog dialog(&db, true, undo_dir_for_dialog.path().string()); dialog.test_set_entries({file}); dialog.test_trigger_confirm(); REQUIRE_FALSE(std::filesystem::exists(source)); REQUIRE(std::filesystem::exists(destination)); const auto cached = db.get_categorized_file(base.string(), renamed, FileType::File); REQUIRE(cached.has_value()); CHECK(cached->category == resolved.category); CHECK(cached->subcategory == resolved.subcategory); CHECK(cached->rename_only); } #endif #endif // !_WIN32 ================================================ FILE: tests/unit/test_checkbox_matrix.cpp ================================================ #include #include "DocumentTextAnalyzer.hpp" #include "LlavaImageAnalyzer.hpp" #include "MainAppTestAccess.hpp" #include "Types.hpp" #include #include #include #include #include #include #include namespace { struct Combo { bool analyze_images; bool analyze_documents; bool process_images_only; bool process_documents_only; bool rename_images_only; bool rename_documents_only; bool categorize_files; }; enum class Bucket { None, Image, Document, Other }; std::string combo_label(const Combo& combo) { std::ostringstream out; out << "AI=" << combo.analyze_images << " AD=" << combo.analyze_documents << " PI=" << combo.process_images_only << " PD=" << combo.process_documents_only << " RI=" << combo.rename_images_only << " RD=" << combo.rename_documents_only << " CF=" << combo.categorize_files; return out.str(); } bool contains_name(const std::vector& entries, const std::string& name) { return std::any_of(entries.begin(), entries.end(), [&name](const FileEntry& entry) { return entry.file_name == name; }); } Bucket expected_bucket(const FileEntry& entry, const Combo& combo, const std::unordered_set& renamed_files) { const bool restrict_types = combo.process_images_only || combo.process_documents_only; const bool allow_images = !restrict_types || combo.process_images_only; const bool allow_documents = !restrict_types || combo.process_documents_only; const bool allow_other_files = combo.categorize_files && !restrict_types; if (entry.type == FileType::Directory) { return restrict_types ? Bucket::None : Bucket::Other; } const bool is_image = LlavaImageAnalyzer::is_supported_image(entry.full_path); const bool is_document = DocumentTextAnalyzer::is_supported_document(entry.full_path); if (is_image) { if (!allow_images) { return Bucket::None; } if (combo.analyze_images) { const bool already_renamed = renamed_files.contains(entry.file_name); if (already_renamed) { return combo.rename_images_only ? Bucket::None : Bucket::Other; } return Bucket::Image; } return allow_other_files ? Bucket::Other : Bucket::None; } if (is_document) { if (!allow_documents) { return Bucket::None; } if (combo.analyze_documents) { const bool already_renamed = renamed_files.contains(entry.file_name); if (already_renamed) { return combo.rename_documents_only ? Bucket::None : Bucket::Other; } return Bucket::Document; } return allow_other_files ? Bucket::Other : Bucket::None; } return allow_other_files ? Bucket::Other : Bucket::None; } Bucket actual_bucket(const FileEntry& entry, const std::vector& image_entries, const std::vector& document_entries, const std::vector& other_entries) { const bool in_images = contains_name(image_entries, entry.file_name); const bool in_docs = contains_name(document_entries, entry.file_name); const bool in_other = contains_name(other_entries, entry.file_name); const int count = static_cast(in_images) + static_cast(in_docs) + static_cast(in_other); CHECK(count <= 1); if (in_images) { return Bucket::Image; } if (in_docs) { return Bucket::Document; } if (in_other) { return Bucket::Other; } return Bucket::None; } void run_combo_matrix(const std::vector& files, const std::unordered_set& renamed_files, bool renamed_label) { for (int mask = 0; mask < 128; ++mask) { Combo combo{ static_cast(mask & (1 << 0)), static_cast(mask & (1 << 1)), static_cast(mask & (1 << 2)), static_cast(mask & (1 << 3)), static_cast(mask & (1 << 4)), static_cast(mask & (1 << 5)), static_cast(mask & (1 << 6)) }; std::vector image_entries; std::vector document_entries; std::vector other_entries; MainAppTestAccess::split_entries_for_analysis(files, combo.analyze_images, combo.analyze_documents, combo.process_images_only, combo.process_documents_only, combo.rename_images_only, combo.rename_documents_only, combo.categorize_files, false, renamed_files, image_entries, document_entries, other_entries); std::cout << "[combo] " << combo_label(combo) << " renamed=" << renamed_label << " -> img=" << image_entries.size() << " doc=" << document_entries.size() << " other=" << other_entries.size() << std::endl; INFO(combo_label(combo)); for (const auto& entry : files) { const Bucket expected = expected_bucket(entry, combo, renamed_files); const Bucket actual = actual_bucket(entry, image_entries, document_entries, other_entries); CHECK(expected == actual); } for (const auto& entry : image_entries) { CHECK(LlavaImageAnalyzer::is_supported_image(entry.full_path)); } for (const auto& entry : document_entries) { CHECK(DocumentTextAnalyzer::is_supported_document(entry.full_path)); } } } } // namespace TEST_CASE("Checkbox combinations route entries without renamed files") { const std::vector files = { {"/tmp/photo.png", "photo.png", FileType::File}, {"/tmp/report.pdf", "report.pdf", FileType::File}, {"/tmp/archive.bin", "archive.bin", FileType::File}, {"/tmp/folder", "folder", FileType::Directory} }; std::unordered_set renamed_files; run_combo_matrix(files, renamed_files, false); } TEST_CASE("Checkbox combinations route entries with renamed files") { const std::vector files = { {"/tmp/photo.png", "photo.png", FileType::File}, {"/tmp/report.pdf", "report.pdf", FileType::File}, {"/tmp/archive.bin", "archive.bin", FileType::File}, {"/tmp/folder", "folder", FileType::Directory} }; std::unordered_set renamed_files = {"photo.png", "report.pdf"}; run_combo_matrix(files, renamed_files, true); } ================================================ FILE: tests/unit/test_cli_reporter.cpp ================================================ #include #include #include #include class TestNamePrinter : public Catch::EventListenerBase { public: using Catch::EventListenerBase::EventListenerBase; void testCaseStarting(Catch::TestCaseInfo const& info) override { std::cout << "[TEST] " << info.name << std::endl; } }; CATCH_REGISTER_LISTENER(TestNamePrinter) ================================================ FILE: tests/unit/test_custom_api_endpoint.cpp ================================================ #include #include "Settings.hpp" #include "TestHelpers.hpp" TEST_CASE("Custom API endpoints persist across Settings load/save") { TempDir config_dir; EnvVarGuard config_guard("AI_FILE_SORTER_CONFIG_DIR", config_dir.path().string()); Settings settings; settings.load(); CustomApiEndpoint endpoint; endpoint.name = "Local LM Studio"; endpoint.description = "Local OpenAI-compatible endpoint"; endpoint.base_url = "http://localhost:1234/v1"; endpoint.api_key = "local-key"; endpoint.model = "llama-3.1"; const std::string id = settings.upsert_custom_api_endpoint(endpoint); REQUIRE_FALSE(id.empty()); settings.set_active_custom_api_id(id); REQUIRE(settings.save()); Settings reloaded; reloaded.load(); const CustomApiEndpoint loaded = reloaded.find_custom_api_endpoint(id); REQUIRE(loaded.id == id); REQUIRE(loaded.name == endpoint.name); REQUIRE(loaded.description == endpoint.description); REQUIRE(loaded.base_url == endpoint.base_url); REQUIRE(loaded.api_key == endpoint.api_key); REQUIRE(loaded.model == endpoint.model); REQUIRE(reloaded.get_active_custom_api_id() == id); } ================================================ FILE: tests/unit/test_custom_llm.cpp ================================================ #include #include "Settings.hpp" #include "TestHelpers.hpp" TEST_CASE("Custom LLM entries persist across Settings load/save") { TempDir config_dir; EnvVarGuard config_guard("AI_FILE_SORTER_CONFIG_DIR", config_dir.path().string()); Settings settings; settings.load(); CustomLLM llm; llm.name = "My Local Model"; llm.path = "/models/custom.gguf"; const std::string id = settings.upsert_custom_llm(llm); REQUIRE_FALSE(id.empty()); settings.set_active_custom_llm_id(id); REQUIRE(settings.save()); Settings reloaded; reloaded.load(); const CustomLLM loaded = reloaded.find_custom_llm(id); REQUIRE(loaded.id == id); REQUIRE(loaded.name == llm.name); REQUIRE(loaded.path == llm.path); REQUIRE(reloaded.get_active_custom_llm_id() == id); } ================================================ FILE: tests/unit/test_database_manager_rename_only.cpp ================================================ #include #include "DatabaseManager.hpp" #include "TestHelpers.hpp" TEST_CASE("DatabaseManager keeps rename-only entries with empty labels") { TempDir base_dir; EnvVarGuard config_guard("AI_FILE_SORTER_CONFIG_DIR", base_dir.path().string()); DatabaseManager db(base_dir.path().string()); const std::string dir_path = "/sample"; DatabaseManager::ResolvedCategory empty{0, "", ""}; const std::string suggested_name = "rename_suggestion.png"; REQUIRE(db.insert_or_update_file_with_categorization( "rename.png", "F", dir_path, empty, false, suggested_name, true)); REQUIRE(db.insert_or_update_file_with_categorization( "empty.png", "F", dir_path, empty, false, std::string(), false)); const auto removed = db.remove_empty_categorizations(dir_path); REQUIRE(removed.size() == 1); CHECK(removed.front().file_name == "empty.png"); const auto entries = db.get_categorized_files(dir_path); REQUIRE(entries.size() == 1); CHECK(entries.front().file_name == "rename.png"); CHECK(entries.front().rename_only); CHECK_FALSE(entries.front().rename_applied); CHECK(entries.front().suggested_name == suggested_name); CHECK(entries.front().category.empty()); CHECK(entries.front().subcategory.empty()); } TEST_CASE("DatabaseManager keeps suggestion-only entries with empty labels") { TempDir base_dir; EnvVarGuard config_guard("AI_FILE_SORTER_CONFIG_DIR", base_dir.path().string()); DatabaseManager db(base_dir.path().string()); const std::string dir_path = "/sample"; DatabaseManager::ResolvedCategory empty{0, "", ""}; const std::string suggested_name = "suggested_name.png"; REQUIRE(db.insert_or_update_file_with_categorization( "suggested.png", "F", dir_path, empty, false, suggested_name, false)); const auto removed = db.remove_empty_categorizations(dir_path); CHECK(removed.empty()); const auto entries = db.get_categorized_files(dir_path); REQUIRE(entries.size() == 1); CHECK(entries.front().file_name == "suggested.png"); CHECK_FALSE(entries.front().rename_only); CHECK(entries.front().suggested_name == suggested_name); CHECK(entries.front().category.empty()); CHECK(entries.front().subcategory.empty()); } TEST_CASE("DatabaseManager sanitizes invalid UTF-8 in cached labels") { TempDir base_dir; EnvVarGuard config_guard("AI_FILE_SORTER_CONFIG_DIR", base_dir.path().string()); DatabaseManager db(base_dir.path().string()); const std::string dir_path = "/sample"; std::string invalid_category = "Imag"; invalid_category.push_back(static_cast(0xFF)); invalid_category += "es"; std::string invalid_subcategory = "Phot"; invalid_subcategory.push_back(static_cast(0xFF)); invalid_subcategory += "os"; std::string invalid_suggested = "sum"; invalid_suggested.push_back(static_cast(0xFF)); invalid_suggested += "mer.png"; DatabaseManager::ResolvedCategory resolved{ 0, invalid_category, invalid_subcategory, }; REQUIRE(db.insert_or_update_file_with_categorization( "photo.png", "F", dir_path, resolved, false, invalid_suggested, false)); const auto entries = db.get_categorized_files(dir_path); REQUIRE(entries.size() == 1); CHECK(entries.front().category == "Images"); CHECK(entries.front().subcategory == "Photos"); CHECK(entries.front().suggested_name == "summer.png"); } TEST_CASE("DatabaseManager normalizes subcategory stopword suffixes for taxonomy matching") { TempDir base_dir; EnvVarGuard config_guard("AI_FILE_SORTER_CONFIG_DIR", base_dir.path().string()); DatabaseManager db(base_dir.path().string()); auto base = db.resolve_category("Images", "Graphics"); auto with_suffix = db.resolve_category("Images", "Graphics files"); REQUIRE(base.taxonomy_id > 0); CHECK(with_suffix.taxonomy_id == base.taxonomy_id); CHECK(with_suffix.category == base.category); CHECK(with_suffix.subcategory == base.subcategory); auto photos = db.resolve_category("Images", "Photos"); CHECK(photos.subcategory == "Photos"); } TEST_CASE("DatabaseManager normalizes backup category synonyms for taxonomy matching") { TempDir base_dir; EnvVarGuard config_guard("AI_FILE_SORTER_CONFIG_DIR", base_dir.path().string()); DatabaseManager db(base_dir.path().string()); auto archives = db.resolve_category("Archives", "General"); auto backup = db.resolve_category("backup files", "General"); REQUIRE(archives.taxonomy_id > 0); CHECK(backup.taxonomy_id == archives.taxonomy_id); CHECK(backup.category == archives.category); CHECK(backup.category == "Archives"); CHECK(backup.subcategory == "General"); } TEST_CASE("DatabaseManager normalizes image category synonyms and image media aliases") { TempDir base_dir; EnvVarGuard config_guard("AI_FILE_SORTER_CONFIG_DIR", base_dir.path().string()); DatabaseManager db(base_dir.path().string()); auto images = db.resolve_category("Images", "Photos"); auto graphics = db.resolve_category("Graphics", "Photos"); auto media_images = db.resolve_category("Media", "Photos"); auto media_audio = db.resolve_category("Media", "Audio"); REQUIRE(images.taxonomy_id > 0); CHECK(graphics.taxonomy_id == images.taxonomy_id); CHECK(media_images.taxonomy_id == images.taxonomy_id); CHECK(graphics.category == "Images"); CHECK(media_images.category == "Images"); CHECK(media_audio.category == "Media"); CHECK(media_audio.taxonomy_id != images.taxonomy_id); } TEST_CASE("DatabaseManager normalizes document category synonyms for taxonomy matching") { TempDir base_dir; EnvVarGuard config_guard("AI_FILE_SORTER_CONFIG_DIR", base_dir.path().string()); DatabaseManager db(base_dir.path().string()); auto documents = db.resolve_category("Documents", "Reports"); auto texts = db.resolve_category("Texts", "Reports"); auto papers = db.resolve_category("Papers", "Reports"); auto spreadsheets = db.resolve_category("Spreadsheets", "Reports"); REQUIRE(documents.taxonomy_id > 0); CHECK(texts.taxonomy_id == documents.taxonomy_id); CHECK(papers.taxonomy_id == documents.taxonomy_id); CHECK(spreadsheets.taxonomy_id == documents.taxonomy_id); CHECK(texts.category == "Documents"); CHECK(papers.category == "Documents"); CHECK(spreadsheets.category == "Documents"); } TEST_CASE("DatabaseManager normalizes installer and update category synonyms for taxonomy matching") { TempDir base_dir; EnvVarGuard config_guard("AI_FILE_SORTER_CONFIG_DIR", base_dir.path().string()); DatabaseManager db(base_dir.path().string()); auto software = db.resolve_category("Software", "Installers"); auto installers = db.resolve_category("Installers", "Installers"); auto setup_files = db.resolve_category("Setup files", "Installers"); auto updates = db.resolve_category("Software Update", "Installers"); auto patches = db.resolve_category("Patches", "Installers"); REQUIRE(software.taxonomy_id > 0); CHECK(installers.taxonomy_id == software.taxonomy_id); CHECK(setup_files.taxonomy_id == software.taxonomy_id); CHECK(updates.taxonomy_id == software.taxonomy_id); CHECK(patches.taxonomy_id == software.taxonomy_id); CHECK(installers.category == "Software"); CHECK(setup_files.category == "Software"); CHECK(updates.category == "Software"); CHECK(patches.category == "Software"); } ================================================ FILE: tests/unit/test_file_scanner.cpp ================================================ #include #include "FileScanner.hpp" #include "TestHelpers.hpp" #include #include #include #ifdef _WIN32 #include #else #include #endif static void write_file(const std::filesystem::path& path) { std::filesystem::create_directories(path.parent_path()); std::ofstream out(path); out << "data"; } TEST_CASE("hidden files require explicit flag") { TempDir temp_dir; const auto hidden_file = temp_dir.path() / ".secret.txt"; write_file(hidden_file); #ifdef _WIN32 auto current_attrs = GetFileAttributesW(hidden_file.c_str()); if (current_attrs == INVALID_FILE_ATTRIBUTES) { FAIL("Failed to get attributes for hidden test file"); } SetFileAttributesW(hidden_file.c_str(), current_attrs | FILE_ATTRIBUTE_HIDDEN); #endif FileScanner scanner; auto entries = scanner.get_directory_entries(temp_dir.path().string(), FileScanOptions::Files); REQUIRE(entries.empty()); entries = scanner.get_directory_entries(temp_dir.path().string(), FileScanOptions::Files | FileScanOptions::HiddenFiles); REQUIRE(entries.size() == 1); CHECK(entries.front().file_name == ".secret.txt"); CHECK(entries.front().type == FileType::File); } TEST_CASE("junk files are skipped regardless of flags") { TempDir temp_dir; const auto junk_file = temp_dir.path() / ".DS_Store"; write_file(junk_file); FileScanner scanner; auto entries = scanner.get_directory_entries(temp_dir.path().string(), FileScanOptions::Files | FileScanOptions::HiddenFiles); REQUIRE(entries.empty()); } TEST_CASE("application bundles are treated as files") { TempDir temp_dir; const auto bundle_dir = temp_dir.path() / "Sample.app"; std::filesystem::create_directories(bundle_dir / "Contents"); FileScanner scanner; auto file_entries = scanner.get_directory_entries(temp_dir.path().string(), FileScanOptions::Files); REQUIRE(file_entries.size() == 1); CHECK(file_entries.front().file_name == "Sample.app"); CHECK(file_entries.front().type == FileType::File); auto dir_entries = scanner.get_directory_entries(temp_dir.path().string(), FileScanOptions::Directories); REQUIRE(dir_entries.empty()); } TEST_CASE("recursive scans include nested files") { TempDir temp_dir; write_file(temp_dir.path() / "top.txt"); write_file(temp_dir.path() / "nested" / "deep.txt"); FileScanner scanner; const auto entries = scanner.get_directory_entries( temp_dir.path().string(), FileScanOptions::Files | FileScanOptions::Recursive); REQUIRE(entries.size() == 2); CHECK(std::any_of(entries.begin(), entries.end(), [](const FileEntry& entry) { return entry.file_name == "top.txt"; })); CHECK(std::any_of(entries.begin(), entries.end(), [](const FileEntry& entry) { return entry.file_name == "deep.txt"; })); } #ifndef _WIN32 class PermissionRestore { public: explicit PermissionRestore(std::filesystem::path path) : path_(std::move(path)) { } ~PermissionRestore() { std::error_code ec; std::filesystem::permissions( path_, std::filesystem::perms::owner_all, std::filesystem::perm_options::add, ec); } private: std::filesystem::path path_; }; TEST_CASE("recursive scans skip unreadable directories and continue") { TempDir temp_dir; const auto readable_file = temp_dir.path() / "readable" / "keep.txt"; const auto blocked_dir = temp_dir.path() / "blocked"; const auto blocked_file = blocked_dir / "skip.txt"; write_file(readable_file); write_file(blocked_file); PermissionRestore restore_permissions(blocked_dir); std::error_code ec; std::filesystem::permissions( blocked_dir, std::filesystem::perms::owner_all | std::filesystem::perms::group_all | std::filesystem::perms::others_all, std::filesystem::perm_options::remove, ec); REQUIRE(!ec); if (::access(blocked_dir.c_str(), R_OK | X_OK) == 0) { SKIP("permission restrictions are not enforced in this test environment"); } FileScanner scanner; std::vector entries; REQUIRE_NOTHROW(entries = scanner.get_directory_entries( temp_dir.path().string(), FileScanOptions::Files | FileScanOptions::Recursive)); REQUIRE(entries.size() == 1); CHECK(entries.front().file_name == "keep.txt"); } #endif ================================================ FILE: tests/unit/test_ggml_runtime_paths.cpp ================================================ #include #include "GgmlRuntimePaths.hpp" #include "TestHelpers.hpp" #include #include TEST_CASE("macOS ggml runtime candidates stay relative to the app layout") { const std::filesystem::path exe = "/tmp/AIFileSorter.app/Contents/MacOS/aifilesorter"; const auto candidates = GgmlRuntimePaths::macos_candidate_dirs(exe, "precompiled-m2"); REQUIRE_FALSE(candidates.empty()); REQUIRE(candidates[0] == std::filesystem::path("/tmp/AIFileSorter.app/Contents/MacOS/../lib/precompiled-m1")); REQUIRE(candidates[1] == std::filesystem::path("/tmp/AIFileSorter.app/Contents/MacOS/../lib/precompiled-m2")); REQUIRE(candidates[5] == std::filesystem::path("/tmp/AIFileSorter.app/Contents/MacOS/../lib/aifilesorter")); REQUIRE(candidates[6] == std::filesystem::path("/tmp/AIFileSorter.app/Contents/MacOS/../../lib/aifilesorter")); REQUIRE(std::find(candidates.begin(), candidates.end(), std::filesystem::path("/usr/local/lib")) == candidates.end()); REQUIRE(std::find(candidates.begin(), candidates.end(), std::filesystem::path("/opt/homebrew/lib")) == candidates.end()); } TEST_CASE("macOS ggml runtime resolution prefers bundled directories over generic siblings") { TempDir temp_dir; const auto root = temp_dir.path(); const auto exe = root / "bin" / "m2" / "aifilesorter"; const auto bundled = root / "lib" / "precompiled-m2"; const auto generic = root / "lib" / "aifilesorter"; std::filesystem::create_directories(exe.parent_path()); std::ofstream(exe).put('x'); std::filesystem::create_directories(bundled); std::ofstream(bundled / "libggml-metal.dylib").put('x'); std::filesystem::create_directories(generic); std::ofstream(generic / "libggml-cpu.dylib").put('x'); const auto resolved = GgmlRuntimePaths::resolve_macos_backend_dir( std::nullopt, exe, "precompiled-m2"); REQUIRE(resolved.has_value()); REQUIRE(*resolved == bundled); } TEST_CASE("macOS ggml runtime resolution preserves a valid explicit override") { TempDir temp_dir; const auto root = temp_dir.path(); const auto exe = root / "bin" / "aifilesorter"; const auto custom = root / "custom-ggml"; std::filesystem::create_directories(exe.parent_path()); std::ofstream(exe).put('x'); std::filesystem::create_directories(custom); std::ofstream(custom / "libggml-blas.dylib").put('x'); const auto resolved = GgmlRuntimePaths::resolve_macos_backend_dir( custom, exe, "precompiled"); REQUIRE(resolved.has_value()); REQUIRE(*resolved == custom); } ================================================ FILE: tests/unit/test_image_rename_metadata_service.cpp ================================================ #include #include "ImageRenameMetadataService.hpp" #include #include #include #include #include #include #include namespace { void append_u16_le(std::vector& buffer, uint16_t value) { buffer.push_back(static_cast(value & 0xFF)); buffer.push_back(static_cast((value >> 8) & 0xFF)); } void append_u32_le(std::vector& buffer, uint32_t value) { buffer.push_back(static_cast(value & 0xFF)); buffer.push_back(static_cast((value >> 8) & 0xFF)); buffer.push_back(static_cast((value >> 16) & 0xFF)); buffer.push_back(static_cast((value >> 24) & 0xFF)); } void append_u32_be(std::vector& buffer, uint32_t value) { buffer.push_back(static_cast((value >> 24) & 0xFF)); buffer.push_back(static_cast((value >> 16) & 0xFF)); buffer.push_back(static_cast((value >> 8) & 0xFF)); buffer.push_back(static_cast(value & 0xFF)); } std::vector make_tiff_with_datetime(const std::string& datetime) { std::string text = datetime; text.push_back('\0'); std::vector tiff; tiff.reserve(8 + 2 + 12 + 4 + text.size()); // TIFF header (little-endian) + first IFD offset. tiff.push_back('I'); tiff.push_back('I'); append_u16_le(tiff, 42); append_u32_le(tiff, 8); // IFD0 with one DateTime entry. append_u16_le(tiff, 1); append_u16_le(tiff, 0x0132); // DateTime append_u16_le(tiff, 2); // ASCII append_u32_le(tiff, static_cast(text.size())); append_u32_le(tiff, 8 + 2 + 12 + 4); // data offset after IFD0 + next-ifd ptr append_u32_le(tiff, 0); // next IFD tiff.insert(tiff.end(), text.begin(), text.end()); return tiff; } std::vector make_png_with_exif_chunk(const std::vector& tiff_payload) { std::vector png = { 0x89, 'P', 'N', 'G', 0x0D, 0x0A, 0x1A, 0x0A }; append_u32_be(png, static_cast(tiff_payload.size())); png.push_back('e'); png.push_back('X'); png.push_back('I'); png.push_back('f'); png.insert(png.end(), tiff_payload.begin(), tiff_payload.end()); append_u32_be(png, 0); // CRC is not validated by parser. append_u32_be(png, 0); png.push_back('I'); png.push_back('E'); png.push_back('N'); png.push_back('D'); append_u32_be(png, 0); return png; } void write_binary_file(const std::filesystem::path& path, const std::vector& bytes) { std::ofstream out(path, std::ios::binary | std::ios::trunc); REQUIRE(out.good()); out.write(reinterpret_cast(bytes.data()), static_cast(bytes.size())); REQUIRE(out.good()); } std::filesystem::path make_temp_dir(const std::string& suffix) { const auto stamp = std::chrono::steady_clock::now().time_since_epoch().count(); const auto dir = std::filesystem::temp_directory_path() / ("aifs_image_metadata_" + suffix + "_" + std::to_string(stamp)); std::filesystem::create_directories(dir); return dir; } void set_path_value(const std::string& value) { #if defined(_WIN32) _putenv_s("PATH", value.c_str()); #else setenv("PATH", value.c_str(), 1); #endif } void clear_path_value() { #if defined(_WIN32) _putenv_s("PATH", ""); #else unsetenv("PATH"); #endif } class PathGuard { public: PathGuard() { const char* existing = std::getenv("PATH"); if (existing) { had_value_ = true; old_value_ = existing; } } ~PathGuard() { if (had_value_) { set_path_value(old_value_); } else { clear_path_value(); } } private: bool had_value_{false}; std::string old_value_; }; } // namespace TEST_CASE("ImageRenameMetadataService composes date and place prefixes") { const std::string actual = ImageRenameMetadataService::apply_prefix_to_filename( "black_ducks_row.jpg", std::optional("2014-03-10"), std::optional("Venice")); CHECK(actual == "2014-03-10_venice_black_ducks_row.jpg"); } TEST_CASE("ImageRenameMetadataService skips prefix duplication") { const std::string already_prefixed = "2014-03-10_venice_black_ducks_row.jpg"; const std::string actual = ImageRenameMetadataService::apply_prefix_to_filename( already_prefixed, std::optional("2014-03-10"), std::optional("venice")); CHECK(actual == already_prefixed); } TEST_CASE("ImageRenameMetadataService sanitizes place labels") { const std::string actual = ImageRenameMetadataService::apply_prefix_to_filename( "street_market.jpg", std::optional("2020-01-05"), std::optional("New York City")); CHECK(actual == "2020-01-05_new_york_city_street_market.jpg"); } TEST_CASE("ImageRenameMetadataService returns original when no prefix data") { const std::string original = "sunset.jpg"; const std::string actual = ImageRenameMetadataService::apply_prefix_to_filename( original, std::nullopt, std::nullopt); CHECK(actual == original); } TEST_CASE("ImageRenameMetadataService reads TIFF date metadata for rename prefix") { const auto temp_dir = make_temp_dir("tiff"); const auto image_path = temp_dir / "sample.tiff"; write_binary_file(image_path, make_tiff_with_datetime("2014:03:10 12:00:00")); { ImageRenameMetadataService service(temp_dir.string()); const std::string actual = service.enrich_suggested_name(image_path, "black_ducks_row.tiff"); CHECK(actual == "2014-03-10_black_ducks_row.tiff"); } std::filesystem::remove_all(temp_dir); } TEST_CASE("ImageRenameMetadataService extracts TIFF capture date") { const auto temp_dir = make_temp_dir("tiff_date"); const auto image_path = temp_dir / "sample.tiff"; write_binary_file(image_path, make_tiff_with_datetime("2016:11:04 09:30:00")); { ImageRenameMetadataService service(temp_dir.string()); const auto date = service.extract_capture_date(image_path); REQUIRE(date.has_value()); CHECK(*date == "2016-11-04"); } std::filesystem::remove_all(temp_dir); } TEST_CASE("ImageRenameMetadataService reads PNG eXIf date metadata for rename prefix") { const auto temp_dir = make_temp_dir("png"); const auto image_path = temp_dir / "sample.png"; const auto tiff_payload = make_tiff_with_datetime("2021:09:17 08:45:30"); write_binary_file(image_path, make_png_with_exif_chunk(tiff_payload)); { ImageRenameMetadataService service(temp_dir.string()); const std::string actual = service.enrich_suggested_name(image_path, "street_market.png"); CHECK(actual == "2021-09-17_street_market.png"); } std::filesystem::remove_all(temp_dir); } #if !defined(_WIN32) TEST_CASE("ImageRenameMetadataService reads HEIC date metadata via exiftool fallback") { const auto temp_dir = make_temp_dir("heic"); const auto image_path = temp_dir / "sample.heic"; write_binary_file(image_path, std::vector{0x00, 0x00, 0x00, 0x00}); const auto exiftool_path = temp_dir / "exiftool"; { std::ofstream script(exiftool_path, std::ios::binary | std::ios::trunc); REQUIRE(script.good()); script << "#!/bin/sh\n"; script << "printf '[{\"DateTimeOriginal\":\"2019:07:11 14:20:00\"}]\\n'\n"; REQUIRE(script.good()); } std::filesystem::permissions(exiftool_path, std::filesystem::perms::owner_exec | std::filesystem::perms::group_exec | std::filesystem::perms::others_exec, std::filesystem::perm_options::add); PathGuard path_guard; const std::string old_path = std::getenv("PATH") ? std::getenv("PATH") : ""; const std::string new_path = temp_dir.string() + ":" + old_path; set_path_value(new_path); { ImageRenameMetadataService service(temp_dir.string()); const std::string actual = service.enrich_suggested_name(image_path, "trip.heic"); CHECK(actual == "2019-07-11_trip.heic"); } std::filesystem::remove_all(temp_dir); } #endif ================================================ FILE: tests/unit/test_llava_image_analyzer.cpp ================================================ #include #include "LlavaImageAnalyzer.hpp" #include "TestHelpers.hpp" #include "TestHooks.hpp" #ifndef GGML_USE_METAL namespace { struct BackendProbeGuard { ~BackendProbeGuard() { TestHooks::reset_backend_memory_probe(); TestHooks::reset_backend_availability_probe(); } }; } // namespace #endif TEST_CASE("LlavaImageAnalyzer uses conservative default visual batch sizing") { CHECK(LlavaImageAnalyzerTestAccess::default_visual_batch_size(false, "vulkan") == 512); CHECK(LlavaImageAnalyzerTestAccess::default_visual_batch_size(true, "metal") == 1024); CHECK(LlavaImageAnalyzerTestAccess::default_visual_batch_size(true, "vulkan") == 512); #if defined(_WIN32) CHECK(LlavaImageAnalyzerTestAccess::default_visual_batch_size(true, "cuda") == 512); #else CHECK(LlavaImageAnalyzerTestAccess::default_visual_batch_size(true, "cuda") == 768); #endif } #ifndef GGML_USE_METAL TEST_CASE("LlavaImageAnalyzer ignores global GPU layer override by default") { TempModelFile model(48, 8 * 1024 * 1024); EnvVarGuard backend("AI_FILE_SORTER_GPU_BACKEND", "vulkan"); EnvVarGuard global_override("AI_FILE_SORTER_N_GPU_LAYERS", "30"); EnvVarGuard visual_override("AI_FILE_SORTER_VISUAL_N_GPU_LAYERS", std::nullopt); EnvVarGuard llama_override("LLAMA_CPP_N_GPU_LAYERS", std::nullopt); EnvVarGuard llama_device("LLAMA_ARG_DEVICE", std::nullopt); BackendProbeGuard guard; TestHooks::set_backend_availability_probe([](std::string_view) { return true; }); TestHooks::set_backend_memory_probe([](std::string_view) { TestHooks::BackendMemoryInfo info; info.memory.free_bytes = 3ULL * 1024ULL * 1024ULL * 1024ULL; info.memory.total_bytes = 3ULL * 1024ULL * 1024ULL * 1024ULL; info.is_integrated = false; info.name = "Visual Test GPU"; return info; }); const int32_t actual = LlavaImageAnalyzerTestAccess::visual_model_n_gpu_layers_for_model(model.path().string()); CHECK(actual != 30); CHECK(actual > 0); } TEST_CASE("LlavaImageAnalyzer honors visual-specific GPU layer override") { TempModelFile model(48, 8 * 1024 * 1024); EnvVarGuard backend("AI_FILE_SORTER_GPU_BACKEND", "vulkan"); EnvVarGuard global_override("AI_FILE_SORTER_N_GPU_LAYERS", "30"); EnvVarGuard visual_override("AI_FILE_SORTER_VISUAL_N_GPU_LAYERS", "12"); EnvVarGuard llama_override("LLAMA_CPP_N_GPU_LAYERS", std::nullopt); EnvVarGuard llama_device("LLAMA_ARG_DEVICE", std::nullopt); BackendProbeGuard guard; TestHooks::set_backend_availability_probe([](std::string_view) { return true; }); TestHooks::set_backend_memory_probe([](std::string_view) { return std::nullopt; }); const int32_t actual = LlavaImageAnalyzerTestAccess::visual_model_n_gpu_layers_for_model(model.path().string()); CHECK(actual == 12); } #endif ================================================ FILE: tests/unit/test_llm_downloader.cpp ================================================ #include #include #include #include #include #include #include "LLMDownloader.hpp" #include "TestHelpers.hpp" #include "TestHooks.hpp" #include "Utils.hpp" namespace { void write_bytes(const std::filesystem::path& path, std::size_t count) { std::filesystem::create_directories(path.parent_path()); std::ofstream out(path, std::ios::binary | std::ios::trunc); for (std::size_t i = 0; i < count; ++i) { out.put('x'); } } void write_metadata(const std::filesystem::path& path, const std::string& url, long long content_length) { std::filesystem::create_directories(path.parent_path()); std::ofstream out(path, std::ios::trunc); out << "url=" << url << "\n"; out << "content_length=" << content_length << "\n"; } std::string make_unique_url() { return std::string("http://example.com/") + make_unique_token("model-") + ".gguf"; } } // namespace TEST_CASE("LLMDownloader retries full download after a range error") { TempDir tmp; const auto destination = (tmp.path() / "model.gguf").string(); const auto partial_destination = destination + ".part"; { std::ofstream out(destination, std::ios::binary); out << "abc"; } LLMDownloader downloader("http://example.com/model.gguf"); LLMDownloader::LLMDownloaderTestAccess::set_download_destination(downloader, destination); LLMDownloader::LLMDownloaderTestAccess::set_resume_headers(downloader, 6); std::atomic attempts{0}; TestHooks::set_llm_download_probe( [&](long offset, const std::string& path) -> CURLcode { ++attempts; if (attempts == 1) { REQUIRE(offset == 3); REQUIRE(path == partial_destination); return CURLE_HTTP_RANGE_ERROR; } REQUIRE(offset == 0); REQUIRE(path == partial_destination); std::ofstream out(path, std::ios::binary | std::ios::trunc); out << "abcdef"; return CURLE_OK; }); std::promise done; std::future finished = done.get_future(); std::atomic success{false}; std::string error_text; downloader.start_download( [](double) {}, [&]() { success = true; done.set_value(); }, nullptr, [&](const std::string& err) { error_text = err; done.set_value(); }); const auto status = finished.wait_for(std::chrono::seconds(2)); TestHooks::reset_llm_download_probe(); REQUIRE(status == std::future_status::ready); REQUIRE(error_text.empty()); REQUIRE(success.load()); REQUIRE(attempts.load() == 2); REQUIRE(std::filesystem::file_size(destination) == 6); REQUIRE_FALSE(std::filesystem::exists(partial_destination)); } TEST_CASE("LLMDownloader uses cached metadata for partial downloads") { TempDir tmp; EnvVarGuard home_guard("HOME", tmp.path().string()); #ifdef _WIN32 EnvVarGuard appdata_guard("APPDATA", tmp.path().string()); #endif const std::string url = make_unique_url(); const std::filesystem::path destination = Utils::make_default_path_to_file_from_download_url(url); const std::filesystem::path metadata = destination.string() + ".aifs.meta"; write_bytes(destination, 4); write_metadata(metadata, url, 16); LLMDownloader downloader(url); CHECK(downloader.get_real_content_length() == 16); CHECK_FALSE(std::filesystem::exists(destination)); CHECK(std::filesystem::exists(destination.string() + ".part")); CHECK(downloader.get_local_download_status() == LLMDownloader::DownloadStatus::InProgress); CHECK(downloader.get_download_status() == LLMDownloader::DownloadStatus::InProgress); CHECK_FALSE(downloader.is_inited()); } TEST_CASE("LLMDownloader resets to not started when local file is missing") { TempDir tmp; EnvVarGuard home_guard("HOME", tmp.path().string()); #ifdef _WIN32 EnvVarGuard appdata_guard("APPDATA", tmp.path().string()); #endif const std::string url = make_unique_url(); const std::filesystem::path destination = Utils::make_default_path_to_file_from_download_url(url); const std::filesystem::path metadata = destination.string() + ".aifs.meta"; write_metadata(metadata, url, 16); LLMDownloader downloader(url); CHECK(downloader.get_real_content_length() == 16); CHECK(downloader.get_local_download_status() == LLMDownloader::DownloadStatus::NotStarted); CHECK(downloader.get_download_status() == LLMDownloader::DownloadStatus::NotStarted); CHECK_FALSE(downloader.is_inited()); } TEST_CASE("LLMDownloader treats full local file as complete with cached metadata") { TempDir tmp; EnvVarGuard home_guard("HOME", tmp.path().string()); #ifdef _WIN32 EnvVarGuard appdata_guard("APPDATA", tmp.path().string()); #endif const std::string url = make_unique_url(); const std::filesystem::path destination = Utils::make_default_path_to_file_from_download_url(url); const std::filesystem::path metadata = destination.string() + ".aifs.meta"; write_bytes(destination, 16); write_metadata(metadata, url, 16); LLMDownloader downloader(url); CHECK(downloader.get_real_content_length() == 16); CHECK(downloader.get_local_download_status() == LLMDownloader::DownloadStatus::Complete); CHECK(downloader.get_download_status() == LLMDownloader::DownloadStatus::Complete); CHECK_FALSE(downloader.is_inited()); } TEST_CASE("LLMDownloader keeps final model intact while partial temp download exists") { TempDir tmp; EnvVarGuard home_guard("HOME", tmp.path().string()); #ifdef _WIN32 EnvVarGuard appdata_guard("APPDATA", tmp.path().string()); #endif const std::string url = make_unique_url(); const std::filesystem::path destination = Utils::make_default_path_to_file_from_download_url(url); const std::filesystem::path partial = destination.string() + ".part"; const std::filesystem::path metadata = destination.string() + ".aifs.meta"; write_bytes(destination, 16); write_bytes(partial, 4); write_metadata(metadata, url, 16); LLMDownloader downloader(url); CHECK(downloader.get_local_download_status() == LLMDownloader::DownloadStatus::InProgress); CHECK_FALSE(downloader.is_download_complete()); CHECK(std::filesystem::file_size(destination) == 16); CHECK(std::filesystem::file_size(partial) == 4); } ================================================ FILE: tests/unit/test_llm_selection_dialog_visual.cpp ================================================ #include #include "LLMDownloader.hpp" #include "LLMSelectionDialog.hpp" #include "LLMSelectionDialogTestAccess.hpp" #include "Settings.hpp" #include "TestHelpers.hpp" #include "TestHooks.hpp" #include "Utils.hpp" #include #include #include #include #include #include #include #include #include #ifndef _WIN32 namespace { std::string file_url_for(const std::filesystem::path& path) { return std::string("file://") + path.string(); } void write_bytes(const std::filesystem::path& path, std::size_t count) { std::filesystem::create_directories(path.parent_path()); std::ofstream out(path, std::ios::binary | std::ios::trunc); for (std::size_t i = 0; i < count; ++i) { out.put('x'); } } bool wait_for_label(QLabel* label, const QString& starts_with, std::chrono::milliseconds timeout) { const auto deadline = std::chrono::steady_clock::now() + timeout; while (std::chrono::steady_clock::now() < deadline) { QCoreApplication::processEvents(QEventLoop::AllEvents, 25); if (label && label->text().startsWith(starts_with)) { return true; } std::this_thread::sleep_for(std::chrono::milliseconds(5)); } return label && label->text().startsWith(starts_with); } } // namespace TEST_CASE("Visual LLaVA entry shows missing env var state") { EnvVarGuard platform_guard("QT_QPA_PLATFORM", std::string("offscreen")); QtAppContext qt_context; TempDir temp; EnvVarGuard home_guard("HOME", temp.path().string()); EnvVarGuard config_guard("AI_FILE_SORTER_CONFIG_DIR", temp.path().string()); EnvVarGuard llava_model_guard("LLAVA_MODEL_URL", std::nullopt); EnvVarGuard llava_mmproj_guard("LLAVA_MMPROJ_URL", std::nullopt); Settings settings; LLMSelectionDialog dialog(settings); const auto entry = LLMSelectionDialogTestAccess::llava_model_entry(dialog); REQUIRE(entry.status_label != nullptr); REQUIRE(entry.download_button != nullptr); CHECK(entry.status_label->text() == QStringLiteral("Missing download URL environment variable (LLAVA_MODEL_URL).")); CHECK_FALSE(entry.download_button->isEnabled()); } TEST_CASE("Visual LLaVA entry shows resume state for partial downloads") { EnvVarGuard platform_guard("QT_QPA_PLATFORM", std::string("offscreen")); QtAppContext qt_context; TempDir temp; EnvVarGuard home_guard("HOME", temp.path().string()); EnvVarGuard config_guard("AI_FILE_SORTER_CONFIG_DIR", temp.path().string()); const std::filesystem::path source_file = temp.path() / "llava-model.gguf"; write_bytes(source_file, 16); const std::string model_url = file_url_for(source_file); EnvVarGuard llava_model_guard("LLAVA_MODEL_URL", model_url); EnvVarGuard llava_mmproj_guard("LLAVA_MMPROJ_URL", std::nullopt); Settings settings; LLMSelectionDialog dialog(settings); auto entry = LLMSelectionDialogTestAccess::llava_model_entry(dialog); REQUIRE(entry.download_button != nullptr); REQUIRE(entry.status_label != nullptr); REQUIRE(entry.downloader != nullptr); const std::filesystem::path dest_path = Utils::make_default_path_to_file_from_download_url(model_url); write_bytes(dest_path, 4); LLMDownloader::LLMDownloaderTestAccess::set_resume_headers(*entry.downloader, 16); LLMSelectionDialogTestAccess::update_llava_model_entry(dialog); CHECK(entry.status_label->text() == QStringLiteral("Partial download detected. You can resume.")); CHECK(entry.download_button->text() == QStringLiteral("Resume download")); CHECK(entry.download_button->isEnabled()); } TEST_CASE("Visual LLaVA entry reports download errors") { EnvVarGuard platform_guard("QT_QPA_PLATFORM", std::string("offscreen")); QtAppContext qt_context; TempDir temp; EnvVarGuard home_guard("HOME", temp.path().string()); EnvVarGuard config_guard("AI_FILE_SORTER_CONFIG_DIR", temp.path().string()); const std::filesystem::path source_file = temp.path() / "llava-model.gguf"; write_bytes(source_file, 16); const std::string model_url = file_url_for(source_file); EnvVarGuard llava_model_guard("LLAVA_MODEL_URL", model_url); EnvVarGuard llava_mmproj_guard("LLAVA_MMPROJ_URL", std::nullopt); Settings settings; LLMSelectionDialog dialog(settings); LLMSelectionDialogTestAccess::set_network_available_override(dialog, true); auto entry = LLMSelectionDialogTestAccess::llava_model_entry(dialog); REQUIRE(entry.status_label != nullptr); REQUIRE(entry.downloader != nullptr); TestHooks::set_llm_download_probe([](long, const std::string&) { return CURLE_COULDNT_CONNECT; }); LLMSelectionDialogTestAccess::start_llava_model_download(dialog); const bool updated = wait_for_label(entry.status_label, QStringLiteral("Download error:"), std::chrono::milliseconds(300)); CHECK(updated); TestHooks::reset_llm_download_probe(); } #endif ================================================ FILE: tests/unit/test_local_llm_backend.cpp ================================================ #include #include "LocalLLMClient.hpp" #include "LocalLLMTestAccess.hpp" #include "TestHooks.hpp" #include "TestHelpers.hpp" #include "Utils.hpp" #ifndef GGML_USE_METAL namespace { struct CudaProbeGuard { ~CudaProbeGuard() { TestHooks::reset_cuda_availability_probe(); TestHooks::reset_cuda_memory_probe(); } }; struct BackendProbeGuard { ~BackendProbeGuard() { TestHooks::reset_backend_memory_probe(); TestHooks::reset_backend_availability_probe(); } }; } // namespace TEST_CASE("detect_preferred_backend reads environment") { EnvVarGuard guard("AI_FILE_SORTER_GPU_BACKEND", "cuda"); REQUIRE(LocalLLMTestAccess::detect_preferred_backend() == LocalLLMTestAccess::BackendPreference::Cuda); } TEST_CASE("CPU backend is honored when forced") { TempModelFile model; EnvVarGuard backend("AI_FILE_SORTER_GPU_BACKEND", "cpu"); EnvVarGuard disable_cuda("GGML_DISABLE_CUDA", std::nullopt); EnvVarGuard override_ngl("AI_FILE_SORTER_N_GPU_LAYERS", std::nullopt); auto params = LocalLLMTestAccess::prepare_model_params_for_testing( model.path().string()); REQUIRE(params.n_gpu_layers == 0); } TEST_CASE("CUDA backend can be forced off via GGML_DISABLE_CUDA") { TempModelFile model; EnvVarGuard backend("AI_FILE_SORTER_GPU_BACKEND", "cuda"); EnvVarGuard disable_cuda("GGML_DISABLE_CUDA", "1"); EnvVarGuard override_ngl("AI_FILE_SORTER_N_GPU_LAYERS", std::nullopt); CudaProbeGuard guard; TestHooks::set_cuda_availability_probe([] { return true; }); auto params = LocalLLMTestAccess::prepare_model_params_for_testing( model.path().string()); REQUIRE(params.n_gpu_layers == 0); } TEST_CASE("CUDA override is applied when backend is available") { TempModelFile model; EnvVarGuard backend("AI_FILE_SORTER_GPU_BACKEND", "cuda"); EnvVarGuard disable_cuda("GGML_DISABLE_CUDA", std::nullopt); EnvVarGuard override_ngl("AI_FILE_SORTER_N_GPU_LAYERS", "7"); CudaProbeGuard guard; TestHooks::set_cuda_availability_probe([] { return true; }); auto params = LocalLLMTestAccess::prepare_model_params_for_testing( model.path().string()); REQUIRE(params.n_gpu_layers == 7); } TEST_CASE("CUDA fallback when no GPU is available") { TempModelFile model; EnvVarGuard backend("AI_FILE_SORTER_GPU_BACKEND", "cuda"); EnvVarGuard disable_cuda("GGML_DISABLE_CUDA", std::nullopt); EnvVarGuard override_ngl("AI_FILE_SORTER_N_GPU_LAYERS", std::nullopt); CudaProbeGuard guard; TestHooks::set_cuda_availability_probe([] { return false; }); auto params = LocalLLMTestAccess::prepare_model_params_for_testing( model.path().string()); REQUIRE((params.n_gpu_layers == 0 || params.n_gpu_layers == -1)); } TEST_CASE("Vulkan backend honors explicit override") { TempModelFile model; EnvVarGuard backend("AI_FILE_SORTER_GPU_BACKEND", "vulkan"); EnvVarGuard override_ngl("AI_FILE_SORTER_N_GPU_LAYERS", "12"); EnvVarGuard llama_device("LLAMA_ARG_DEVICE", std::nullopt); BackendProbeGuard guard; TestHooks::set_backend_availability_probe([](std::string_view) { return true; }); TestHooks::set_backend_memory_probe([](std::string_view) { return std::nullopt; }); auto params = LocalLLMTestAccess::prepare_model_params_for_testing( model.path().string()); REQUIRE(params.n_gpu_layers == 12); } TEST_CASE("Vulkan backend derives layer count from memory probe") { TempModelFile model(48, 8 * 1024 * 1024); EnvVarGuard backend("AI_FILE_SORTER_GPU_BACKEND", "vulkan"); EnvVarGuard override_ngl("AI_FILE_SORTER_N_GPU_LAYERS", std::nullopt); EnvVarGuard llama_device("LLAMA_ARG_DEVICE", std::nullopt); BackendProbeGuard guard; TestHooks::set_backend_availability_probe([](std::string_view) { return true; }); TestHooks::set_backend_memory_probe([](std::string_view) { TestHooks::BackendMemoryInfo info; info.memory.free_bytes = 3ULL * 1024ULL * 1024ULL * 1024ULL; info.memory.total_bytes = 3ULL * 1024ULL * 1024ULL * 1024ULL; info.is_integrated = false; info.name = "Vulkan Test GPU"; return info; }); auto params = LocalLLMTestAccess::prepare_model_params_for_testing( model.path().string()); REQUIRE(params.n_gpu_layers > 0); REQUIRE(params.n_gpu_layers <= 48); } TEST_CASE("Vulkan backend falls back to CPU when memory metrics are unavailable") { TempModelFile model; EnvVarGuard backend("AI_FILE_SORTER_GPU_BACKEND", "vulkan"); EnvVarGuard override_ngl("AI_FILE_SORTER_N_GPU_LAYERS", std::nullopt); EnvVarGuard llama_device("LLAMA_ARG_DEVICE", std::nullopt); BackendProbeGuard guard; TestHooks::set_backend_availability_probe([](std::string_view) { return true; }); TestHooks::set_backend_memory_probe([](std::string_view) { return std::nullopt; }); auto params = LocalLLMTestAccess::prepare_model_params_for_testing( model.path().string()); REQUIRE(params.n_gpu_layers == 0); } TEST_CASE("Vulkan backend falls back to CPU when unavailable") { TempModelFile model; EnvVarGuard backend("AI_FILE_SORTER_GPU_BACKEND", "vulkan"); EnvVarGuard override_ngl("AI_FILE_SORTER_N_GPU_LAYERS", std::nullopt); EnvVarGuard llama_device("LLAMA_ARG_DEVICE", std::nullopt); BackendProbeGuard guard; TestHooks::set_backend_availability_probe([](std::string_view) { return false; }); auto params = LocalLLMTestAccess::prepare_model_params_for_testing( model.path().string()); REQUIRE(params.n_gpu_layers == 0); } TEST_CASE("LocalLLMClient declines GPU fallback when callback returns false") { TempModelFile model; EnvVarGuard backend("AI_FILE_SORTER_GPU_BACKEND", "vulkan"); EnvVarGuard override_ngl("AI_FILE_SORTER_N_GPU_LAYERS", "1"); EnvVarGuard llama_device("LLAMA_ARG_DEVICE", std::nullopt); BackendProbeGuard guard; TestHooks::set_backend_availability_probe([](std::string_view) { return true; }); bool called = false; try { LocalLLMClient client(model.path().string(), [&called](const std::string&) { called = true; return false; }); FAIL("Expected LocalLLMClient to throw when CPU fallback is declined"); } catch (const std::runtime_error& ex) { REQUIRE(called); REQUIRE(std::string(ex.what()).find("CPU fallback was declined") != std::string::npos); } } TEST_CASE("LocalLLMClient retries on CPU when fallback is accepted") { TempModelFile model; EnvVarGuard backend("AI_FILE_SORTER_GPU_BACKEND", "vulkan"); EnvVarGuard override_ngl("AI_FILE_SORTER_N_GPU_LAYERS", "1"); EnvVarGuard llama_device("LLAMA_ARG_DEVICE", std::nullopt); BackendProbeGuard guard; TestHooks::set_backend_availability_probe([](std::string_view) { return true; }); bool called = false; try { LocalLLMClient client(model.path().string(), [&called](const std::string&) { called = true; return true; }); FAIL("Expected LocalLLMClient to throw due to invalid model"); } catch (const std::runtime_error& ex) { REQUIRE(called); REQUIRE(std::string(ex.what()).find("Failed to load model") != std::string::npos); } } #endif // GGML_USE_METAL ================================================ FILE: tests/unit/test_main_app_image_options.cpp ================================================ #include #include "MainApp.hpp" #include "MainAppTestAccess.hpp" #include "Settings.hpp" #include "TestHelpers.hpp" #include "Utils.hpp" #include #include #include #include #include #include #include #include #ifndef _WIN32 namespace { void create_visual_llm_files() { const std::string model_url = "https://example.com/llava-model.gguf"; const std::string mmproj_url = "https://example.com/mmproj-model-f16.gguf"; const std::filesystem::path model_path = Utils::make_default_path_to_file_from_download_url(model_url); const std::filesystem::path mmproj_path = Utils::make_default_path_to_file_from_download_url(mmproj_url); std::filesystem::create_directories(model_path.parent_path()); std::ofstream(model_path.string(), std::ios::binary).put('x'); std::ofstream(mmproj_path.string(), std::ios::binary).put('x'); } } // namespace TEST_CASE("Image analysis checkboxes enable and enforce rename-only behavior") { EnvVarGuard platform_guard("QT_QPA_PLATFORM", std::string("offscreen")); QtAppContext qt_context; TempDir temp; EnvVarGuard home_guard("HOME", temp.path().string()); EnvVarGuard config_guard("AI_FILE_SORTER_CONFIG_DIR", temp.path().string()); EnvVarGuard model_guard("LLAVA_MODEL_URL", std::string("https://example.com/llava-model.gguf")); EnvVarGuard mmproj_guard("LLAVA_MMPROJ_URL", std::string("https://example.com/mmproj-model-f16.gguf")); create_visual_llm_files(); Settings settings; settings.set_analyze_images_by_content(false); settings.set_offer_rename_images(false); settings.set_rename_images_only(false); REQUIRE(settings.save()); MainApp window(settings, /*development_mode=*/false); QCheckBox* analyze = MainAppTestAccess::analyze_images_checkbox(window); QCheckBox* process_only = MainAppTestAccess::process_images_only_checkbox(window); QCheckBox* add_date_category = MainAppTestAccess::add_image_date_to_category_checkbox(window); QCheckBox* add_date_place = MainAppTestAccess::add_image_date_place_to_filename_checkbox(window); QCheckBox* add_media_metadata = MainAppTestAccess::add_audio_video_metadata_to_filename_checkbox(window); QCheckBox* offer = MainAppTestAccess::offer_rename_images_checkbox(window); QCheckBox* rename_only = MainAppTestAccess::rename_images_only_checkbox(window); REQUIRE(analyze != nullptr); REQUIRE(process_only != nullptr); REQUIRE(add_date_category != nullptr); REQUIRE(add_date_place != nullptr); REQUIRE(add_media_metadata != nullptr); REQUIRE(offer != nullptr); REQUIRE(rename_only != nullptr); REQUIRE_FALSE(analyze->isChecked()); REQUIRE_FALSE(process_only->isEnabled()); REQUIRE_FALSE(add_date_category->isEnabled()); REQUIRE_FALSE(add_date_place->isEnabled()); REQUIRE(add_media_metadata->isEnabled()); REQUIRE(add_media_metadata->isChecked()); REQUIRE_FALSE(offer->isEnabled()); REQUIRE_FALSE(rename_only->isEnabled()); analyze->setChecked(true); REQUIRE(process_only->isEnabled()); REQUIRE(add_date_category->isEnabled()); REQUIRE_FALSE(add_date_place->isEnabled()); REQUIRE(add_media_metadata->isEnabled()); REQUIRE(offer->isEnabled()); REQUIRE(rename_only->isEnabled()); add_date_category->setChecked(true); REQUIRE(settings.get_add_image_date_to_category()); add_media_metadata->setChecked(false); REQUIRE_FALSE(settings.get_add_audio_video_metadata_to_filename()); offer->setChecked(true); REQUIRE(add_date_place->isEnabled()); add_date_place->setChecked(true); REQUIRE(settings.get_add_image_date_place_to_filename()); rename_only->setChecked(true); REQUIRE(offer->isChecked()); REQUIRE_FALSE(add_date_category->isEnabled()); offer->setChecked(false); REQUIRE_FALSE(add_date_place->isEnabled()); REQUIRE(add_date_place->isChecked()); REQUIRE_FALSE(rename_only->isChecked()); REQUIRE(add_date_category->isEnabled()); REQUIRE(add_date_category->isChecked()); } TEST_CASE("Top-level analysis rows share the same leading edge") { EnvVarGuard platform_guard("QT_QPA_PLATFORM", std::string("offscreen")); QtAppContext qt_context; TempDir temp; EnvVarGuard home_guard("HOME", temp.path().string()); EnvVarGuard config_guard("AI_FILE_SORTER_CONFIG_DIR", temp.path().string()); Settings settings; REQUIRE(settings.save()); MainApp window(settings, /*development_mode=*/false); window.show(); QApplication::processEvents(); QCheckBox* analyze_documents = MainAppTestAccess::analyze_documents_checkbox(window); QCheckBox* analyze_images = MainAppTestAccess::analyze_images_checkbox(window); QCheckBox* add_media_metadata = MainAppTestAccess::add_audio_video_metadata_to_filename_checkbox(window); REQUIRE(analyze_documents != nullptr); REQUIRE(analyze_images != nullptr); REQUIRE(add_media_metadata != nullptr); CHECK(add_media_metadata->x() == analyze_documents->x()); CHECK(add_media_metadata->x() == analyze_images->x()); } TEST_CASE("Analysis toggles use disclosure indicators instead of toolbutton arrows") { EnvVarGuard platform_guard("QT_QPA_PLATFORM", std::string("offscreen")); QtAppContext qt_context; TempDir temp; EnvVarGuard home_guard("HOME", temp.path().string()); EnvVarGuard config_guard("AI_FILE_SORTER_CONFIG_DIR", temp.path().string()); Settings settings; REQUIRE(settings.save()); MainApp window(settings, /*development_mode=*/false); QToolButton* image_toggle = MainAppTestAccess::image_options_toggle_button(window); QToolButton* document_toggle = MainAppTestAccess::document_options_toggle_button(window); REQUIRE(image_toggle != nullptr); REQUIRE(document_toggle != nullptr); CHECK(image_toggle->arrowType() == Qt::NoArrow); CHECK(document_toggle->arrowType() == Qt::NoArrow); CHECK(image_toggle->isCheckable()); CHECK(document_toggle->isCheckable()); } TEST_CASE("Image rename-only does not disable categorization unless processing images only") { EnvVarGuard platform_guard("QT_QPA_PLATFORM", std::string("offscreen")); QtAppContext qt_context; TempDir temp; EnvVarGuard home_guard("HOME", temp.path().string()); EnvVarGuard config_guard("AI_FILE_SORTER_CONFIG_DIR", temp.path().string()); EnvVarGuard model_guard("LLAVA_MODEL_URL", std::string("https://example.com/llava-model.gguf")); EnvVarGuard mmproj_guard("LLAVA_MMPROJ_URL", std::string("https://example.com/mmproj-model-f16.gguf")); create_visual_llm_files(); Settings settings; settings.set_analyze_images_by_content(false); settings.set_offer_rename_images(false); settings.set_rename_images_only(false); settings.set_process_images_only(false); REQUIRE(settings.save()); MainApp window(settings, /*development_mode=*/false); QCheckBox* categorize_files = MainAppTestAccess::categorize_files_checkbox(window); QCheckBox* analyze = MainAppTestAccess::analyze_images_checkbox(window); QCheckBox* process_only = MainAppTestAccess::process_images_only_checkbox(window); QCheckBox* rename_only = MainAppTestAccess::rename_images_only_checkbox(window); REQUIRE(categorize_files != nullptr); REQUIRE(analyze != nullptr); REQUIRE(process_only != nullptr); REQUIRE(rename_only != nullptr); analyze->setChecked(true); rename_only->setChecked(true); CHECK(categorize_files->isEnabled()); process_only->setChecked(true); CHECK_FALSE(categorize_files->isEnabled()); } TEST_CASE("Document rename-only does not disable categorization unless processing documents only") { EnvVarGuard platform_guard("QT_QPA_PLATFORM", std::string("offscreen")); QtAppContext qt_context; TempDir temp; EnvVarGuard home_guard("HOME", temp.path().string()); EnvVarGuard config_guard("AI_FILE_SORTER_CONFIG_DIR", temp.path().string()); Settings settings; settings.set_analyze_documents_by_content(false); settings.set_offer_rename_documents(false); settings.set_rename_documents_only(false); settings.set_process_documents_only(false); REQUIRE(settings.save()); MainApp window(settings, /*development_mode=*/false); QCheckBox* categorize_files = MainAppTestAccess::categorize_files_checkbox(window); QCheckBox* analyze = MainAppTestAccess::analyze_documents_checkbox(window); QCheckBox* process_only = MainAppTestAccess::process_documents_only_checkbox(window); QCheckBox* rename_only = MainAppTestAccess::rename_documents_only_checkbox(window); REQUIRE(categorize_files != nullptr); REQUIRE(analyze != nullptr); REQUIRE(process_only != nullptr); REQUIRE(rename_only != nullptr); analyze->setChecked(true); rename_only->setChecked(true); CHECK(categorize_files->isEnabled()); process_only->setChecked(true); CHECK_FALSE(categorize_files->isEnabled()); } TEST_CASE("Document analysis ignores other files when categorize files is off") { std::vector files = { {"/tmp/photo.jpg", "photo.jpg", FileType::File}, {"/tmp/report.pdf", "report.pdf", FileType::File}, {"/tmp/archive.bin", "archive.bin", FileType::File}, {"/tmp/folder", "folder", FileType::Directory} }; std::unordered_set renamed_files; auto contains = [](const std::vector& entries, const std::string& name) { return std::any_of(entries.begin(), entries.end(), [&name](const FileEntry& entry) { return entry.file_name == name; }); }; std::vector image_entries; std::vector document_entries; std::vector other_entries; MainAppTestAccess::split_entries_for_analysis(files, false, true, false, false, false, false, false, false, renamed_files, image_entries, document_entries, other_entries); CHECK(image_entries.empty()); CHECK(contains(document_entries, "report.pdf")); CHECK_FALSE(contains(other_entries, "photo.jpg")); CHECK_FALSE(contains(other_entries, "archive.bin")); CHECK(contains(other_entries, "folder")); } TEST_CASE("Image analysis toggle disables when dialog closes without downloads") { EnvVarGuard platform_guard("QT_QPA_PLATFORM", std::string("offscreen")); QtAppContext qt_context; TempDir temp; EnvVarGuard home_guard("HOME", temp.path().string()); EnvVarGuard config_guard("AI_FILE_SORTER_CONFIG_DIR", temp.path().string()); EnvVarGuard model_guard("LLAVA_MODEL_URL", std::string("https://example.com/llava-model.gguf")); EnvVarGuard mmproj_guard("LLAVA_MMPROJ_URL", std::string("https://example.com/mmproj-model-f16.gguf")); Settings settings; settings.set_analyze_images_by_content(false); settings.set_offer_rename_images(false); settings.set_rename_images_only(false); REQUIRE(settings.save()); MainApp window(settings, /*development_mode=*/false); MainAppTestAccess::set_visual_llm_available_probe(window, []() { return false; }); MainAppTestAccess::set_llm_selection_runner(window, []() {}); MainAppTestAccess::set_image_analysis_prompt_override(window, []() { return true; }); QCheckBox* analyze = MainAppTestAccess::analyze_images_checkbox(window); REQUIRE(analyze != nullptr); analyze->setChecked(true); REQUIRE_FALSE(analyze->isChecked()); REQUIRE_FALSE(settings.get_analyze_images_by_content()); } TEST_CASE("Image analysis toggle cancels when user declines download") { EnvVarGuard platform_guard("QT_QPA_PLATFORM", std::string("offscreen")); QtAppContext qt_context; TempDir temp; EnvVarGuard home_guard("HOME", temp.path().string()); EnvVarGuard config_guard("AI_FILE_SORTER_CONFIG_DIR", temp.path().string()); EnvVarGuard model_guard("LLAVA_MODEL_URL", std::string("https://example.com/llava-model.gguf")); EnvVarGuard mmproj_guard("LLAVA_MMPROJ_URL", std::string("https://example.com/mmproj-model-f16.gguf")); Settings settings; settings.set_analyze_images_by_content(false); settings.set_offer_rename_images(false); settings.set_rename_images_only(false); REQUIRE(settings.save()); bool dialog_opened = false; MainApp window(settings, /*development_mode=*/false); MainAppTestAccess::set_visual_llm_available_probe(window, []() { return false; }); MainAppTestAccess::set_llm_selection_runner(window, [&dialog_opened]() { dialog_opened = true; }); MainAppTestAccess::set_image_analysis_prompt_override(window, []() { return false; }); QCheckBox* analyze = MainAppTestAccess::analyze_images_checkbox(window); REQUIRE(analyze != nullptr); analyze->setChecked(true); REQUIRE_FALSE(analyze->isChecked()); REQUIRE_FALSE(settings.get_analyze_images_by_content()); REQUIRE_FALSE(dialog_opened); } TEST_CASE("Already-renamed images skip vision analysis") { std::vector files = { {"/tmp/renamed.png", "renamed.png", FileType::File}, {"/tmp/other.png", "other.png", FileType::File}, {"/tmp/doc.txt", "doc.txt", FileType::File}, {"/tmp/folder", "folder", FileType::Directory} }; std::unordered_set renamed_files = {"renamed.png"}; auto contains = [](const std::vector& entries, const std::string& name) { return std::any_of(entries.begin(), entries.end(), [&name](const FileEntry& entry) { return entry.file_name == name; }); }; std::vector image_entries; std::vector document_entries; std::vector other_entries; SECTION("categorization uses filename when already renamed") { MainAppTestAccess::split_entries_for_analysis(files, true, false, false, false, false, false, true, false, renamed_files, image_entries, document_entries, other_entries); CHECK_FALSE(contains(image_entries, "renamed.png")); CHECK_FALSE(contains(document_entries, "renamed.png")); CHECK(contains(other_entries, "renamed.png")); CHECK(contains(image_entries, "other.png")); CHECK_FALSE(contains(document_entries, "other.png")); CHECK(contains(other_entries, "doc.txt")); CHECK(contains(other_entries, "folder")); } SECTION("rename-only skips already-renamed images entirely") { MainAppTestAccess::split_entries_for_analysis(files, true, false, false, false, true, false, true, false, renamed_files, image_entries, document_entries, other_entries); CHECK_FALSE(contains(image_entries, "renamed.png")); CHECK_FALSE(contains(document_entries, "renamed.png")); CHECK_FALSE(contains(other_entries, "renamed.png")); CHECK(contains(image_entries, "other.png")); CHECK_FALSE(contains(document_entries, "other.png")); } } #endif ================================================ FILE: tests/unit/test_main_app_translation.cpp ================================================ #include #include "MainApp.hpp" #include "MainAppTestAccess.hpp" #include "TestHelpers.hpp" #include "TranslationManager.hpp" #include "Language.hpp" #include #include #ifndef _WIN32 TEST_CASE("MainApp retranslate reflects language changes") { EnvVarGuard platform_guard("QT_QPA_PLATFORM", "offscreen"); QtAppContext qt_context; Settings settings; settings.load(); MainApp window(settings, /*development_mode=*/false); struct ExpectedTranslation { Language language; QString analyze_label; QString folder_label; }; const std::vector expected = { {Language::English, QStringLiteral("Analyze folder"), QStringLiteral("Folder:")}, {Language::French, QStringLiteral("Analyser le dossier"), QStringLiteral("Dossier :")}, {Language::German, QStringLiteral("Ordner analysieren"), QStringLiteral("Ordner:")}, {Language::Italian, QStringLiteral("Analizza cartella"), QStringLiteral("Cartella:")}, {Language::Spanish, QStringLiteral("Analizar carpeta"), QStringLiteral("Carpeta:")}, {Language::Dutch, QStringLiteral("Map analyseren"), QStringLiteral("Map:")}, {Language::Turkish, QStringLiteral("Klasörü analiz et"), QStringLiteral("Klasör:")}, {Language::Korean, QStringLiteral("폴더 분석"), QStringLiteral("폴더:")} }; for (const auto& entry : expected) { settings.set_language(entry.language); TranslationManager::instance().set_language(entry.language); MainAppTestAccess::trigger_retranslate(window); const auto analyze_text = MainAppTestAccess::analyze_button_text(window); const auto folder_text = MainAppTestAccess::path_label_text(window); CAPTURE(static_cast(entry.language), analyze_text, folder_text); REQUIRE(analyze_text == entry.analyze_label); REQUIRE(folder_text == entry.folder_label); } } TEST_CASE("Updater strings are translated for all supported UI languages") { EnvVarGuard platform_guard("QT_QPA_PLATFORM", "offscreen"); QtAppContext qt_context; struct ExpectedTranslation { Language language; QString update_failed; QString update_manually; QString prepare_failed; QString installer_launch_failed; QString no_download_target; QString downloading_update; QString downloading_installer; QString installer_ready; QString quit_and_launch_message; QString quit_and_launch_button; }; const std::vector expected = { {Language::English, QStringLiteral("Update Failed"), QStringLiteral("Update manually"), QStringLiteral("Failed to prepare the update installer.\n%1"), QStringLiteral("The installer could not be launched."), QStringLiteral("No download target is available for this update."), QStringLiteral("Downloading Update"), QStringLiteral("Downloading the update installer..."), QStringLiteral("Installer Ready"), QStringLiteral("Quit the app and launch the installer to update"), QStringLiteral("Quit and Launch Installer")}, {Language::French, QStringLiteral("Échec de la mise à jour"), QStringLiteral("Mettre à jour manuellement"), QStringLiteral("Échec de la préparation du programme d'installation de la mise à jour.\n%1"), QStringLiteral("Le programme d'installation n'a pas pu être lancé."), QStringLiteral("Aucune cible de téléchargement n'est disponible pour cette mise à jour."), QStringLiteral("Téléchargement de la mise à jour"), QStringLiteral("Téléchargement du programme d'installation de la mise à jour..."), QStringLiteral("Programme d'installation prêt"), QStringLiteral("Quittez l'application et lancez le programme d'installation pour effectuer la mise à jour"), QStringLiteral("Quitter et lancer le programme d'installation")}, {Language::German, QStringLiteral("Update fehlgeschlagen"), QStringLiteral("Manuell aktualisieren"), QStringLiteral("Das Update-Installationsprogramm konnte nicht vorbereitet werden.\n%1"), QStringLiteral("Das Installationsprogramm konnte nicht gestartet werden."), QStringLiteral("Für dieses Update ist kein Download-Ziel verfügbar."), QStringLiteral("Update wird heruntergeladen"), QStringLiteral("Das Update-Installationsprogramm wird heruntergeladen..."), QStringLiteral("Installationsprogramm bereit"), QStringLiteral("Beenden Sie die App und starten Sie das Installationsprogramm, um zu aktualisieren"), QStringLiteral("Beenden und Installationsprogramm starten")}, {Language::Italian, QStringLiteral("Aggiornamento non riuscito"), QStringLiteral("Aggiorna manualmente"), QStringLiteral("Impossibile preparare il programma di installazione dell'aggiornamento.\n%1"), QStringLiteral("Impossibile avviare il programma di installazione."), QStringLiteral("Nessuna destinazione di download disponibile per questo aggiornamento."), QStringLiteral("Download aggiornamento"), QStringLiteral("Download del programma di installazione dell'aggiornamento..."), QStringLiteral("Programma di installazione pronto"), QStringLiteral("Chiudi l'app e avvia il programma di installazione per aggiornare"), QStringLiteral("Chiudi e avvia il programma di installazione")}, {Language::Spanish, QStringLiteral("La actualización falló"), QStringLiteral("Actualizar manualmente"), QStringLiteral("No se pudo preparar el instalador de la actualización.\n%1"), QStringLiteral("No se pudo ejecutar el instalador."), QStringLiteral("No hay un destino de descarga disponible para esta actualización."), QStringLiteral("Descargando actualización"), QStringLiteral("Descargando el instalador de la actualización..."), QStringLiteral("Instalador listo"), QStringLiteral("Cierra la aplicación y ejecuta el instalador para actualizar"), QStringLiteral("Cerrar y ejecutar instalador")}, {Language::Dutch, QStringLiteral("Bijwerken mislukt"), QStringLiteral("Handmatig bijwerken"), QStringLiteral("Het installatieprogramma van de update kon niet worden voorbereid.\n%1"), QStringLiteral("Het installatieprogramma kon niet worden gestart."), QStringLiteral("Er is geen downloaddoel beschikbaar voor deze update."), QStringLiteral("Update downloaden"), QStringLiteral("Het installatieprogramma van de update wordt gedownload..."), QStringLiteral("Installatieprogramma gereed"), QStringLiteral("Sluit de app af en start het installatieprogramma om bij te werken"), QStringLiteral("Afsluiten en installatieprogramma starten")}, {Language::Turkish, QStringLiteral("Güncelleme başarısız oldu"), QStringLiteral("Elle güncelle"), QStringLiteral("Güncelleme yükleyicisi hazırlanamadı.\n%1"), QStringLiteral("Yükleyici başlatılamadı."), QStringLiteral("Bu güncelleme için kullanılabilir bir indirme hedefi yok."), QStringLiteral("Güncelleme indiriliyor"), QStringLiteral("Güncelleme yükleyicisi indiriliyor..."), QStringLiteral("Yükleyici hazır"), QStringLiteral("Güncellemek için uygulamadan çıkın ve yükleyiciyi başlatın"), QStringLiteral("Çık ve yükleyiciyi başlat")}, {Language::Korean, QStringLiteral("업데이트 실패"), QStringLiteral("수동으로 업데이트"), QStringLiteral("업데이트 설치 프로그램을 준비하지 못했습니다.\n%1"), QStringLiteral("설치 프로그램을 실행할 수 없습니다."), QStringLiteral("이 업데이트에 사용할 다운로드 대상이 없습니다."), QStringLiteral("업데이트 다운로드 중"), QStringLiteral("업데이트 설치 프로그램을 다운로드하는 중..."), QStringLiteral("설치 프로그램 준비 완료"), QStringLiteral("업데이트하려면 앱을 종료하고 설치 프로그램을 실행하세요"), QStringLiteral("종료 후 설치 프로그램 실행")} }; for (const auto& entry : expected) { TranslationManager::instance().set_language(entry.language); const auto update_failed = QCoreApplication::translate("QObject", "Update Failed"); const auto update_manually = QCoreApplication::translate("QObject", "Update manually"); const auto prepare_failed = QCoreApplication::translate("QObject", "Failed to prepare the update installer.\n%1"); const auto installer_launch_failed = QCoreApplication::translate("QObject", "The installer could not be launched."); const auto no_download_target = QCoreApplication::translate("QObject", "No download target is available for this update."); const auto downloading_update = QCoreApplication::translate("QObject", "Downloading Update"); const auto downloading_installer = QCoreApplication::translate("QObject", "Downloading the update installer..."); const auto installer_ready = QCoreApplication::translate("QObject", "Installer Ready"); const auto quit_and_launch_message = QCoreApplication::translate("QObject", "Quit the app and launch the installer to update"); const auto quit_and_launch_button = QCoreApplication::translate("QObject", "Quit and Launch Installer"); CAPTURE(static_cast(entry.language), update_failed, update_manually, prepare_failed, installer_launch_failed, no_download_target, downloading_update, downloading_installer, installer_ready, quit_and_launch_message, quit_and_launch_button); REQUIRE(update_failed == entry.update_failed); REQUIRE(update_manually == entry.update_manually); REQUIRE(prepare_failed == entry.prepare_failed); REQUIRE(installer_launch_failed == entry.installer_launch_failed); REQUIRE(no_download_target == entry.no_download_target); REQUIRE(downloading_update == entry.downloading_update); REQUIRE(downloading_installer == entry.downloading_installer); REQUIRE(installer_ready == entry.installer_ready); REQUIRE(quit_and_launch_message == entry.quit_and_launch_message); REQUIRE(quit_and_launch_button == entry.quit_and_launch_button); } } #endif ================================================ FILE: tests/unit/test_main_app_visual_fallback.cpp ================================================ #include #include "MainAppTestAccess.hpp" #include TEST_CASE("Visual CPU fallback detection recognizes retryable GPU failures") { CHECK(MainAppTestAccess::should_offer_visual_cpu_fallback( "Failed to create llama_context (try AI_FILE_SORTER_VISUAL_USE_GPU=0 to force CPU)")); CHECK(MainAppTestAccess::should_offer_visual_cpu_fallback("mtmd_helper_eval_chunks failed")); CHECK(MainAppTestAccess::should_offer_visual_cpu_fallback("VK_ERROR_OUT_OF_DEVICE_MEMORY")); CHECK(MainAppTestAccess::should_offer_visual_cpu_fallback("CUDA error out of memory")); } TEST_CASE("Visual CPU fallback detection ignores non-retryable startup failures") { CHECK_FALSE(MainAppTestAccess::should_offer_visual_cpu_fallback( "Failed to load mmproj file at C:/models/mmproj.gguf")); CHECK_FALSE(MainAppTestAccess::should_offer_visual_cpu_fallback( "Failed to load LLaVA text model at C:/models/model.gguf")); CHECK_FALSE(MainAppTestAccess::should_offer_visual_cpu_fallback( "The provided mmproj file does not expose vision capabilities")); } ================================================ FILE: tests/unit/test_media_rename_metadata_service.cpp ================================================ #include #include "MediaRenameMetadataService.hpp" #include #include #include #include #include #include #include #include TEST_CASE("MediaRenameMetadataService composes year-artist-album-title filenames") { MediaRenameMetadataService::MetadataFields metadata; metadata.year = "2014"; metadata.artist = "Massive Attack"; metadata.album = "Mezzanine"; metadata.title = "Teardrop"; const std::filesystem::path input{"/tmp/track01.mp3"}; const std::string output = MediaRenameMetadataService::compose_filename(input, metadata); REQUIRE(output == "2014_massive_attack_mezzanine_teardrop.mp3"); } TEST_CASE("MediaRenameMetadataService falls back to source stem when title is missing") { MediaRenameMetadataService::MetadataFields metadata; metadata.year = "1997"; metadata.artist = "Daft Punk"; const std::filesystem::path input{"/tmp/Around The World.flac"}; const std::string output = MediaRenameMetadataService::compose_filename(input, metadata); REQUIRE(output == "1997_daft_punk_around_the_world.flac"); } TEST_CASE("MediaRenameMetadataService keeps original filename when metadata is absent") { const MediaRenameMetadataService::MetadataFields metadata{}; const std::filesystem::path input{"/tmp/video_clip.mp4"}; const std::string output = MediaRenameMetadataService::compose_filename(input, metadata); REQUIRE(output == "video_clip.mp4"); } #ifndef AI_FILE_SORTER_USE_MEDIAINFOLIB namespace { class TempMediaFile { public: explicit TempMediaFile(const std::string& file_name) { const auto now = std::chrono::steady_clock::now().time_since_epoch().count(); path_ = std::filesystem::temp_directory_path() / ("aifs_media_meta_" + std::to_string(now) + "_" + file_name); } ~TempMediaFile() { std::error_code ec; std::filesystem::remove(path_, ec); } const std::filesystem::path& path() const { return path_; } private: std::filesystem::path path_; }; void write_binary_file(const std::filesystem::path& path, const std::vector& bytes) { std::ofstream output(path, std::ios::binary | std::ios::trunc); REQUIRE(output.is_open()); output.write(reinterpret_cast(bytes.data()), static_cast(bytes.size())); REQUIRE(output.good()); } void append_le_u32(std::vector& output, std::uint32_t value) { output.push_back(static_cast(value & 0xFFU)); output.push_back(static_cast((value >> 8) & 0xFFU)); output.push_back(static_cast((value >> 16) & 0xFFU)); output.push_back(static_cast((value >> 24) & 0xFFU)); } void append_be_u32(std::vector& output, std::uint32_t value) { output.push_back(static_cast((value >> 24) & 0xFFU)); output.push_back(static_cast((value >> 16) & 0xFFU)); output.push_back(static_cast((value >> 8) & 0xFFU)); output.push_back(static_cast(value & 0xFFU)); } void append_le_u64(std::vector& output, std::uint64_t value) { for (int index = 0; index < 8; ++index) { output.push_back(static_cast((value >> (index * 8)) & 0xFFU)); } } std::vector make_mp4_atom(const std::array& type, const std::vector& payload) { std::vector atom; append_be_u32(atom, static_cast(8 + payload.size())); atom.insert(atom.end(), type.begin(), type.end()); atom.insert(atom.end(), payload.begin(), payload.end()); return atom; } std::vector make_mp4_data_atom(const std::string& value) { std::vector payload; append_be_u32(payload, 1); // UTF-8 data type append_be_u32(payload, 0); // locale payload.insert(payload.end(), value.begin(), value.end()); return make_mp4_atom({'d', 'a', 't', 'a'}, payload); } std::vector make_mp4_metadata_atom(const std::array& key, const std::string& value) { return make_mp4_atom(key, make_mp4_data_atom(value)); } void write_fixed_id3v1_field(std::array& tag, std::size_t offset, std::size_t length, const std::string& value) { const std::size_t copy_length = std::min(length, value.size()); std::copy_n(value.begin(), copy_length, tag.begin() + static_cast(offset)); } std::vector make_mp3_with_id3v1() { std::vector bytes(64, 0); std::array tag{}; tag[0] = 'T'; tag[1] = 'A'; tag[2] = 'G'; write_fixed_id3v1_field(tag, 3, 30, "Celestial Echoes"); write_fixed_id3v1_field(tag, 33, 30, "Synth Unit"); write_fixed_id3v1_field(tag, 63, 30, "Moon Tides"); write_fixed_id3v1_field(tag, 93, 4, "2024"); bytes.insert(bytes.end(), tag.begin(), tag.end()); return bytes; } std::vector make_vorbis_comment_payload(const std::vector& comments) { std::vector payload; const std::string vendor = "AIFileSorterTests"; append_le_u32(payload, static_cast(vendor.size())); payload.insert(payload.end(), vendor.begin(), vendor.end()); append_le_u32(payload, static_cast(comments.size())); for (const auto& comment : comments) { append_le_u32(payload, static_cast(comment.size())); payload.insert(payload.end(), comment.begin(), comment.end()); } return payload; } std::vector make_flac_with_vorbis_comments() { const std::vector comments = make_vorbis_comment_payload({ "TITLE=Celestial Echoes Continued", "ARTIST=Synth Unit", "ALBUM=Moon Tides", "DATE=2023-04-09" }); std::vector bytes; bytes.insert(bytes.end(), {'f', 'L', 'a', 'C'}); bytes.push_back(0x84); // last metadata block + vorbis comment block type bytes.push_back(static_cast((comments.size() >> 16) & 0xFFU)); bytes.push_back(static_cast((comments.size() >> 8) & 0xFFU)); bytes.push_back(static_cast(comments.size() & 0xFFU)); bytes.insert(bytes.end(), comments.begin(), comments.end()); return bytes; } std::vector make_opus_with_tags() { std::vector opus_head = { 'O', 'p', 'u', 's', 'H', 'e', 'a', 'd', 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; std::vector opus_tags = {'O', 'p', 'u', 's', 'T', 'a', 'g', 's'}; const std::vector comments = make_vorbis_comment_payload({ "TITLE=Celestial Echoes 2", "ARTIST=Synth Unit", "ALBUM=Celestial Sets", "YEAR=2022" }); opus_tags.insert(opus_tags.end(), comments.begin(), comments.end()); REQUIRE(opus_head.size() < 255); REQUIRE(opus_tags.size() < 255); std::vector bytes; bytes.insert(bytes.end(), {'O', 'g', 'g', 'S'}); bytes.push_back(0); // version bytes.push_back(0x02); // BOS page append_le_u64(bytes, 0); append_le_u32(bytes, 1); // serial number append_le_u32(bytes, 0); // sequence number append_le_u32(bytes, 0); // checksum (not validated by parser) bytes.push_back(2); // segment count bytes.push_back(static_cast(opus_head.size())); bytes.push_back(static_cast(opus_tags.size())); bytes.insert(bytes.end(), opus_head.begin(), opus_head.end()); bytes.insert(bytes.end(), opus_tags.begin(), opus_tags.end()); return bytes; } std::vector make_mp4_with_ilst_tags() { std::vector ilst_payload; const std::uint8_t copyright = 0xA9; const std::array title_tag = {copyright, 'n', 'a', 'm'}; const std::array artist_tag = {copyright, 'A', 'R', 'T'}; const std::array album_tag = {copyright, 'a', 'l', 'b'}; const std::array date_tag = {copyright, 'd', 'a', 'y'}; const auto title_atom = make_mp4_metadata_atom(title_tag, "Celestial Echoes Video"); ilst_payload.insert(ilst_payload.end(), title_atom.begin(), title_atom.end()); const auto artist_atom = make_mp4_metadata_atom(artist_tag, "Synth Unit"); ilst_payload.insert(ilst_payload.end(), artist_atom.begin(), artist_atom.end()); const auto album_atom = make_mp4_metadata_atom(album_tag, "Moon Tides Live"); ilst_payload.insert(ilst_payload.end(), album_atom.begin(), album_atom.end()); const auto date_atom = make_mp4_metadata_atom(date_tag, "2021-06-30"); ilst_payload.insert(ilst_payload.end(), date_atom.begin(), date_atom.end()); const auto ilst_atom = make_mp4_atom({'i', 'l', 's', 't'}, ilst_payload); std::vector meta_payload(4, 0); // version + flags meta_payload.insert(meta_payload.end(), ilst_atom.begin(), ilst_atom.end()); const auto meta_atom = make_mp4_atom({'m', 'e', 't', 'a'}, meta_payload); const auto udta_atom = make_mp4_atom({'u', 'd', 't', 'a'}, meta_atom); const auto moov_atom = make_mp4_atom({'m', 'o', 'o', 'v'}, udta_atom); std::vector ftyp_payload = { 'i', 's', 'o', 'm', 0, 0, 0, 1, 'i', 's', 'o', 'm', 'm', 'p', '4', '1' }; const auto ftyp_atom = make_mp4_atom({'f', 't', 'y', 'p'}, ftyp_payload); std::vector file; file.insert(file.end(), ftyp_atom.begin(), ftyp_atom.end()); file.insert(file.end(), moov_atom.begin(), moov_atom.end()); return file; } } // namespace TEST_CASE("MediaRenameMetadataService extracts MP3 ID3v1 metadata when MediaInfo is unavailable") { TempMediaFile file("raw_track.mp3"); write_binary_file(file.path(), make_mp3_with_id3v1()); MediaRenameMetadataService service; const auto suggestion = service.suggest_name(file.path()); REQUIRE(suggestion.has_value()); REQUIRE(*suggestion == "2024_synth_unit_moon_tides_celestial_echoes.mp3"); } TEST_CASE("MediaRenameMetadataService extracts FLAC Vorbis comments when MediaInfo is unavailable") { TempMediaFile file("raw_track.flac"); write_binary_file(file.path(), make_flac_with_vorbis_comments()); MediaRenameMetadataService service; const auto suggestion = service.suggest_name(file.path()); REQUIRE(suggestion.has_value()); REQUIRE(*suggestion == "2023_synth_unit_moon_tides_celestial_echoes_continued.flac"); } TEST_CASE("MediaRenameMetadataService extracts OpusTags when MediaInfo is unavailable") { TempMediaFile file("raw_track.opus"); write_binary_file(file.path(), make_opus_with_tags()); MediaRenameMetadataService service; const auto suggestion = service.suggest_name(file.path()); REQUIRE(suggestion.has_value()); REQUIRE(*suggestion == "2022_synth_unit_celestial_sets_celestial_echoes_2.opus"); } TEST_CASE("MediaRenameMetadataService extracts MP4 tags when MediaInfo is unavailable") { TempMediaFile file("video_clip.mp4"); write_binary_file(file.path(), make_mp4_with_ilst_tags()); MediaRenameMetadataService service; const auto suggestion = service.suggest_name(file.path()); REQUIRE(suggestion.has_value()); REQUIRE(*suggestion == "2021_synth_unit_moon_tides_live_celestial_echoes_video.mp4"); } #endif ================================================ FILE: tests/unit/test_review_dialog_rename_gate.cpp ================================================ #include #include "CategorizationDialog.hpp" #include "TestHelpers.hpp" #include "Types.hpp" #include #include #ifndef _WIN32 namespace { QCheckBox* find_checkbox_by_text(QWidget& dialog, const QString& text) { const auto boxes = dialog.findChildren(); for (auto* box : boxes) { if (box && box->text() == text) { return box; } } return nullptr; } std::vector make_sample_files(const std::string& base_dir) { CategorizedFile image; image.file_path = base_dir; image.file_name = "photo.png"; image.type = FileType::File; image.category = "Photos"; image.suggested_name = "sunset.png"; CategorizedFile document; document.file_path = base_dir; document.file_name = "report.pdf"; document.type = FileType::File; document.category = "Docs"; document.suggested_name = "report-2024.pdf"; return {image, document}; } } // namespace TEST_CASE("Review dialog rename-only toggles disabled when renames are not allowed") { EnvVarGuard platform_guard("QT_QPA_PLATFORM", "offscreen"); QtAppContext qt_context; TempDir base_dir; const auto files = make_sample_files(base_dir.path().string()); TempDir undo_dir_disabled; CategorizationDialog dialog_disabled(nullptr, true, undo_dir_disabled.path().string()); QTimer::singleShot(0, &dialog_disabled, &QDialog::accept); dialog_disabled.show_results(files, std::string(), false, false, false); QCheckBox* image_disabled = find_checkbox_by_text( dialog_disabled, QStringLiteral("Do not categorize picture files (only rename)")); QCheckBox* document_disabled = find_checkbox_by_text( dialog_disabled, QStringLiteral("Do not categorize document files (only rename)")); REQUIRE(image_disabled != nullptr); REQUIRE(document_disabled != nullptr); CHECK_FALSE(image_disabled->isEnabled()); CHECK_FALSE(document_disabled->isEnabled()); TempDir undo_dir_enabled; CategorizationDialog dialog_enabled(nullptr, true, undo_dir_enabled.path().string()); QTimer::singleShot(0, &dialog_enabled, &QDialog::accept); dialog_enabled.show_results(files, std::string(), false, true, true); QCheckBox* image_enabled = find_checkbox_by_text( dialog_enabled, QStringLiteral("Do not categorize picture files (only rename)")); QCheckBox* document_enabled = find_checkbox_by_text( dialog_enabled, QStringLiteral("Do not categorize document files (only rename)")); REQUIRE(image_enabled != nullptr); REQUIRE(document_enabled != nullptr); CHECK(image_enabled->isEnabled()); CHECK(document_enabled->isEnabled()); } #endif ================================================ FILE: tests/unit/test_settings_image_options.cpp ================================================ #include #include "Settings.hpp" #include "TestHelpers.hpp" #include "Utils.hpp" #include #include namespace { void create_visual_llm_files() { const std::string model_url = "https://example.com/llava-model.gguf"; const std::string mmproj_url = "https://example.com/mmproj-model-f16.gguf"; const std::filesystem::path model_path = Utils::make_default_path_to_file_from_download_url(model_url); const std::filesystem::path mmproj_path = Utils::make_default_path_to_file_from_download_url(mmproj_url); std::filesystem::create_directories(model_path.parent_path()); std::ofstream(model_path.string(), std::ios::binary).put('x'); std::ofstream(mmproj_path.string(), std::ios::binary).put('x'); } } // namespace TEST_CASE("Settings defaults image analysis off even when visual LLM files exist") { TempDir temp; EnvVarGuard home_guard("HOME", temp.path().string()); #ifdef _WIN32 EnvVarGuard appdata_guard("APPDATA", temp.path().string()); #endif EnvVarGuard config_guard("AI_FILE_SORTER_CONFIG_DIR", temp.path().string()); EnvVarGuard model_guard("LLAVA_MODEL_URL", std::string("https://example.com/llava-model.gguf")); EnvVarGuard mmproj_guard("LLAVA_MMPROJ_URL", std::string("https://example.com/mmproj-model-f16.gguf")); create_visual_llm_files(); Settings settings; const bool loaded = settings.load(); REQUIRE_FALSE(loaded); REQUIRE_FALSE(settings.get_analyze_images_by_content()); REQUIRE_FALSE(settings.get_offer_rename_images()); } TEST_CASE("Settings defaults image analysis off when visual LLM files are missing") { TempDir temp; EnvVarGuard home_guard("HOME", temp.path().string()); #ifdef _WIN32 EnvVarGuard appdata_guard("APPDATA", temp.path().string()); #endif EnvVarGuard config_guard("AI_FILE_SORTER_CONFIG_DIR", temp.path().string()); EnvVarGuard model_guard("LLAVA_MODEL_URL", std::string("https://example.com/llava-model.gguf")); EnvVarGuard mmproj_guard("LLAVA_MMPROJ_URL", std::string("https://example.com/mmproj-model-f16.gguf")); Settings settings; const bool loaded = settings.load(); REQUIRE_FALSE(loaded); REQUIRE_FALSE(settings.get_analyze_images_by_content()); REQUIRE_FALSE(settings.get_offer_rename_images()); } TEST_CASE("Settings enforces rename-only implies offer rename") { TempDir temp; EnvVarGuard home_guard("HOME", temp.path().string()); #ifdef _WIN32 EnvVarGuard appdata_guard("APPDATA", temp.path().string()); #endif EnvVarGuard config_guard("AI_FILE_SORTER_CONFIG_DIR", temp.path().string()); EnvVarGuard model_guard("LLAVA_MODEL_URL", std::string("https://example.com/llava-model.gguf")); EnvVarGuard mmproj_guard("LLAVA_MMPROJ_URL", std::string("https://example.com/mmproj-model-f16.gguf")); Settings settings; settings.set_analyze_images_by_content(true); settings.set_offer_rename_images(false); settings.set_rename_images_only(true); settings.set_process_images_only(true); REQUIRE(settings.save()); Settings reloaded; REQUIRE(reloaded.load()); REQUIRE(reloaded.get_offer_rename_images()); REQUIRE(reloaded.get_rename_images_only()); REQUIRE(reloaded.get_process_images_only()); } TEST_CASE("Settings persists options group expansion state") { TempDir temp; EnvVarGuard home_guard("HOME", temp.path().string()); #ifdef _WIN32 EnvVarGuard appdata_guard("APPDATA", temp.path().string()); #endif EnvVarGuard config_guard("AI_FILE_SORTER_CONFIG_DIR", temp.path().string()); Settings settings; settings.set_image_options_expanded(true); settings.set_document_options_expanded(false); REQUIRE(settings.save()); Settings reloaded; REQUIRE(reloaded.load()); REQUIRE(reloaded.get_image_options_expanded()); REQUIRE_FALSE(reloaded.get_document_options_expanded()); } TEST_CASE("Settings persists image EXIF date/place rename toggle") { TempDir temp; EnvVarGuard home_guard("HOME", temp.path().string()); #ifdef _WIN32 EnvVarGuard appdata_guard("APPDATA", temp.path().string()); #endif EnvVarGuard config_guard("AI_FILE_SORTER_CONFIG_DIR", temp.path().string()); Settings settings; settings.set_offer_rename_images(true); settings.set_add_image_date_place_to_filename(true); REQUIRE(settings.save()); Settings reloaded; REQUIRE(reloaded.load()); REQUIRE(reloaded.get_offer_rename_images()); REQUIRE(reloaded.get_add_image_date_place_to_filename()); } TEST_CASE("Settings defaults audio/video metadata rename toggle to enabled") { TempDir temp; EnvVarGuard home_guard("HOME", temp.path().string()); #ifdef _WIN32 EnvVarGuard appdata_guard("APPDATA", temp.path().string()); #endif EnvVarGuard config_guard("AI_FILE_SORTER_CONFIG_DIR", temp.path().string()); Settings settings; const bool loaded = settings.load(); REQUIRE_FALSE(loaded); REQUIRE(settings.get_add_audio_video_metadata_to_filename()); } TEST_CASE("Settings persists audio/video metadata rename toggle") { TempDir temp; EnvVarGuard home_guard("HOME", temp.path().string()); #ifdef _WIN32 EnvVarGuard appdata_guard("APPDATA", temp.path().string()); #endif EnvVarGuard config_guard("AI_FILE_SORTER_CONFIG_DIR", temp.path().string()); Settings settings; settings.set_add_audio_video_metadata_to_filename(false); REQUIRE(settings.save()); Settings reloaded; REQUIRE(reloaded.load()); REQUIRE_FALSE(reloaded.get_add_audio_video_metadata_to_filename()); } TEST_CASE("Settings persists image date-to-category toggle") { TempDir temp; EnvVarGuard home_guard("HOME", temp.path().string()); #ifdef _WIN32 EnvVarGuard appdata_guard("APPDATA", temp.path().string()); #endif EnvVarGuard config_guard("AI_FILE_SORTER_CONFIG_DIR", temp.path().string()); Settings settings; settings.set_analyze_images_by_content(true); settings.set_add_image_date_to_category(true); REQUIRE(settings.save()); Settings reloaded; REQUIRE(reloaded.load()); REQUIRE(reloaded.get_analyze_images_by_content()); REQUIRE(reloaded.get_add_image_date_to_category()); } ================================================ FILE: tests/unit/test_support_prompt.cpp ================================================ #include #include "MainApp.hpp" #include "MainAppTestAccess.hpp" #include "SupportCodeManager.hpp" #include "TestHelpers.hpp" #include "Settings.hpp" #include #include namespace { struct TestEnvironment { TempDir home_dir; EnvVarGuard home_guard; EnvVarGuard config_guard; Settings settings; bool prompt_state{false}; TestEnvironment() : home_dir(), home_guard("HOME", home_dir.path().string()), config_guard("AI_FILE_SORTER_CONFIG_DIR", (home_dir.path() / ".config").string()), settings() { std::filesystem::create_directories(home_dir.path() / ".config" / "AIFileSorter"); settings.load(); } }; } // namespace static void run_support_prompt_case(MainAppTestAccess::SimulatedSupportResult response) { TestEnvironment env; std::vector totals; auto callback = [&](int total) { totals.push_back(total); return response; }; REQUIRE(env.settings.get_total_categorized_files() == 0); const int base_threshold = env.settings.get_next_support_prompt_threshold(); REQUIRE(base_threshold > 0); const int first_step = std::max(1, base_threshold / 2); const int second_step = base_threshold - first_step; MainAppTestAccess::simulate_support_prompt(env.settings, env.prompt_state, first_step, callback); CHECK(env.settings.get_total_categorized_files() == first_step); CHECK(totals.empty()); MainAppTestAccess::simulate_support_prompt(env.settings, env.prompt_state, second_step, callback); CHECK(env.settings.get_total_categorized_files() == base_threshold); REQUIRE(totals.size() == 1); CHECK(totals.front() == base_threshold); const int next_threshold = env.settings.get_next_support_prompt_threshold(); CHECK(next_threshold == base_threshold + 50); const int increment = next_threshold - base_threshold; if (increment > 1) { MainAppTestAccess::simulate_support_prompt(env.settings, env.prompt_state, increment - 1, callback); CHECK(totals.size() == 1); MainAppTestAccess::simulate_support_prompt(env.settings, env.prompt_state, 1, callback); } else { MainAppTestAccess::simulate_support_prompt(env.settings, env.prompt_state, 1, callback); } CHECK(env.settings.get_total_categorized_files() == base_threshold + increment); REQUIRE(totals.size() == 2); CHECK(totals.back() == base_threshold + increment); CHECK(env.settings.get_next_support_prompt_threshold() == next_threshold + 50); } TEST_CASE("Support prompt thresholds advance in fixed 50-file steps") { run_support_prompt_case(MainAppTestAccess::SimulatedSupportResult::NotSure); } TEST_CASE("Zero categorized increments do not change totals or trigger prompts") { TestEnvironment env; bool callback_invoked = false; const int base_threshold = env.settings.get_next_support_prompt_threshold(); MainAppTestAccess::simulate_support_prompt( env.settings, env.prompt_state, 0, [&](int) { callback_invoked = true; return MainAppTestAccess::SimulatedSupportResult::NotSure; }); CHECK(env.settings.get_total_categorized_files() == 0); CHECK_FALSE(callback_invoked); CHECK(env.settings.get_next_support_prompt_threshold() == base_threshold); } TEST_CASE("Donation code redemption suppresses future support prompts") { TestEnvironment env; SupportCodeManager support_codes(std::filesystem::path(env.settings.get_config_dir())); REQUIRE_FALSE(support_codes.is_prompt_permanently_disabled()); REQUIRE_FALSE(SupportCodeManager::is_valid_code("not-a-real-code")); REQUIRE(support_codes.force_disable_prompt_for_testing()); CHECK(support_codes.is_prompt_permanently_disabled()); bool callback_invoked = false; const int threshold = env.settings.get_next_support_prompt_threshold(); MainAppTestAccess::simulate_support_prompt( env.settings, env.prompt_state, threshold, [&](int) { callback_invoked = true; return MainAppTestAccess::SimulatedSupportResult::NotSure; }); CHECK_FALSE(callback_invoked); } TEST_CASE("Support response creates suppression state and stops future prompts") { TestEnvironment env; int callback_count = 0; const int threshold = env.settings.get_next_support_prompt_threshold(); MainAppTestAccess::simulate_support_prompt( env.settings, env.prompt_state, threshold, [&](int) { ++callback_count; return MainAppTestAccess::SimulatedSupportResult::Support; }); CHECK(callback_count == 1); CHECK(SupportCodeManager(std::filesystem::path(env.settings.get_config_dir())) .is_prompt_permanently_disabled()); CHECK(env.settings.get_next_support_prompt_threshold() == threshold); MainAppTestAccess::simulate_support_prompt( env.settings, env.prompt_state, threshold, [&](int) { ++callback_count; return MainAppTestAccess::SimulatedSupportResult::NotSure; }); CHECK(callback_count == 1); } ================================================ FILE: tests/unit/test_ui_translator.cpp ================================================ #include #include "Language.hpp" #include "Settings.hpp" #include "TestHelpers.hpp" #include "UiTranslator.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef _WIN32 namespace { struct UiTranslatorTestHarness { EnvVarGuard platform_guard{"QT_QPA_PLATFORM", "offscreen"}; QtAppContext qt_context{}; Settings settings{}; QMainWindow window{}; QPointer path_label{new QLabel(&window)}; QPointer browse_button{new QPushButton(&window)}; QPointer analyze_button{new QPushButton(&window)}; QPointer subcategories_checkbox{new QCheckBox(&window)}; QPointer style_heading{new QLabel(&window)}; QPointer style_refined{new QRadioButton(&window)}; QPointer style_consistent{new QRadioButton(&window)}; QPointer use_whitelist{new QCheckBox(&window)}; QPointer whitelist_selector{new QComboBox(&window)}; QPointer files_checkbox{new QCheckBox(&window)}; QPointer directories_checkbox{new QCheckBox(&window)}; QPointer include_subdirectories_checkbox{new QCheckBox(&window)}; QPointer analyze_images_checkbox{new QCheckBox(&window)}; QPointer process_images_only_checkbox{new QCheckBox(&window)}; QPointer add_image_date_to_category_checkbox{new QCheckBox(&window)}; QPointer add_image_date_place_to_filename_checkbox{new QCheckBox(&window)}; QPointer add_audio_video_metadata_to_filename_checkbox{new QCheckBox(&window)}; QPointer offer_rename_images_checkbox{new QCheckBox(&window)}; QPointer rename_images_only_checkbox{new QCheckBox(&window)}; QPointer image_options_toggle_button{new QToolButton(&window)}; QPointer analyze_documents_checkbox{new QCheckBox(&window)}; QPointer process_documents_only_checkbox{new QCheckBox(&window)}; QPointer offer_rename_documents_checkbox{new QCheckBox(&window)}; QPointer rename_documents_only_checkbox{new QCheckBox(&window)}; QPointer add_document_date_to_category_checkbox{new QCheckBox(&window)}; QPointer document_options_toggle_button{new QToolButton(&window)}; QPointer tree_model{new QStandardItemModel(0, 5, &window)}; QMenu* file_menu = new QMenu(&window); QMenu* edit_menu = new QMenu(&window); QMenu* view_menu = new QMenu(&window); QMenu* settings_menu = new QMenu(&window); QMenu* development_menu = new QMenu(&window); QMenu* development_settings_menu = new QMenu(&window); QMenu* language_menu = new QMenu(&window); QMenu* category_language_menu = new QMenu(&window); QMenu* help_menu = new QMenu(&window); QAction* file_quit_action = new QAction(&window); QAction* run_benchmark_action = new QAction(&window); QAction* copy_action = new QAction(&window); QAction* cut_action = new QAction(&window); QAction* undo_last_run_action = new QAction(&window); QAction* paste_action = new QAction(&window); QAction* delete_action = new QAction(&window); QAction* toggle_explorer_action = new QAction(&window); QAction* toggle_llm_action = new QAction(&window); QAction* manage_whitelists_action = new QAction(&window); QAction* development_prompt_logging_action = new QAction(&window); QAction* consistency_pass_action = new QAction(&window); QAction* english_action = new QAction(&window); QAction* dutch_action = new QAction(&window); QAction* french_action = new QAction(&window); QAction* german_action = new QAction(&window); QAction* italian_action = new QAction(&window); QAction* spanish_action = new QAction(&window); QAction* turkish_action = new QAction(&window); QAction* korean_action = new QAction(&window); QAction* category_language_english = new QAction(&window); QAction* category_language_french = new QAction(&window); QAction* category_language_german = new QAction(&window); QAction* category_language_italian = new QAction(&window); QAction* category_language_dutch = new QAction(&window); QAction* category_language_polish = new QAction(&window); QAction* category_language_portuguese = new QAction(&window); QAction* category_language_spanish = new QAction(&window); QAction* category_language_turkish = new QAction(&window); QAction* about_action = new QAction(&window); QAction* about_qt_action = new QAction(&window); QAction* about_agpl_action = new QAction(&window); QAction* support_project_action = new QAction(&window); QActionGroup* language_group = new QActionGroup(&window); QActionGroup* category_language_group = new QActionGroup(&window); QPointer file_explorer_dock{new QDockWidget(&window)}; UiTranslator translator; UiTranslator::State state{.analysis_in_progress = false, .stop_analysis_requested = false, .status_is_ready = true}; UiTranslatorTestHarness() : translator(build_deps()) { settings.set_language(Language::French); setup_tree_model(); setup_language_actions(); } void setup_tree_model() { tree_model->setRowCount(1); auto* type_item = new QStandardItem(); type_item->setData(QStringLiteral("D"), Qt::UserRole); tree_model->setItem(0, 1, type_item); auto* status_item = new QStandardItem(); status_item->setData(QStringLiteral("ready"), Qt::UserRole); tree_model->setItem(0, 4, status_item); } void setup_language_actions() { language_group->setExclusive(true); english_action->setCheckable(true); english_action->setData(static_cast(Language::English)); dutch_action->setCheckable(true); dutch_action->setData(static_cast(Language::Dutch)); french_action->setCheckable(true); french_action->setData(static_cast(Language::French)); german_action->setCheckable(true); german_action->setData(static_cast(Language::German)); italian_action->setCheckable(true); italian_action->setData(static_cast(Language::Italian)); spanish_action->setCheckable(true); turkish_action->setCheckable(true); spanish_action->setData(static_cast(Language::Spanish)); turkish_action->setData(static_cast(Language::Turkish)); korean_action->setCheckable(true); korean_action->setData(static_cast(Language::Korean)); language_group->addAction(english_action); language_group->addAction(dutch_action); language_group->addAction(french_action); language_group->addAction(german_action); language_group->addAction(italian_action); language_group->addAction(spanish_action); language_group->addAction(turkish_action); language_group->addAction(korean_action); } UiTranslator::Dependencies build_deps() { return UiTranslator::Dependencies{ .window = window, .primary = UiTranslator::PrimaryControls{ path_label, browse_button, analyze_button, subcategories_checkbox, style_heading, style_refined, style_consistent, use_whitelist, whitelist_selector, files_checkbox, directories_checkbox, include_subdirectories_checkbox, analyze_images_checkbox, process_images_only_checkbox, add_image_date_to_category_checkbox, add_image_date_place_to_filename_checkbox, add_audio_video_metadata_to_filename_checkbox, offer_rename_images_checkbox, rename_images_only_checkbox, image_options_toggle_button, analyze_documents_checkbox, process_documents_only_checkbox, offer_rename_documents_checkbox, rename_documents_only_checkbox, add_document_date_to_category_checkbox, document_options_toggle_button}, .tree_model = tree_model, .menus = UiTranslator::MenuControls{ file_menu, edit_menu, view_menu, settings_menu, development_menu, development_settings_menu, language_menu, category_language_menu, help_menu}, .actions = UiTranslator::ActionControls{ file_quit_action, run_benchmark_action, copy_action, cut_action, undo_last_run_action, paste_action, delete_action, toggle_explorer_action, toggle_llm_action, manage_whitelists_action, development_prompt_logging_action, consistency_pass_action, english_action, dutch_action, french_action, german_action, italian_action, spanish_action, turkish_action, korean_action, category_language_english, category_language_french, category_language_german, category_language_italian, category_language_dutch, category_language_polish, category_language_portuguese, category_language_spanish, category_language_turkish, about_action, about_qt_action, about_agpl_action, support_project_action}, .language = UiTranslator::LanguageControls{ language_group, english_action, dutch_action, french_action, german_action, italian_action, spanish_action, turkish_action, korean_action}, .category_language = UiTranslator::CategoryLanguageControls{ category_language_group, category_language_dutch, category_language_english, category_language_french, category_language_german, category_language_italian, category_language_polish, category_language_portuguese, category_language_spanish, category_language_turkish}, .file_explorer_dock = file_explorer_dock, .settings = settings, .translator = [](const char* source) { return QString::fromUtf8(source); } }; } }; void verify_primary_controls(const UiTranslatorTestHarness& h) { REQUIRE(h.path_label->text() == QStringLiteral("Folder:")); REQUIRE(h.browse_button->text() == QStringLiteral("Browse…")); REQUIRE(h.analyze_button->text() == QStringLiteral("Analyze folder")); REQUIRE(h.subcategories_checkbox->text() == QStringLiteral("Use subcategories")); REQUIRE(h.style_heading->text() == QStringLiteral("Categorization type")); REQUIRE(h.style_refined->text() == QStringLiteral("More refined")); REQUIRE(h.style_consistent->text() == QStringLiteral("More consistent")); REQUIRE(h.use_whitelist->text() == QStringLiteral("Use a whitelist")); REQUIRE(h.files_checkbox->text() == QStringLiteral("Categorize files")); REQUIRE(h.directories_checkbox->text() == QStringLiteral("Categorize folders")); REQUIRE(h.include_subdirectories_checkbox->text() == QStringLiteral("Scan subfolders")); REQUIRE(h.analyze_images_checkbox->text() == QStringLiteral("Analyze picture files by content (can be slow)")); REQUIRE(h.process_images_only_checkbox->text() == QStringLiteral("Process picture files only (ignore any other files)")); REQUIRE(h.add_image_date_to_category_checkbox->text() == QStringLiteral("Add image creation date (if available) to category name")); REQUIRE(h.add_image_date_place_to_filename_checkbox->text() == QStringLiteral("Add photo date and place to filename (if available)")); REQUIRE(h.add_audio_video_metadata_to_filename_checkbox->text() == QStringLiteral("Add audio/video metadata to file name (if available)")); REQUIRE(h.offer_rename_images_checkbox->text() == QStringLiteral("Offer to rename picture files")); REQUIRE(h.rename_images_only_checkbox->text() == QStringLiteral("Do not categorize picture files (only rename)")); REQUIRE(h.analyze_documents_checkbox->text() == QStringLiteral("Analyze document files by content")); REQUIRE(h.process_documents_only_checkbox->text() == QStringLiteral("Process document files only (ignore any other files)")); REQUIRE(h.offer_rename_documents_checkbox->text() == QStringLiteral("Offer to rename document files")); REQUIRE(h.rename_documents_only_checkbox->text() == QStringLiteral("Do not categorize document files (only rename)")); REQUIRE(h.add_document_date_to_category_checkbox->text() == QStringLiteral("Add document creation date (if available) to category name")); } void verify_menus_and_actions(const UiTranslatorTestHarness& h) { REQUIRE(h.file_menu->title() == QStringLiteral("&File")); REQUIRE(h.settings_menu->title() == QStringLiteral("&Settings")); REQUIRE(h.run_benchmark_action->text() == QStringLiteral("System compatibility check…")); REQUIRE(h.toggle_llm_action->text() == QStringLiteral("Select &LLM…")); REQUIRE(h.manage_whitelists_action->text() == QStringLiteral("Manage category whitelists…")); REQUIRE(h.development_prompt_logging_action->text() == QStringLiteral("Log prompts and responses to stdout")); const QString help_title = h.help_menu->title(); REQUIRE(help_title.endsWith(QStringLiteral("&Help"))); REQUIRE(help_title.startsWith(QString(QChar(0x200B)))); } void verify_tree_and_status(const UiTranslatorTestHarness& h) { REQUIRE(h.file_explorer_dock->windowTitle() == QStringLiteral("File Explorer")); REQUIRE(h.tree_model->horizontalHeaderItem(0)->text() == QStringLiteral("File")); REQUIRE(h.tree_model->item(0, 1)->text() == QStringLiteral("Directory")); REQUIRE(h.tree_model->item(0, 4)->text() == QStringLiteral("Ready")); REQUIRE_FALSE(h.english_action->isChecked()); REQUIRE(h.french_action->isChecked()); REQUIRE(h.window.statusBar()->currentMessage() == QStringLiteral("Ready")); } } // namespace TEST_CASE("UiTranslator updates menus, actions, and controls") { UiTranslatorTestHarness h; h.translator.retranslate_all(h.state); verify_primary_controls(h); verify_menus_and_actions(h); verify_tree_and_status(h); } #endif ================================================ FILE: tests/unit/test_update_feed.cpp ================================================ #include #include "Settings.hpp" #include "UpdateFeed.hpp" #include "UpdateInstaller.hpp" #include "UpdateInstallerTestAccess.hpp" #include "TestHelpers.hpp" #include #include #include #include #include #include namespace { std::string sha256_hex(std::string_view payload) { QCryptographicHash hash(QCryptographicHash::Sha256); hash.addData(QByteArrayView(payload.data(), static_cast(payload.size()))); return hash.result().toHex().toStdString(); } std::string read_file(const std::filesystem::path& path) { std::ifstream in(path, std::ios::binary); return std::string(std::istreambuf_iterator(in), std::istreambuf_iterator()); } void create_zip_archive(const std::filesystem::path& archive_path, const std::vector>& entries) { int error_code = 0; zip_t* archive = zip_open(archive_path.string().c_str(), ZIP_CREATE | ZIP_TRUNCATE, &error_code); REQUIRE(archive != nullptr); for (const auto& [name, payload] : entries) { zip_source_t* source = zip_source_buffer(archive, payload.data(), static_cast(payload.size()), 0); REQUIRE(source != nullptr); const zip_int64_t index = zip_file_add(archive, name.c_str(), source, ZIP_FL_OVERWRITE | ZIP_FL_ENC_UTF_8); REQUIRE(index >= 0); } REQUIRE(zip_close(archive) == 0); } } // namespace TEST_CASE("UpdateFeed selects the correct platform stream") { const std::string json = R"json( { "update": { "windows": { "current_version": "1.8.0", "min_version": "1.7.0", "download_url": "https://filesorter.app/windows", "installer_url": "https://filesorter.app/aifs-1.8.0.exe", "installer_sha256": "ABCDEF" }, "macos": { "current_version": "1.8.1", "min_version": "1.6.0", "download_url": "https://filesorter.app/macos" }, "linux": { "current_version": "1.8.2", "min_version": "1.5.0", "download_url": "https://filesorter.app/linux" } } } )json"; const auto windows = UpdateFeed::parse_for_platform(json, UpdateFeed::Platform::Windows); REQUIRE(windows.has_value()); CHECK(windows->current_version == "1.8.0"); CHECK(windows->min_version == "1.7.0"); CHECK(windows->download_url == "https://filesorter.app/windows"); CHECK(windows->installer_url == "https://filesorter.app/aifs-1.8.0.exe"); CHECK(windows->installer_sha256 == "abcdef"); const auto macos = UpdateFeed::parse_for_platform(json, UpdateFeed::Platform::MacOS); REQUIRE(macos.has_value()); CHECK(macos->current_version == "1.8.1"); CHECK(macos->download_url == "https://filesorter.app/macos"); CHECK(macos->installer_url.empty()); const auto linux = UpdateFeed::parse_for_platform(json, UpdateFeed::Platform::Linux); REQUIRE(linux.has_value()); CHECK(linux->current_version == "1.8.2"); CHECK(linux->download_url == "https://filesorter.app/linux"); } TEST_CASE("UpdateFeed falls back to the legacy single-stream schema") { const std::string json = R"json( { "update": { "current_version": "1.7.1", "min_version": "1.6.0", "download_url": "https://filesorter.app/download" } } )json"; const auto info = UpdateFeed::parse_for_platform(json, UpdateFeed::Platform::Windows); REQUIRE(info.has_value()); CHECK(info->current_version == "1.7.1"); CHECK(info->min_version == "1.6.0"); CHECK(info->download_url == "https://filesorter.app/download"); } TEST_CASE("UpdateInstaller downloads, verifies, and reuses a cached installer") { TempDir tmp; EnvVarGuard config_root("AI_FILE_SORTER_CONFIG_DIR", tmp.path().string()); Settings settings; const std::string payload = "signed-installer-payload"; const std::string expected_sha256 = sha256_hex(payload); int download_calls = 0; std::filesystem::path prepared_path; std::filesystem::path launched_path; UpdateInstaller installer( settings, [&](const std::string&, const std::filesystem::path& destination_path, UpdateInstaller::ProgressCallback progress_cb, UpdateInstaller::CancelCheck) { ++download_calls; prepared_path = destination_path; if (progress_cb) { progress_cb(0.5, "Downloading"); progress_cb(1.0, "Downloaded"); } std::ofstream out(destination_path, std::ios::binary | std::ios::trunc); out << payload; }, [&](const std::filesystem::path& path) { launched_path = path; return true; }); UpdateInfo info; info.current_version = "1.8.0"; info.installer_url = "https://filesorter.app/downloads/AIFileSorterSetup.exe"; info.installer_sha256 = expected_sha256; const auto first = installer.prepare(info); REQUIRE(first.status == UpdatePreparationResult::Status::Ready); CHECK(download_calls == 1); CHECK(std::filesystem::exists(first.installer_path)); CHECK(first.installer_path.extension() == ".exe"); CHECK(prepared_path.extension() == ".part"); const auto second = installer.prepare(info); REQUIRE(second.status == UpdatePreparationResult::Status::Ready); CHECK(download_calls == 1); CHECK(second.installer_path == first.installer_path); CHECK(installer.launch(second.installer_path)); CHECK(launched_path == second.installer_path); } TEST_CASE("UpdateInstaller rejects installers that fail SHA-256 verification") { TempDir tmp; EnvVarGuard config_root("AI_FILE_SORTER_CONFIG_DIR", tmp.path().string()); Settings settings; UpdateInstaller installer( settings, [&](const std::string&, const std::filesystem::path& destination_path, UpdateInstaller::ProgressCallback, UpdateInstaller::CancelCheck) { std::ofstream out(destination_path, std::ios::binary | std::ios::trunc); out << "tampered"; }); UpdateInfo info; info.current_version = "1.8.0"; info.installer_url = "https://filesorter.app/downloads/AIFileSorterSetup.exe"; info.installer_sha256 = sha256_hex("expected"); const auto result = installer.prepare(info); REQUIRE(result.status == UpdatePreparationResult::Status::Failed); CHECK(result.message.find("SHA-256") != std::string::npos); CHECK(result.installer_path.empty()); } TEST_CASE("UpdateInstaller extracts installer payloads from ZIP update packages") { TempDir tmp; EnvVarGuard config_root("AI_FILE_SORTER_CONFIG_DIR", tmp.path().string()); Settings settings; const std::string installer_payload = "installer-from-zip"; const auto archive_path = tmp.path() / "AIFileSorterSetup.zip"; create_zip_archive(archive_path, {{"nested/AIFileSorterSetup.exe", installer_payload}}); const std::string expected_sha256 = sha256_hex(read_file(archive_path)); int download_calls = 0; UpdateInstaller installer( settings, [&](const std::string&, const std::filesystem::path& destination_path, UpdateInstaller::ProgressCallback, UpdateInstaller::CancelCheck) { ++download_calls; std::filesystem::copy_file( archive_path, destination_path, std::filesystem::copy_options::overwrite_existing); }); UpdateInfo info; info.current_version = "1.8.0"; info.installer_url = "https://filesorter.app/downloads/AIFileSorterSetup.zip"; info.installer_sha256 = expected_sha256; const auto first = installer.prepare(info); REQUIRE(first.status == UpdatePreparationResult::Status::Ready); CHECK(download_calls == 1); CHECK(first.installer_path.extension() == ".exe"); CHECK(first.installer_path.filename() == "AIFileSorterSetup.exe"); CHECK(read_file(first.installer_path) == installer_payload); const auto second = installer.prepare(info); REQUIRE(second.status == UpdatePreparationResult::Status::Ready); CHECK(download_calls == 1); CHECK(second.installer_path == first.installer_path); } TEST_CASE("UpdateInstaller rejects ZIP update packages without an installer payload") { TempDir tmp; EnvVarGuard config_root("AI_FILE_SORTER_CONFIG_DIR", tmp.path().string()); Settings settings; const auto archive_path = tmp.path() / "AIFileSorterSetup.zip"; create_zip_archive(archive_path, {{"README.txt", "no installer here"}}); const std::string expected_sha256 = sha256_hex(read_file(archive_path)); UpdateInstaller installer( settings, [&](const std::string&, const std::filesystem::path& destination_path, UpdateInstaller::ProgressCallback, UpdateInstaller::CancelCheck) { std::filesystem::copy_file( archive_path, destination_path, std::filesystem::copy_options::overwrite_existing); }); UpdateInfo info; info.current_version = "1.8.0"; info.installer_url = "https://filesorter.app/downloads/AIFileSorterSetup.zip"; info.installer_sha256 = expected_sha256; const auto result = installer.prepare(info); REQUIRE(result.status == UpdatePreparationResult::Status::Failed); CHECK(result.message.find("ZIP archive") != std::string::npos); CHECK(result.installer_path.empty()); } TEST_CASE("UpdateInstaller redownloads cached installers that fail verification") { TempDir tmp; EnvVarGuard config_root("AI_FILE_SORTER_CONFIG_DIR", tmp.path().string()); Settings settings; const std::string payload = "fresh-installer-payload"; const std::string expected_sha256 = sha256_hex(payload); int download_calls = 0; UpdateInstaller installer( settings, [&](const std::string&, const std::filesystem::path& destination_path, UpdateInstaller::ProgressCallback, UpdateInstaller::CancelCheck) { ++download_calls; std::ofstream out(destination_path, std::ios::binary | std::ios::trunc); out << payload; }); UpdateInfo info; info.current_version = "1.8.0"; info.installer_url = "https://filesorter.app/downloads/AIFileSorterSetup.exe"; info.installer_sha256 = expected_sha256; const auto first = installer.prepare(info); REQUIRE(first.status == UpdatePreparationResult::Status::Ready); CHECK(download_calls == 1); { std::ofstream out(first.installer_path, std::ios::binary | std::ios::trunc); out << "tampered-cache"; } const auto second = installer.prepare(info); REQUIRE(second.status == UpdatePreparationResult::Status::Ready); CHECK(download_calls == 2); CHECK(second.installer_path == first.installer_path); CHECK(read_file(second.installer_path) == payload); } TEST_CASE("UpdateInstaller reports canceled downloads and removes partial files") { TempDir tmp; EnvVarGuard config_root("AI_FILE_SORTER_CONFIG_DIR", tmp.path().string()); Settings settings; std::filesystem::path partial_path; UpdateInstaller installer( settings, [&](const std::string&, const std::filesystem::path& destination_path, UpdateInstaller::ProgressCallback, UpdateInstaller::CancelCheck cancel_check) { partial_path = destination_path; std::ofstream out(destination_path, std::ios::binary | std::ios::trunc); out << "partial"; if (cancel_check && cancel_check()) { throw UpdateInstaller::DownloadCanceledError(); } }); UpdateInfo info; info.current_version = "1.8.0"; info.installer_url = "https://filesorter.app/downloads/AIFileSorterSetup.exe"; info.installer_sha256 = sha256_hex("payload"); const auto result = installer.prepare(info, {}, []() { return true; }); REQUIRE(result.status == UpdatePreparationResult::Status::Canceled); CHECK(result.message.find("cancel") != std::string::npos); CHECK(result.installer_path.empty()); CHECK_FALSE(partial_path.empty()); CHECK_FALSE(std::filesystem::exists(partial_path)); } TEST_CASE("UpdateInstaller requires installer metadata before preparing") { TempDir tmp; EnvVarGuard config_root("AI_FILE_SORTER_CONFIG_DIR", tmp.path().string()); Settings settings; UpdateInstaller installer(settings); UpdateInfo missing_url; missing_url.current_version = "1.8.0"; missing_url.installer_sha256 = sha256_hex("payload"); const auto missing_url_result = installer.prepare(missing_url); REQUIRE(missing_url_result.status == UpdatePreparationResult::Status::Failed); CHECK(missing_url_result.message.find("URL") != std::string::npos); UpdateInfo missing_sha; missing_sha.current_version = "1.8.0"; missing_sha.installer_url = "https://filesorter.app/downloads/AIFileSorterSetup.exe"; const auto missing_sha_result = installer.prepare(missing_sha); REQUIRE(missing_sha_result.status == UpdatePreparationResult::Status::Failed); CHECK(missing_sha_result.message.find("SHA-256") != std::string::npos); } TEST_CASE("UpdateInstaller builds launch requests for EXE and MSI installers") { const auto exe_request = UpdateInstallerTestAccess::build_launch_request( std::filesystem::path("C:/Program Files/AI File Sorter/AIFileSorterSetup.exe")); CHECK(exe_request.program == "C:/Program Files/AI File Sorter/AIFileSorterSetup.exe"); CHECK(exe_request.arguments.empty()); const auto msi_request = UpdateInstallerTestAccess::build_launch_request( std::filesystem::path("C:/Program Files/AI File Sorter/AIFileSorterSetup.MSI")); CHECK(msi_request.program == "msiexec.exe"); REQUIRE(msi_request.arguments.size() == 2); CHECK(msi_request.arguments[0] == "/i"); CHECK(msi_request.arguments[1] == "C:/Program Files/AI File Sorter/AIFileSorterSetup.MSI"); } TEST_CASE("UpdateInstaller auto-install support remains Windows-only") { TempDir tmp; EnvVarGuard config_root("AI_FILE_SORTER_CONFIG_DIR", tmp.path().string()); Settings settings; UpdateInstaller installer(settings); UpdateInfo info; info.current_version = "1.8.0"; info.installer_url = "https://filesorter.app/downloads/AIFileSorterSetup.exe"; info.installer_sha256 = sha256_hex("payload"); #ifdef _WIN32 CHECK(installer.supports_auto_install(info)); #else CHECK_FALSE(installer.supports_auto_install(info)); #endif } ================================================ FILE: tests/unit/test_updater.cpp ================================================ #include #include "Settings.hpp" #include "TestHelpers.hpp" #include "Updater.hpp" #include "UpdaterLaunchOptions.hpp" #include "UpdaterLiveTestConfig.hpp" #include "UpdaterTestAccess.hpp" #include "app_version.hpp" #include #include #include #include #include #include namespace { void schedule_message_box_button_click(const QString& target_text, bool* saw_button = nullptr) { auto clicker = std::make_shared>(); *clicker = [clicker, target_text, saw_button](int attempts_remaining) { auto* box = qobject_cast(QApplication::activeModalWidget()); if (!box) { if (attempts_remaining > 0) { QTimer::singleShot(0, [clicker, attempts_remaining]() { (*clicker)(attempts_remaining - 1); }); return; } if (saw_button) { *saw_button = false; } return; } for (auto* button : box->buttons()) { if (button && button->text() == target_text) { if (saw_button) { *saw_button = true; } button->click(); return; } } if (saw_button) { *saw_button = false; } if (auto* ok_button = box->button(QMessageBox::Ok)) { ok_button->click(); } }; QTimer::singleShot(0, [clicker]() { (*clicker)(10); }); } } // namespace TEST_CASE("Updater live test mode synthesizes a newer update without a feed URL") { TempDir config_dir; EnvVarGuard config_guard("AI_FILE_SORTER_CONFIG_DIR", config_dir.path().string()); EnvVarGuard update_spec_guard("UPDATE_SPEC_FILE_URL", std::nullopt); EnvVarGuard live_test_mode_guard(UpdaterLaunchOptions::kLiveTestModeEnv, std::string("1")); EnvVarGuard live_test_url_guard(UpdaterLaunchOptions::kLiveTestUrlEnv, std::string("https://filesorter.app/downloads/AIFileSorterSetup.zip")); EnvVarGuard live_test_sha_guard(UpdaterLaunchOptions::kLiveTestSha256Env, std::string("AABBCCDDEEFF00112233445566778899AABBCCDDEEFF00112233445566778899")); EnvVarGuard live_test_version_guard(UpdaterLaunchOptions::kLiveTestVersionEnv, std::nullopt); EnvVarGuard live_test_min_guard(UpdaterLaunchOptions::kLiveTestMinVersionEnv, std::nullopt); Settings settings; Updater updater(settings); REQUIRE(UpdaterTestAccess::is_update_available(updater)); const auto info = UpdaterTestAccess::current_update_info(updater); REQUIRE(info.has_value()); CHECK(info->current_version == APP_VERSION.to_string() + ".1"); CHECK(info->min_version == "0.0.0"); CHECK(info->download_url == "https://filesorter.app/downloads/AIFileSorterSetup.zip"); CHECK(info->installer_url == info->download_url); CHECK(info->installer_sha256 == "aabbccddeeff00112233445566778899aabbccddeeff00112233445566778899"); } TEST_CASE("Updater live test mode can read missing values from live-test.ini next to the executable") { TempDir temp_dir; const auto exe_dir = temp_dir.path() / "bin"; std::filesystem::create_directories(exe_dir); { std::ofstream out(exe_dir / "live-test.ini", std::ios::binary | std::ios::trunc); out << "[LiveTest]\n"; out << "download_url = https://filesorter.app/downloads/from-ini.zip\n"; out << "sha256 = 11223344556677889900AABBCCDDEEFF11223344556677889900AABBCCDDEEFF\n"; out << "current_version = 9.9.9\n"; out << "min_version = 1.0.0\n"; } UpdaterLiveTestConfig config; config.enabled = true; const auto loaded = load_missing_values_from_live_test_ini(config, exe_dir / "aifilesorter.exe"); REQUIRE(loaded.has_value()); CHECK(loaded->filename() == "live-test.ini"); REQUIRE(config.installer_url.has_value()); REQUIRE(config.installer_sha256.has_value()); REQUIRE(config.current_version.has_value()); REQUIRE(config.min_version.has_value()); CHECK(*config.installer_url == "https://filesorter.app/downloads/from-ini.zip"); CHECK(*config.installer_sha256 == "11223344556677889900AABBCCDDEEFF11223344556677889900AABBCCDDEEFF"); CHECK(*config.current_version == "9.9.9"); CHECK(*config.min_version == "1.0.0"); } TEST_CASE("Updater live test flags override live-test.ini values") { TempDir temp_dir; const auto exe_dir = temp_dir.path() / "bin"; std::filesystem::create_directories(exe_dir); { std::ofstream out(exe_dir / "live-test.ini", std::ios::binary | std::ios::trunc); out << "[LiveTest]\n"; out << "download_url = https://filesorter.app/downloads/from-ini.zip\n"; out << "sha256 = 11223344556677889900AABBCCDDEEFF11223344556677889900AABBCCDDEEFF\n"; } UpdaterLiveTestConfig config; config.enabled = true; config.installer_url = "https://filesorter.app/downloads/from-flag.zip"; const auto loaded = load_missing_values_from_live_test_ini(config, exe_dir / "aifilesorter.exe"); REQUIRE(loaded.has_value()); REQUIRE(config.installer_url.has_value()); REQUIRE(config.installer_sha256.has_value()); CHECK(*config.installer_url == "https://filesorter.app/downloads/from-flag.zip"); CHECK(*config.installer_sha256 == "11223344556677889900AABBCCDDEEFF11223344556677889900AABBCCDDEEFF"); } TEST_CASE("Updater error dialog offers manual update fallback without quitting when not requested") { EnvVarGuard platform_guard("QT_QPA_PLATFORM", "offscreen"); QtAppContext qt_context; TempDir config_dir; EnvVarGuard config_guard("AI_FILE_SORTER_CONFIG_DIR", config_dir.path().string()); EnvVarGuard update_spec_guard("UPDATE_SPEC_FILE_URL", "https://example.com/aifs_version.json"); Settings settings; Updater updater(settings); std::string opened_url; bool quit_called = false; bool saw_manual_button = false; UpdaterTestAccess::set_open_download_url_handler(updater, [&](const std::string& url) { opened_url = url; }); UpdaterTestAccess::set_quit_handler(updater, [&]() { quit_called = true; }); UpdateInfo info; info.download_url = "https://filesorter.app/download"; schedule_message_box_button_click(QStringLiteral("Update manually"), &saw_manual_button); const bool result = UpdaterTestAccess::handle_update_error( updater, info, QStringLiteral("Failed to prepare the update installer."), nullptr, false); CHECK(result); CHECK(saw_manual_button); CHECK(opened_url == info.download_url); CHECK_FALSE(quit_called); } TEST_CASE("Updater error dialog can request quit after manual fallback") { EnvVarGuard platform_guard("QT_QPA_PLATFORM", "offscreen"); QtAppContext qt_context; TempDir config_dir; EnvVarGuard config_guard("AI_FILE_SORTER_CONFIG_DIR", config_dir.path().string()); EnvVarGuard update_spec_guard("UPDATE_SPEC_FILE_URL", "https://example.com/aifs_version.json"); Settings settings; Updater updater(settings); std::string opened_url; bool quit_called = false; UpdaterTestAccess::set_open_download_url_handler(updater, [&](const std::string& url) { opened_url = url; }); UpdaterTestAccess::set_quit_handler(updater, [&]() { quit_called = true; }); UpdateInfo info; info.download_url = "https://filesorter.app/download"; schedule_message_box_button_click(QStringLiteral("Update manually")); const bool result = UpdaterTestAccess::handle_update_error( updater, info, QStringLiteral("The installer could not be launched."), nullptr, true); CHECK(result); CHECK(opened_url == info.download_url); CHECK(quit_called); } TEST_CASE("Updater error dialog omits manual fallback when no download URL is available") { EnvVarGuard platform_guard("QT_QPA_PLATFORM", "offscreen"); QtAppContext qt_context; TempDir config_dir; EnvVarGuard config_guard("AI_FILE_SORTER_CONFIG_DIR", config_dir.path().string()); EnvVarGuard update_spec_guard("UPDATE_SPEC_FILE_URL", "https://example.com/aifs_version.json"); Settings settings; Updater updater(settings); std::string opened_url; bool quit_called = false; bool saw_manual_button = true; UpdaterTestAccess::set_open_download_url_handler(updater, [&](const std::string& url) { opened_url = url; }); UpdaterTestAccess::set_quit_handler(updater, [&]() { quit_called = true; }); UpdateInfo info; schedule_message_box_button_click(QStringLiteral("Update manually"), &saw_manual_button); const bool result = UpdaterTestAccess::handle_update_error( updater, info, QStringLiteral("No download target is available for this update."), nullptr, true); CHECK_FALSE(result); CHECK_FALSE(saw_manual_button); CHECK(opened_url.empty()); CHECK_FALSE(quit_called); } ================================================ FILE: tests/unit/test_updater_build_modes.cpp ================================================ #include #include "Settings.hpp" #include "TestHelpers.hpp" #include "UpdateFeed.hpp" #include "Updater.hpp" #include "UpdaterBuildConfig.hpp" #include "UpdaterLaunchOptions.hpp" #include "UpdaterTestAccess.hpp" #include namespace { constexpr UpdaterBuildConfig::Mode expected_mode() { #if defined(AI_FILE_SORTER_EXPECTED_UPDATE_MODE_DISABLED) return UpdaterBuildConfig::Mode::Disabled; #elif defined(AI_FILE_SORTER_EXPECTED_UPDATE_MODE_NOTIFY_ONLY) return UpdaterBuildConfig::Mode::NotifyOnly; #elif defined(AI_FILE_SORTER_EXPECTED_UPDATE_MODE_AUTO_INSTALL) return UpdaterBuildConfig::Mode::AutoInstall; #else static_assert(false, "Expected updater mode macro is not defined for this test target."); #endif } void ensure_qt_application() { if (QApplication::instance()) { return; } static int argc = 1; static char arg0[] = "updater-build-mode-tests"; static char* argv[] = {arg0, nullptr}; static QApplication app(argc, argv); Q_UNUSED(app); } } // namespace TEST_CASE("Updater build config matches the expected mode for this target") { CHECK(UpdaterBuildConfig::current_mode() == expected_mode()); CHECK(UpdaterBuildConfig::update_checks_enabled() == (expected_mode() != UpdaterBuildConfig::Mode::Disabled)); CHECK(UpdaterBuildConfig::auto_install_enabled() == (expected_mode() == UpdaterBuildConfig::Mode::AutoInstall)); } TEST_CASE("Updater begin schedules work only when update checks are enabled") { EnvVarGuard platform_guard("QT_QPA_PLATFORM", "offscreen"); ensure_qt_application(); TempDir config_dir; EnvVarGuard config_guard("AI_FILE_SORTER_CONFIG_DIR", config_dir.path().string()); EnvVarGuard update_spec_guard("UPDATE_SPEC_FILE_URL", std::nullopt); Settings settings; Updater updater(settings); updater.begin(); CHECK(UpdaterTestAccess::has_update_task(updater) == (expected_mode() != UpdaterBuildConfig::Mode::Disabled)); UpdaterTestAccess::wait_for_update_task(updater); } TEST_CASE("Notify-only updater opens the download page instead of preparing an installer") { if constexpr (expected_mode() != UpdaterBuildConfig::Mode::NotifyOnly) { SUCCEED("This target is not built in notify-only mode."); return; } TempDir config_dir; EnvVarGuard config_guard("AI_FILE_SORTER_CONFIG_DIR", config_dir.path().string()); Settings settings; Updater updater(settings); std::string opened_url; bool quit_called = false; UpdaterTestAccess::set_open_download_url_handler(updater, [&](const std::string& url) { opened_url = url; }); UpdaterTestAccess::set_quit_handler(updater, [&]() { quit_called = true; }); UpdateInfo info; info.current_version = "9.9.9"; info.download_url = "https://filesorter.app/downloads/AIFileSorterSetup.zip"; info.installer_url = "https://filesorter.app/downloads/AIFileSorterSetup.exe"; info.installer_sha256 = "00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff"; const bool result = UpdaterTestAccess::trigger_update_action(updater, info, nullptr, true); CHECK(result); CHECK(opened_url == info.download_url); CHECK(quit_called); } TEST_CASE("Disabled updater mode ignores live-test environment when startup checks are blocked") { if constexpr (expected_mode() != UpdaterBuildConfig::Mode::Disabled) { SUCCEED("This target still allows updater startup checks."); return; } EnvVarGuard platform_guard("QT_QPA_PLATFORM", "offscreen"); ensure_qt_application(); TempDir config_dir; EnvVarGuard config_guard("AI_FILE_SORTER_CONFIG_DIR", config_dir.path().string()); EnvVarGuard update_spec_guard("UPDATE_SPEC_FILE_URL", std::nullopt); EnvVarGuard live_test_mode_guard(UpdaterLaunchOptions::kLiveTestModeEnv, std::string("1")); EnvVarGuard live_test_url_guard(UpdaterLaunchOptions::kLiveTestUrlEnv, std::string("https://filesorter.app/downloads/AIFileSorterSetup.zip")); EnvVarGuard live_test_sha_guard(UpdaterLaunchOptions::kLiveTestSha256Env, std::string("AABBCCDDEEFF00112233445566778899AABBCCDDEEFF00112233445566778899")); Settings settings; Updater updater(settings); updater.begin(); CHECK_FALSE(UpdaterTestAccess::has_update_task(updater)); CHECK_FALSE(UpdaterTestAccess::current_update_info(updater).has_value()); } ================================================ FILE: tests/unit/test_utils.cpp ================================================ #include #include "Utils.hpp" #include "TestHooks.hpp" #include "TestHelpers.hpp" #include #include #include TEST_CASE("get_file_name_from_url extracts filename") { const std::string url = "https://example.com/models/mistral-7b.gguf"; REQUIRE(Utils::get_file_name_from_url(url) == "mistral-7b.gguf"); } TEST_CASE("get_file_name_from_url rejects malformed input") { REQUIRE_THROWS_AS(Utils::get_file_name_from_url("https://example.com/"), std::runtime_error); } TEST_CASE("is_cuda_available honors probe overrides") { struct ProbeGuard { ~ProbeGuard() { TestHooks::reset_cuda_availability_probe(); } } guard; TestHooks::set_cuda_availability_probe([] { return true; }); REQUIRE(Utils::is_cuda_available()); TestHooks::set_cuda_availability_probe([] { return false; }); REQUIRE_FALSE(Utils::is_cuda_available()); } TEST_CASE("abbreviate_user_path strips home prefix") { TempDir temp_home; EnvVarGuard home_guard("HOME", temp_home.path().string()); const auto file = temp_home.path() / "Documents" / "taxes.pdf"; std::filesystem::create_directories(file.parent_path()); std::ofstream(file).put('x'); const std::string abbreviated = Utils::abbreviate_user_path(file.string()); REQUIRE(abbreviated == "Documents/taxes.pdf"); } TEST_CASE("sanitize_path_label strips invalid UTF-8 bytes") { std::string invalid = "Alpha"; invalid.push_back(static_cast(0xFF)); invalid += "Beta"; REQUIRE(Utils::sanitize_path_label(invalid) == "AlphaBeta"); } ================================================ FILE: tests/unit/test_whitelist_and_prompt.cpp ================================================ #include #include "CategorizationService.hpp" #include "CategorizationServiceTestAccess.hpp" #include "DatabaseManager.hpp" #include "ILLMClient.hpp" #include "MainAppTestAccess.hpp" #include "CategoryLanguage.hpp" #include "LocalLLMTestAccess.hpp" #include "Settings.hpp" #include "WhitelistStore.hpp" #include "TestHelpers.hpp" #include "Utils.hpp" #include #include #include namespace { class FixedResponseLLM : public ILLMClient { public: FixedResponseLLM(std::shared_ptr calls, std::string response) : calls_(std::move(calls)), response_(std::move(response)) {} std::string categorize_file(const std::string&, const std::string&, FileType, const std::string&) override { ++(*calls_); return response_; } std::string complete_prompt(const std::string&, int) override { return std::string(); } void set_prompt_logging_enabled(bool) override { } private: std::shared_ptr calls_; std::string response_; }; class TranslationAwareLLM : public ILLMClient { public: TranslationAwareLLM(std::shared_ptr categorize_calls, std::shared_ptr translation_calls, std::string categorize_response, std::deque translation_responses) : categorize_calls_(std::move(categorize_calls)), translation_calls_(std::move(translation_calls)), categorize_response_(std::move(categorize_response)), translation_responses_(std::move(translation_responses)) {} std::string categorize_file(const std::string&, const std::string&, FileType, const std::string&) override { ++(*categorize_calls_); return categorize_response_; } std::string complete_prompt(const std::string&, int) override { ++(*translation_calls_); if (translation_responses_.empty()) { return std::string(); } std::string response = translation_responses_.front(); translation_responses_.pop_front(); return response; } void set_prompt_logging_enabled(bool) override { } private: std::shared_ptr categorize_calls_; std::shared_ptr translation_calls_; std::string categorize_response_; std::deque translation_responses_; }; } // namespace TEST_CASE("WhitelistStore initializes from settings and persists defaults") { TempDir base_dir; EnvVarGuard config_guard("AI_FILE_SORTER_CONFIG_DIR", base_dir.path().string()); Settings settings; settings.set_active_whitelist("MyList"); WhitelistStore store(settings.get_config_dir()); store.set("MyList", WhitelistEntry{{"Alpha", "Beta"}, {"One", "Two"}}); store.save(); store.initialize_from_settings(settings); auto names = store.list_names(); REQUIRE(std::find(names.begin(), names.end(), "MyList") != names.end()); auto entry = store.get("MyList"); REQUIRE(entry.has_value()); REQUIRE(entry->categories == std::vector{"Alpha", "Beta"}); REQUIRE(entry->subcategories == std::vector{"One", "Two"}); REQUIRE(settings.get_active_whitelist() == "MyList"); REQUIRE(settings.get_allowed_categories() == entry->categories); REQUIRE(settings.get_allowed_subcategories() == entry->subcategories); WhitelistStore reloaded(settings.get_config_dir()); REQUIRE(reloaded.load()); auto persisted = reloaded.get("MyList"); REQUIRE(persisted.has_value()); REQUIRE(persisted->categories == entry->categories); REQUIRE(persisted->subcategories == entry->subcategories); } TEST_CASE("CategorizationService builds numbered whitelist context") { TempDir base_dir; EnvVarGuard config_guard("AI_FILE_SORTER_CONFIG_DIR", base_dir.path().string()); Settings settings; settings.set_allowed_categories({"CatA", "CatB"}); settings.set_allowed_subcategories({}); DatabaseManager db(settings.get_config_dir()); CategorizationService service(settings, db, nullptr); const std::string context = CategorizationServiceTestAccess::build_whitelist_context(service); REQUIRE(context.find("Allowed main categories") != std::string::npos); REQUIRE(context.find("1) CatA") != std::string::npos); REQUIRE(context.find("2) CatB") != std::string::npos); REQUIRE(context.find("Allowed subcategories: any") != std::string::npos); } TEST_CASE("CategorizationService builds category language context when non-English selected") { TempDir base_dir; EnvVarGuard config_guard("AI_FILE_SORTER_CONFIG_DIR", base_dir.path().string()); Settings settings; settings.set_category_language(CategoryLanguage::French); DatabaseManager db(settings.get_config_dir()); CategorizationService service(settings, db, nullptr); const std::string context = CategorizationServiceTestAccess::build_category_language_context(service); REQUIRE_FALSE(context.empty()); REQUIRE(context.find("English only") != std::string::npos); REQUIRE(context.find("French") != std::string::npos); } TEST_CASE("CategorizationService builds category language context for Spanish") { TempDir base_dir; EnvVarGuard config_guard("AI_FILE_SORTER_CONFIG_DIR", base_dir.path().string()); Settings settings; settings.set_category_language(CategoryLanguage::Spanish); DatabaseManager db(settings.get_config_dir()); CategorizationService service(settings, db, nullptr); const std::string context = CategorizationServiceTestAccess::build_category_language_context(service); REQUIRE_FALSE(context.empty()); REQUIRE(context.find("English only") != std::string::npos); REQUIRE(context.find("Spanish") != std::string::npos); } TEST_CASE("LocalLLM sanitizer keeps labeled multi-line replies intact") { const std::string output = "Category: Images\n" "Subcategory: Screenshots\n" "Reason: macOS screenshot naming pattern"; REQUIRE(LocalLLMTestAccess::sanitize_output_for_testing(output) == "Images : Screenshots"); } TEST_CASE("LocalLLM sanitizer prefers the last inline pair") { const std::string output = "Texts : Documents\n" "Productivity : File managers\n" "Archives : CAD assets"; REQUIRE(LocalLLMTestAccess::sanitize_output_for_testing(output) == "Archives : CAD assets"); } TEST_CASE("LocalLLM sanitizer strips rationale and natural language lead-ins") { const std::string output = "Based on the file name and context provided, the file falls under the Finances category : Credit reports"; REQUIRE(LocalLLMTestAccess::sanitize_output_for_testing(output) == "Finances : Credit reports"); } TEST_CASE("LocalLLM sanitizer ignores trailing note lines") { const std::string output = "Images : Screenshots\n" "(Note: Since the file is an image and not an installer, this question should not have been directed to me.)"; REQUIRE(LocalLLMTestAccess::sanitize_output_for_testing(output) == "Images : Screenshots"); } TEST_CASE("LocalLLM sanitizer strips translated parenthetical glosses") { const std::string output = "Traitement de texte. (Text documents) : Installateurs. (Software installation)"; REQUIRE(LocalLLMTestAccess::sanitize_output_for_testing(output) == "Traitement de texte : Installateurs"); } TEST_CASE("LocalLLM sanitizer strips inline subcategory label artifacts from category values") { const std::string output = "Category: Images, subcategory: Funny seals"; REQUIRE(LocalLLMTestAccess::sanitize_output_for_testing(output) == "Images : Funny seals"); } TEST_CASE("CategorizationService parses category output without spaced colon delimiters") { TempDir base_dir; EnvVarGuard config_guard("AI_FILE_SORTER_CONFIG_DIR", base_dir.path().string()); Settings settings; DatabaseManager db(settings.get_config_dir()); CategorizationService service(settings, db, nullptr); TempDir data_dir; const std::string file_name = "report.xlsx"; const std::string full_path = (data_dir.path() / file_name).string(); const std::vector files = {FileEntry{full_path, file_name, FileType::File}}; std::atomic stop_flag{false}; auto calls = std::make_shared(0); auto factory = [calls]() { return std::make_unique(calls, "Documents:Spreadsheets"); }; const auto categorized = service.categorize_entries(files, true, stop_flag, {}, {}, {}, {}, factory); REQUIRE(categorized.size() == 1); CHECK(categorized.front().category == "Documents"); CHECK(categorized.front().subcategory == "Spreadsheets"); CHECK(*calls == 1); } TEST_CASE("CategorizationService parses labeled category and subcategory lines") { TempDir base_dir; EnvVarGuard config_guard("AI_FILE_SORTER_CONFIG_DIR", base_dir.path().string()); Settings settings; DatabaseManager db(settings.get_config_dir()); CategorizationService service(settings, db, nullptr); TempDir data_dir; const std::string file_name = "photo.jpg"; const std::string full_path = (data_dir.path() / file_name).string(); const std::vector files = {FileEntry{full_path, file_name, FileType::File}}; std::atomic stop_flag{false}; auto calls = std::make_shared(0); auto factory = [calls]() { return std::make_unique(calls, "Category: Images\nSubcategory: Photos"); }; const auto categorized = service.categorize_entries(files, true, stop_flag, {}, {}, {}, {}, factory); REQUIRE(categorized.size() == 1); CHECK(categorized.front().category == "Images"); CHECK(categorized.front().subcategory == "Photos"); CHECK(*calls == 1); } TEST_CASE("CategorizationService extracts the trailing pair from verbose responses") { TempDir base_dir; EnvVarGuard config_guard("AI_FILE_SORTER_CONFIG_DIR", base_dir.path().string()); Settings settings; DatabaseManager db(settings.get_config_dir()); CategorizationService service(settings, db, nullptr); TempDir data_dir; const std::string file_name = "Screenshot 2026-03-10 at 12.07.00.png"; const std::string full_path = (data_dir.path() / file_name).string(); const std::vector files = {FileEntry{full_path, file_name, FileType::File}}; std::atomic stop_flag{false}; auto calls = std::make_shared(0); auto factory = [calls]() { return std::make_unique( calls, "Based on the filename and extension, the most appropriate categorization is: Images : Screenshots"); }; const auto categorized = service.categorize_entries(files, true, stop_flag, {}, {}, {}, {}, factory); REQUIRE(categorized.size() == 1); CHECK(categorized.front().category == "Images"); CHECK(categorized.front().subcategory == "Screenshots"); CHECK(*calls == 1); } TEST_CASE("CategorizationService prefers the final pair when the model echoes examples") { TempDir base_dir; EnvVarGuard config_guard("AI_FILE_SORTER_CONFIG_DIR", base_dir.path().string()); Settings settings; DatabaseManager db(settings.get_config_dir()); CategorizationService service(settings, db, nullptr); TempDir data_dir; const std::string file_name = "iphone14_pro_magsafe_stls.zip"; const std::string full_path = (data_dir.path() / file_name).string(); const std::vector files = {FileEntry{full_path, file_name, FileType::File}}; std::atomic stop_flag{false}; auto calls = std::make_shared(0); auto factory = [calls]() { return std::make_unique( calls, "Texts : Documents\n" "Productivity : File managers\n" "Archives : CAD assets"); }; const auto categorized = service.categorize_entries(files, true, stop_flag, {}, {}, {}, {}, factory); REQUIRE(categorized.size() == 1); CHECK(categorized.front().category == "Archives"); CHECK(categorized.front().subcategory == "CAD assets"); CHECK(*calls == 1); } TEST_CASE("CategorizationService strips rationale from subcategory text") { TempDir base_dir; EnvVarGuard config_guard("AI_FILE_SORTER_CONFIG_DIR", base_dir.path().string()); Settings settings; DatabaseManager db(settings.get_config_dir()); CategorizationService service(settings, db, nullptr); TempDir data_dir; const std::string file_name = "balenaEtcher-2.1.4-arm64.dmg"; const std::string full_path = (data_dir.path() / file_name).string(); const std::vector files = {FileEntry{full_path, file_name, FileType::File}}; std::atomic stop_flag{false}; auto calls = std::make_shared(0); auto factory = [calls]() { return std::make_unique( calls, "Operating system : MacOS (based on the .dmg file extension) - This file is an installer for macOS software"); }; const auto categorized = service.categorize_entries(files, true, stop_flag, {}, {}, {}, {}, factory); REQUIRE(categorized.size() == 1); CHECK(categorized.front().category == "Operating system"); CHECK(categorized.front().subcategory == "MacOS"); CHECK(*calls == 1); } TEST_CASE("CategorizationService extracts a short category from natural language lead-ins") { TempDir base_dir; EnvVarGuard config_guard("AI_FILE_SORTER_CONFIG_DIR", base_dir.path().string()); Settings settings; DatabaseManager db(settings.get_config_dir()); CategorizationService service(settings, db, nullptr); TempDir data_dir; const std::string file_name = "credit_excerpt.pdf"; const std::string full_path = (data_dir.path() / file_name).string(); const std::vector files = {FileEntry{full_path, file_name, FileType::File}}; std::atomic stop_flag{false}; auto calls = std::make_shared(0); auto factory = [calls]() { return std::make_unique( calls, "Based on the file name and context provided, the file falls under the Finances category : Credit reports"); }; const auto categorized = service.categorize_entries(files, true, stop_flag, {}, {}, {}, {}, factory); REQUIRE(categorized.size() == 1); CHECK(categorized.front().category == "Finances"); CHECK(categorized.front().subcategory == "Credit reports"); CHECK(*calls == 1); } TEST_CASE("CategorizationService ignores trailing note lines after a valid answer") { TempDir base_dir; EnvVarGuard config_guard("AI_FILE_SORTER_CONFIG_DIR", base_dir.path().string()); Settings settings; DatabaseManager db(settings.get_config_dir()); CategorizationService service(settings, db, nullptr); TempDir data_dir; const std::string file_name = "Capture d'ecran.png"; const std::string full_path = (data_dir.path() / file_name).string(); const std::vector files = {FileEntry{full_path, file_name, FileType::File}}; std::atomic stop_flag{false}; auto calls = std::make_shared(0); auto factory = [calls]() { return std::make_unique( calls, "Images : Screenshots\n" "(Note: Since the file is an image and not an installer, this question should not have been directed to me.)"); }; const auto categorized = service.categorize_entries(files, true, stop_flag, {}, {}, {}, {}, factory); REQUIRE(categorized.size() == 1); CHECK(categorized.front().category == "Images"); CHECK(categorized.front().subcategory == "Screenshots"); CHECK(*calls == 1); } TEST_CASE("CategorizationService progress shows current and categorization paths") { TempDir base_dir; EnvVarGuard config_guard("AI_FILE_SORTER_CONFIG_DIR", base_dir.path().string()); Settings settings; DatabaseManager db(settings.get_config_dir()); CategorizationService service(settings, db, nullptr); TempDir data_dir; const std::string file_name = "legacy_name.pdf"; const std::string full_path = (data_dir.path() / file_name).string(); const std::string suggested_name = "new_suggested_file_name.pdf"; const std::string prompt_path = (data_dir.path() / suggested_name).generic_string(); const std::vector files = {FileEntry{full_path, file_name, FileType::File}}; std::atomic stop_flag{false}; auto calls = std::make_shared(0); auto factory = [calls]() { return std::make_unique(calls, "Category: Security\nSubcategory: PCI DSS guidelines"); }; std::vector progress_messages; const auto categorized = service.categorize_entries( files, true, stop_flag, [&progress_messages](const std::string& message) { progress_messages.push_back(message); }, {}, {}, {}, factory, [suggested_name, prompt_path](const FileEntry&) { return CategorizationService::PromptOverride{suggested_name, prompt_path}; }); REQUIRE(categorized.size() == 1); REQUIRE(progress_messages.size() == 1); CHECK(progress_messages.front().find("Category : Security") != std::string::npos); CHECK(progress_messages.front().find("Subcat : PCI DSS guidelines") != std::string::npos); CHECK(progress_messages.front().find("Current Path : " + Utils::abbreviate_user_path(full_path)) != std::string::npos); CHECK(progress_messages.front().find("Categorization Path : " + Utils::abbreviate_user_path(prompt_path)) != std::string::npos); } TEST_CASE("Document prompt helpers use the suggested filename for categorization") { CHECK(MainAppTestAccess::resolve_document_prompt_name("legacy_name.pdf", "cached_name.pdf") == "cached_name.pdf"); CHECK(MainAppTestAccess::resolve_document_prompt_name("legacy_name.pdf", "") == "legacy_name.pdf"); } TEST_CASE("Document prompt path uses the suggested filename and preserves summaries") { TempDir data_dir; const std::filesystem::path original_path = data_dir.path() / "legacy_name.pdf"; const std::string prompt_name = "new_suggested_name.pdf"; const std::string summary = "PCI DSS quick reference"; const std::string expected_path = Utils::path_to_utf8(data_dir.path() / prompt_name); const std::string prompt_path = MainAppTestAccess::build_document_prompt_path( original_path.string(), prompt_name, summary); CHECK(prompt_path.find(expected_path) == 0); CHECK(prompt_path.find("\nDocument summary: " + summary) != std::string::npos); CHECK(prompt_path.find("legacy_name.pdf") == std::string::npos); } TEST_CASE("CategorizationService stores canonical English labels and persists translated taxonomy labels") { TempDir base_dir; EnvVarGuard config_guard("AI_FILE_SORTER_CONFIG_DIR", base_dir.path().string()); Settings settings; settings.set_category_language(CategoryLanguage::French); DatabaseManager db(settings.get_config_dir()); CategorizationService service(settings, db, nullptr); TempDir data_dir; const std::string file_name = "setup_game.exe"; const std::string full_path = (data_dir.path() / file_name).string(); const std::vector files = {FileEntry{full_path, file_name, FileType::File}}; std::atomic stop_flag{false}; auto categorize_calls = std::make_shared(0); auto translation_calls = std::make_shared(0); auto factory = [categorize_calls, translation_calls]() { return std::make_unique( categorize_calls, translation_calls, "Software : Installers", std::deque{ "{\"category\":\"Logiciels\",\"subcategory\":\"Installateurs\"}" }); }; const auto categorized = service.categorize_entries(files, true, stop_flag, {}, {}, {}, {}, factory); REQUIRE(categorized.size() == 1); CHECK(categorized.front().category == "Logiciels"); CHECK(categorized.front().subcategory == "Installateurs"); CHECK(categorized.front().canonical_category == "Software"); CHECK(categorized.front().canonical_subcategory == "Installers"); CHECK(*categorize_calls == 1); CHECK(*translation_calls == 1); const auto cached = db.get_categorization_from_db(data_dir.path().string(), file_name, FileType::File); REQUIRE(cached.size() == 2); CHECK(cached[0] == "Software"); CHECK(cached[1] == "Installers"); const auto translated = db.get_category_translation(categorized.front().taxonomy_id, CategoryLanguage::French); REQUIRE(translated.has_value()); CHECK(translated->category == "Logiciels"); CHECK(translated->subcategory == "Installateurs"); const auto resolved_french = db.resolve_category_for_language("Logiciels", "Installateurs", CategoryLanguage::French); CHECK(resolved_french.taxonomy_id == categorized.front().taxonomy_id); CHECK(resolved_french.category == "Software"); CHECK(resolved_french.subcategory == "Installers"); const auto cached_entries = service.load_cached_entries(data_dir.path().string()); REQUIRE(cached_entries.size() == 1); CHECK(cached_entries.front().category == "Logiciels"); CHECK(cached_entries.front().subcategory == "Installateurs"); CHECK(cached_entries.front().canonical_category == "Software"); CHECK(cached_entries.front().canonical_subcategory == "Installers"); } TEST_CASE("CategorizationService strips inline subcategory label artifacts when parsing service output") { TempDir base_dir; EnvVarGuard config_guard("AI_FILE_SORTER_CONFIG_DIR", base_dir.path().string()); Settings settings; DatabaseManager db(settings.get_config_dir()); CategorizationService service(settings, db, nullptr); TempDir data_dir; const std::string file_name = "seal_photo.jpg"; const std::string full_path = (data_dir.path() / file_name).string(); const std::vector files = {FileEntry{full_path, file_name, FileType::File}}; std::atomic stop_flag{false}; auto calls = std::make_shared(0); auto factory = [calls]() { return std::make_unique(calls, "Category: Images, subcategory: Funny seals"); }; const auto categorized = service.categorize_entries(files, true, stop_flag, {}, {}, {}, {}, factory); REQUIRE(categorized.size() == 1); CHECK(categorized.front().category == "Images"); CHECK(categorized.front().subcategory == "Funny seals"); CHECK(*calls == 1); }