Full Code of hyperfield/ai-file-sorter for AI

main 630b46a1c682 cached
1196 files
8.3 MB
2.2M tokens
2850 symbols
1 requests
Download .txt
Showing preview only (8,908K chars total). Download the full file or copy to clipboard to get everything.
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. <https://fsf.org/>
 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.

    <one line to give the program's name and a brief idea of what it does.>
    Copyright (C) <year>  <name of author>

    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 <https://www.gnu.org/licenses/>.

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
<https://www.gnu.org/licenses/>.



================================================
FILE: README.md
================================================
<!-- markdownlint-disable MD046 -->
# 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/)

<p align="center">
  <img src="app/resources/images/icon_256x256.png" alt="AI File Sorter logo" width="128" height="128">
</p>

<p align="center">
  <img src="images/platform-logos/logo-vulkan.png" alt="Vulkan" width="160">
  <img src="images/platform-logos/logo-cuda.png" alt="CUDA" width="160">
  <img src="images/platform-logos/logo-metal.png" alt="Apple Metal" width="160">
  <img src="images/platform-logos/logo-windows.png" alt="Windows" width="160">
  <img src="images/platform-logos/logo-macos.png" alt="macOS" width="160">
  <img src="images/platform-logos/logo-linux.png" alt="Linux" width="160">
</p>

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.

<p align="center">
  <img src="images/screenshots/before-after/aifs_before_after_v.png" alt="AI File Sorter before and after organization example" width="600">
</p>

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/<variant>` and the runtime DLL/SO copies under `app/lib/ggml/w<variant>`. 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: <https://github.com/microsoft/vcpkg> (clone and bootstrap)
   - package-managed `libmediainfo` via vcpkg manifest (no vendored MediaInfo submodule/binaries)
   - **MSYS2 MinGW64 + OpenBLAS**: install MSYS2 from <https://www.msys2.org>, 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=<path>` 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=<path>` 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\<cpu|cuda|vulkan>` and copies the runtime DLLs into `app\lib\ggml\w<variant>`. 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 <N>` to override the default “all cores” parallel build behaviour (for example, `-Parallel 8`). By default the script invokes `cmake --build ... --parallel <core-count>` and `ctest -j <core-count>` 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=<path>` 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=<https://.../AIFileSorterSetup.zip>`
  `--updater-live-test-sha256=<sha256-of-the-downloaded-package>`
  `--updater-live-test-version=<optional-version>`
  `--updater-live-test-min-version=<optional-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: <https://github.com/curl/curl>
- Dotenv: <https://github.com/motdotla/dotenv>
- git-scm: <https://git-scm.com>
- Hugging Face: <https://huggingface.co>
- JSONCPP: <https://github.com/open-source-parsers/jsoncpp>
- Llama: <https://www.llama.com>
- libzip: <https://libzip.org>
- Local File Organizer <https://github.com/QiuYannnn/Local-File-Organizer>
- llama.cpp <https://github.com/ggml-org/llama.cpp>
- MediaInfoLib: <https://mediaarea.net/en/MediaInfo>
- Mistral AI: <https://mistral.ai>
- OpenAI: <https://platform.openai.com/docs/overview>
- OpenSSL: <https://github.com/openssl/openssl>
- PDFium: <https://pdfium.googlesource.com/pdfium/>
- Poppler (pdftotext): <https://poppler.freedesktop.org/>
- pugixml: <https://pugixml.org>
- Qt: <https://www.qt.io/>
- spdlog: <https://github.com/gabime/spdlog>
- unzip (Info-ZIP): <https://infozip.sourceforge.net/>

## 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 "<test case name or pattern>"`
- 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 <path>`.
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(
        "$<$<COMPILE_LANGUAGE:C>:/MP>"
        "$<$<COMPILE_LANGUAGE:CXX>:/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=<path> 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=<path> 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=<path> first.")
        endif()
        if(NOT EXISTS "${dll_path}")
            message(FATAL_ERROR "Missing ${dll_path}. Run app/scripts/build_llama_windows.ps1 cuda=off vcpkgroot=<path> 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}"
                "$<TARGET_FILE_DIR:aifilesorter>"
        )
    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 "$<TARGET_FILE_DIR:aifilesorter>/openblas.dll"
        COMMAND ${CMAKE_COMMAND} -E make_directory "$<TARGET_FILE_DIR:aifilesorter>/lib/ggml/wocuda"
        COMMAND ${CMAKE_COMMAND} -E make_directory "$<TARGET_FILE_DIR:aifilesorter>/lib/ggml/wcuda"
        COMMAND ${CMAKE_COMMAND} -E make_directory "$<TARGET_FILE_DIR:aifilesorter>/lib/ggml/wvulkan"
        COMMAND ${CMAKE_COMMAND} -E copy_directory
            "${PRECOMPILED_CPU_ROOT}"
            "$<TARGET_FILE_DIR:aifilesorter>/lib/ggml/wocuda"
        COMMAND ${CMAKE_COMMAND} -E copy_directory
            "${PRECOMPILED_CUDA_ROOT}"
            "$<TARGET_FILE_DIR:aifilesorter>/lib/ggml/wcuda"
        COMMAND ${CMAKE_COMMAND} -E copy_directory
            "${PRECOMPILED_VULKAN_ROOT}"
            "$<TARGET_FILE_DIR:aifilesorter>/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}"
    #             "$<TARGET_FILE_DIR:aifilesorter>/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
                    $<TARGET_RUNTIME_DLLS:${target_name}>
                    $<TARGET_FILE_DIR:${target_name}>
                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}
                        $<TARGET_FILE_DIR:${target_name}>
                    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
                                    "$<TARGET_FILE_DIR:${target_name}>/${_aifs_qt_plugin_subdir}"
                                COMMAND ${CMAKE_COMMAND} -E copy_if_different
                                    ${_aifs_qt_plugin_dlls}
                                    "$<TARGET_FILE_DIR:${target_name}>/${_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}"
                    "$<TARGET_FILE_DIR:${target_name}>"
            )
        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_SO
Download .txt
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
Download .txt
Showing preview only (244K chars total). Download the full file or copy to clipboard to get everything.
SYMBOL INDEX (2850 symbols across 374 files)

FILE: app/include/AppInfo.hpp
  function QString (line 9) | inline QString app_display_name() {

FILE: app/include/CategorizationDialog.hpp
  class DatabaseManager (line 17) | class DatabaseManager
  class QCloseEvent (line 18) | class QCloseEvent
  class QEvent (line 19) | class QEvent
  class QPushButton (line 20) | class QPushButton
  class QTableView (line 21) | class QTableView
  class QCheckBox (line 22) | class QCheckBox
  class QStandardItem (line 23) | class QStandardItem
  class CategorizationDialog (line 25) | class CategorizationDialog : public QDialog
    method show_subcategory_column_enabled (line 36) | bool show_subcategory_column_enabled() const { return show_subcategory...
    type RowStatus (line 57) | enum class RowStatus {
    type Column (line 82) | enum Column {
    type MoveRecord (line 93) | struct MoveRecord {
    type PreviewRecord (line 100) | struct PreviewRecord {

FILE: app/include/CategorizationProgressDialog.hpp
  class MainApp (line 16) | class MainApp
  class QLabel (line 17) | class QLabel
  class QPlainTextEdit (line 18) | class QPlainTextEdit
  class QPushButton (line 19) | class QPushButton
  class QTableWidget (line 20) | class QTableWidget
  class QTimer (line 21) | class QTimer
  class QEvent (line 22) | class QEvent
  class CategorizationProgressDialog (line 24) | class CategorizationProgressDialog : public QDialog
    type StageId (line 28) | enum class StageId {
    type StagePlan (line 34) | struct StagePlan {
    type ItemStatus (line 55) | enum class ItemStatus {
    type DisplayType (line 62) | enum class DisplayType {
    type StageState (line 69) | struct StageState {
    type ItemState (line 74) | struct ItemState {

FILE: app/include/CategorizationService.hpp
  class Settings (line 18) | class Settings
  class ILLMClient (line 19) | class ILLMClient
  type spdlog (line 20) | namespace spdlog { class logger; }
    class logger (line 20) | class logger
  class CategorizationService (line 25) | class CategorizationService {
    type PromptOverride (line 34) | struct PromptOverride {

FILE: app/include/CategorizationServiceTestAccess.hpp
  class CategorizationServiceTestAccess (line 10) | class CategorizationServiceTestAccess {
    method build_whitelist_context (line 17) | static std::string build_whitelist_context(const CategorizationService...
    method build_category_language_context (line 26) | static std::string build_category_language_context(const Categorizatio...

FILE: app/include/CategorizationSession.hpp
  class CategorizationSession (line 7) | class CategorizationSession {

FILE: app/include/CategoryLanguage.hpp
  type CategoryLanguage (line 8) | enum class CategoryLanguage {
  function QString (line 20) | inline QString categoryLanguageToString(CategoryLanguage language)
  function CategoryLanguage (line 41) | inline CategoryLanguage categoryLanguageFromString(const QString& value)
  function categoryLanguageDisplay (line 63) | inline std::string categoryLanguageDisplay(CategoryLanguage lang) {

FILE: app/include/ConsistencyPassService.hpp
  class ILLMClient (line 16) | class ILLMClient
  type spdlog (line 17) | namespace spdlog { class logger; }
    class logger (line 17) | class logger
  class ConsistencyPassService (line 19) | class ConsistencyPassService {

FILE: app/include/CustomApiDialog.hpp
  class QCheckBox (line 9) | class QCheckBox
  class QLineEdit (line 10) | class QLineEdit
  class QPushButton (line 11) | class QPushButton
  class QTextEdit (line 12) | class QTextEdit
  class CustomApiDialog (line 17) | class CustomApiDialog : public QDialog

FILE: app/include/CustomLLMDialog.hpp
  class QLineEdit (line 9) | class QLineEdit
  class QPushButton (line 10) | class QPushButton
  class QTextEdit (line 11) | class QTextEdit
  class CustomLLMDialog (line 16) | class CustomLLMDialog : public QDialog

FILE: app/include/DatabaseManager.hpp
  class DatabaseManager (line 13) | class DatabaseManager {
    type ResolvedCategory (line 19) | struct ResolvedCategory {
    type TaxonomyEntry (line 88) | struct TaxonomyEntry {

FILE: app/include/DialogUtils.hpp
  class QWidget (line 6) | class QWidget
  class DialogUtils (line 8) | class DialogUtils {

FILE: app/include/DocumentTextAnalyzer.hpp
  class ILLMClient (line 7) | class ILLMClient
  type DocumentAnalysisResult (line 9) | struct DocumentAnalysisResult {
  class DocumentTextAnalyzer (line 23) | class DocumentTextAnalyzer {
    type Settings (line 28) | struct Settings {

FILE: app/include/DryRunPreviewDialog.hpp
  class DryRunPreviewDialog (line 10) | class DryRunPreviewDialog : public QDialog {
    type Entry (line 13) | struct Entry {

FILE: app/include/EmbeddedEnv.hpp
  class EmbeddedEnv (line 7) | class EmbeddedEnv {

FILE: app/include/FileScanner.hpp
  class FileScanner (line 12) | class FileScanner {
    method FileScanner (line 14) | FileScanner() = default;
    type ScanContext (line 20) | struct ScanContext

FILE: app/include/GeminiClient.hpp
  class GeminiClient (line 8) | class GeminiClient : public ILLMClient {

FILE: app/include/GgmlRuntimePaths.hpp
  type GgmlRuntimePaths (line 8) | namespace GgmlRuntimePaths {

FILE: app/include/ILLMClient.hpp
  class ILLMClient (line 5) | class ILLMClient {

FILE: app/include/ImageRenameMetadataService.hpp
  type sqlite3 (line 9) | struct sqlite3
  class ImageRenameMetadataService (line 20) | class ImageRenameMetadataService {
    method ImageRenameMetadataService (line 35) | ImageRenameMetadataService(const ImageRenameMetadataService&) = delete;
    method ImageRenameMetadataService (line 36) | ImageRenameMetadataService& operator=(const ImageRenameMetadataService...
    type ExifMetadata (line 76) | struct ExifMetadata {
    type CacheLookup (line 82) | struct CacheLookup {
    type ReverseGeocodeResult (line 87) | struct ReverseGeocodeResult {

FILE: app/include/IniConfig.hpp
  class IniConfig (line 10) | class IniConfig {

FILE: app/include/LLMClient.hpp
  class LLMClient (line 8) | class LLMClient : public ILLMClient {

FILE: app/include/LLMDownloader.hpp
  class LLMDownloader (line 16) | class LLMDownloader
    type DownloadStatus (line 96) | enum class DownloadStatus {
    class LLMDownloaderTestAccess (line 128) | class LLMDownloaderTestAccess {

FILE: app/include/LLMErrors.hpp
  class BackoffError (line 7) | class BackoffError : public std::runtime_error {
    method BackoffError (line 9) | BackoffError(const std::string& message, int retry_seconds)
    method retry_after_seconds (line 12) | int retry_after_seconds() const { return retry_after_seconds_; }

FILE: app/include/LLMSelectionDialog.hpp
  class QLabel (line 15) | class QLabel
  class QProgressBar (line 16) | class QProgressBar
  class QPushButton (line 17) | class QPushButton
  class QRadioButton (line 18) | class QRadioButton
  class QDialogButtonBox (line 19) | class QDialogButtonBox
  class QWidget (line 20) | class QWidget
  class QString (line 21) | class QString
  class QComboBox (line 22) | class QComboBox
  class QListWidget (line 23) | class QListWidget
  class QLineEdit (line 24) | class QLineEdit
  class QCheckBox (line 25) | class QCheckBox
  class QToolButton (line 26) | class QToolButton
  class QScrollArea (line 27) | class QScrollArea
  class QShowEvent (line 28) | class QShowEvent
  class Settings (line 30) | class Settings
  class LLMSelectionDialogTestAccess (line 33) | class LLMSelectionDialogTestAccess
  class LLMSelectionDialog (line 36) | class LLMSelectionDialog : public QDialog
    type VisualLlmDownloadEntry (line 60) | struct VisualLlmDownloadEntry {

FILE: app/include/LLMSelectionDialogTestAccess.hpp
  class LLMDownloader (line 10) | class LLMDownloader
  class LLMSelectionDialog (line 11) | class LLMSelectionDialog
  class LLMSelectionDialogTestAccess (line 13) | class LLMSelectionDialogTestAccess {
    type VisualEntryRefs (line 15) | struct VisualEntryRefs {

FILE: app/include/Language.hpp
  type Language (line 6) | enum class Language {
  function QString (line 17) | inline QString languageToString(Language language)
  function Language (line 40) | inline Language languageFromString(const QString& value)

FILE: app/include/LlamaModelParams.hpp
  type spdlog (line 7) | namespace spdlog { class logger; }
    class logger (line 7) | class logger

FILE: app/include/LlavaImageAnalyzer.hpp
  type llama_model (line 13) | struct llama_model
  type llama_context (line 14) | struct llama_context
  type llama_vocab (line 15) | struct llama_vocab
  type mtmd_context (line 16) | struct mtmd_context
  type mtmd_bitmap (line 17) | struct mtmd_bitmap
  type LlavaImageAnalysisResult (line 23) | struct LlavaImageAnalysisResult {
  class LlavaImageAnalyzer (line 37) | class LlavaImageAnalyzer {
    type Settings (line 42) | struct Settings {
    method LlavaImageAnalyzer (line 84) | LlavaImageAnalyzer(const LlavaImageAnalyzer&) = delete;
    method LlavaImageAnalyzer (line 85) | LlavaImageAnalyzer& operator=(const LlavaImageAnalyzer&) = delete;
    type ggml_log_level (line 193) | enum ggml_log_level
  type LlavaImageAnalyzerTestAccess (line 205) | namespace LlavaImageAnalyzerTestAccess {

FILE: app/include/LlmCatalog.hpp
  type DefaultLlmEntry (line 12) | struct DefaultLlmEntry {

FILE: app/include/LocalLLMClient.hpp
  type spdlog (line 10) | namespace spdlog { class logger; }
    class logger (line 10) | class logger
  class LocalLLMClient (line 12) | class LocalLLMClient : public ILLMClient {
    type Status (line 17) | enum class Status {

FILE: app/include/LocalLLMTestAccess.hpp
  type LocalLLMTestAccess (line 8) | namespace LocalLLMTestAccess {
    type BackendPreference (line 10) | enum class BackendPreference {

FILE: app/include/Logger.hpp
  class Logger (line 10) | class Logger {
    method Logger (line 20) | Logger() = delete;

FILE: app/include/MainApp.hpp
  class QAction (line 36) | class QAction
  class QCheckBox (line 37) | class QCheckBox
  class QRadioButton (line 38) | class QRadioButton
  class QComboBox (line 39) | class QComboBox
  class QLabel (line 40) | class QLabel
  class QDockWidget (line 41) | class QDockWidget
  class QFileSystemModel (line 42) | class QFileSystemModel
  class QLineEdit (line 43) | class QLineEdit
  class QString (line 44) | class QString
  class QPushButton (line 45) | class QPushButton
  class QToolButton (line 46) | class QToolButton
  class QTreeView (line 47) | class QTreeView
  class QStackedWidget (line 48) | class QStackedWidget
  class QWidget (line 49) | class QWidget
  class QLabel (line 50) | class QLabel
  class QEvent (line 51) | class QEvent
  class MainAppUiBuilder (line 52) | class MainAppUiBuilder
  class WhitelistManagerDialog (line 53) | class WhitelistManagerDialog
  class SuitabilityBenchmarkDialog (line 54) | class SuitabilityBenchmarkDialog
  type CategorizedFile (line 56) | struct CategorizedFile
  type FileEntry (line 57) | struct FileEntry
  class MainAppTestAccess (line 60) | class MainAppTestAccess
  class MainApp (line 66) | class MainApp : public QMainWindow
    type SupportPromptResult (line 73) | enum class SupportPromptResult { Support, NotSure }
    method is_development_mode (line 124) | bool is_development_mode() const { return development_mode_; }
  class WhitelistManagerDialog (line 380) | class WhitelistManagerDialog

FILE: app/include/MainAppEditActions.hpp
  class QLineEdit (line 6) | class QLineEdit
  class MainAppEditActions (line 8) | class MainAppEditActions {

FILE: app/include/MainAppHelpActions.hpp
  class QWidget (line 6) | class QWidget
  class MainAppHelpActions (line 8) | class MainAppHelpActions {

FILE: app/include/MainAppTestAccess.hpp
  class MainApp (line 19) | class MainApp
  class Settings (line 20) | class Settings
  class MainAppTestAccess (line 25) | class MainAppTestAccess {
    type SimulatedSupportResult (line 30) | enum class SimulatedSupportResult {

FILE: app/include/MainAppUiBuilder.hpp
  class MainApp (line 8) | class MainApp
  class MainAppUiBuilder (line 13) | class MainAppUiBuilder {

FILE: app/include/MediaRenameMetadataService.hpp
  class MediaRenameMetadataService (line 17) | class MediaRenameMetadataService {
    type MetadataFields (line 22) | struct MetadataFields {

FILE: app/include/MovableCategorizedFile.hpp
  class MovableCategorizedFile (line 7) | class MovableCategorizedFile {
    type PreviewPaths (line 9) | struct PreviewPaths {
    type MovePaths (line 42) | struct MovePaths {

FILE: app/include/ResultsCoordinator.hpp
  class ResultsCoordinator (line 16) | class ResultsCoordinator {

FILE: app/include/Settings.hpp
  class Settings (line 16) | class Settings

FILE: app/include/SuitabilityBenchmarkDialog.hpp
  class QLabel (line 12) | class QLabel
  class QTextEdit (line 13) | class QTextEdit
  class QProgressBar (line 14) | class QProgressBar
  class QPushButton (line 15) | class QPushButton
  class QCheckBox (line 16) | class QCheckBox
  class Settings (line 17) | class Settings
  class QCloseEvent (line 18) | class QCloseEvent
  class QEvent (line 19) | class QEvent
  class SuitabilityBenchmarkDialog (line 24) | class SuitabilityBenchmarkDialog : public QDialog

FILE: app/include/SupportCodeManager.hpp
  class SupportCodeManager (line 15) | class SupportCodeManager {

FILE: app/include/TestHooks.hpp
  type TestHooks (line 11) | namespace TestHooks {
    type BackendMemoryInfo (line 13) | struct BackendMemoryInfo {
    type CategorizationMoveInfo (line 35) | struct CategorizationMoveInfo {

FILE: app/include/TranslationManager.hpp
  class QApplication (line 11) | class QApplication
  class TranslationManager (line 13) | class TranslationManager : public QObject
    type LanguageInfo (line 16) | struct LanguageInfo {

FILE: app/include/Types.hpp
  type LLMChoice (line 6) | enum class LLMChoice {
  function is_remote_choice (line 17) | inline bool is_remote_choice(LLMChoice choice) {
  type FileType (line 23) | enum class FileType {File, Directory}
  type CategorizedFile (line 25) | struct CategorizedFile {
  function to_string (line 41) | inline std::string to_string(FileType type) {
  type FileEntry (line 49) | struct FileEntry {
  type CustomLLM (line 55) | struct CustomLLM {
  function is_valid_custom_llm (line 62) | inline bool is_valid_custom_llm(const CustomLLM& entry) {
  type CustomApiEndpoint (line 69) | struct CustomApiEndpoint {
  function is_valid_custom_api_endpoint (line 81) | inline bool is_valid_custom_api_endpoint(const CustomApiEndpoint& entry) {
  type FileScanOptions (line 88) | enum class FileScanOptions {
  function has_flag (line 96) | inline bool has_flag(FileScanOptions value, FileScanOptions flag) {
  function FileScanOptions (line 100) | inline FileScanOptions operator|(FileScanOptions a, FileScanOptions b) {
  function FileScanOptions (line 104) | inline FileScanOptions operator&(FileScanOptions a, FileScanOptions b) {
  function FileScanOptions (line 108) | inline FileScanOptions operator~(FileScanOptions a) {
  type cudaDeviceProp (line 112) | struct cudaDeviceProp {

FILE: app/include/UiTranslator.hpp
  class QAction (line 12) | class QAction
  class QActionGroup (line 13) | class QActionGroup
  class QDockWidget (line 15) | class QDockWidget
  class QLabel (line 16) | class QLabel
  class QMainWindow (line 17) | class QMainWindow
  class QMenu (line 18) | class QMenu
  class QPushButton (line 19) | class QPushButton
  class QComboBox (line 20) | class QComboBox
  class QStandardItemModel (line 21) | class QStandardItemModel
  class QToolButton (line 22) | class QToolButton
  class Settings (line 24) | class Settings
  class UiTranslator (line 32) | class UiTranslator
    type PrimaryControls (line 38) | struct PrimaryControls {
    type MenuControls (line 70) | struct MenuControls {
    type ActionControls (line 85) | struct ActionControls {
    type LanguageControls (line 124) | struct LanguageControls {
    type CategoryLanguageControls (line 139) | struct CategoryLanguageControls {
    type State (line 155) | struct State {
    type Dependencies (line 164) | struct Dependencies {

FILE: app/include/UndoManager.hpp
  class UndoManager (line 14) | class UndoManager {
    type Entry (line 16) | struct Entry {
    type UndoResult (line 31) | struct UndoResult {

FILE: app/include/UpdateArchiveExtractor.hpp
  class UpdateArchiveExtractor (line 6) | class UpdateArchiveExtractor
    type ExtractionResult (line 9) | struct ExtractionResult
      method ExtractionResult (line 14) | static ExtractionResult success(std::filesystem::path path)
      method ExtractionResult (line 19) | static ExtractionResult failure(std::string error)
      method ok (line 24) | bool ok() const

FILE: app/include/UpdateFeed.hpp
  type UpdateInfo (line 6) | struct UpdateInfo
    method has_download_target (line 15) | bool has_download_target() const
    method has_direct_installer (line 20) | bool has_direct_installer() const
  class UpdateFeed (line 26) | class UpdateFeed
    type Platform (line 29) | enum class Platform {

FILE: app/include/UpdateInstaller.hpp
  type UpdatePreparationResult (line 12) | struct UpdatePreparationResult
    type Status (line 14) | enum class Status {
    method UpdatePreparationResult (line 24) | static UpdatePreparationResult ready(std::filesystem::path path)
    method UpdatePreparationResult (line 29) | static UpdatePreparationResult canceled(std::string message = {})
    method UpdatePreparationResult (line 34) | static UpdatePreparationResult failed(std::string message)
  class UpdateInstaller (line 40) | class UpdateInstaller
    type LaunchRequest (line 43) | struct LaunchRequest
    class DownloadCanceledError (line 49) | class DownloadCanceledError : public std::runtime_error

FILE: app/include/UpdateInstallerTestAccess.hpp
  class UpdateInstallerTestAccess (line 7) | class UpdateInstallerTestAccess {

FILE: app/include/Updater.hpp
  class QWidget (line 13) | class QWidget
  class QString (line 14) | class QString
  class UpdaterTestAccess (line 17) | class UpdaterTestAccess
  class Updater (line 20) | class Updater

FILE: app/include/UpdaterBuildConfig.hpp
  type UpdaterBuildConfig (line 3) | namespace UpdaterBuildConfig {
    type Mode (line 5) | enum class Mode {
    function Mode (line 11) | constexpr Mode current_mode()
    function update_checks_enabled (line 24) | constexpr bool update_checks_enabled()
    function auto_install_enabled (line 29) | constexpr bool auto_install_enabled()

FILE: app/include/UpdaterLaunchOptions.hpp
  type UpdaterLaunchOptions (line 3) | namespace UpdaterLaunchOptions {

FILE: app/include/UpdaterLiveTestConfig.hpp
  type UpdaterLiveTestConfig (line 7) | struct UpdaterLiveTestConfig

FILE: app/include/UpdaterTestAccess.hpp
  class QWidget (line 10) | class QWidget
  class Updater (line 11) | class Updater
  class UpdaterTestAccess (line 13) | class UpdaterTestAccess {

FILE: app/include/Utils.hpp
  class Utils (line 13) | class Utils {
    type CudaMemoryInfo (line 28) | struct CudaMemoryInfo {
      method valid (line 33) | bool valid() const {

FILE: app/include/Version.hpp
  class Version (line 9) | class Version {

FILE: app/include/WhitelistManagerDialog.hpp
  class QListWidget (line 11) | class QListWidget
  class QTextEdit (line 12) | class QTextEdit
  class QLineEdit (line 13) | class QLineEdit
  class QPushButton (line 14) | class QPushButton
  class QLabel (line 15) | class QLabel
  class WhitelistManagerDialog (line 20) | class WhitelistManagerDialog : public QDialog {
    method set_on_lists_changed (line 34) | void set_on_lists_changed(std::function<void()> cb) { on_lists_changed...

FILE: app/include/WhitelistStore.hpp
  class Settings (line 9) | class Settings
  type WhitelistEntry (line 11) | struct WhitelistEntry {
  class WhitelistStore (line 16) | class WhitelistStore {
    method empty (line 27) | bool empty() const { return entries_.empty(); }
    method default_name (line 34) | std::string default_name() const { return default_name_; }

FILE: app/include/external/dotenv.h
  function class (line 91) | class dotenv
  function init (line 125) | inline void dotenv::init(const char* filename)
  function init (line 145) | inline void dotenv::init(int flags, const char* filename)
  function setenv (line 169) | inline int setenv(const char *name, const char *value, int overwrite)
  function find_var_start (line 194) | inline size_t dotenv::find_var_start(const std::string& str, size_t pos,...
  function find_var_end (line 213) | inline size_t dotenv::find_var_end(const std::string& str, size_t pos, c...
  function ltrim (line 223) | inline void dotenv::ltrim(std::string& s) {
  function rtrim (line 228) | inline void dotenv::rtrim(std::string& s) {
  function trim (line 233) | inline void dotenv::trim(std::string& s) {
  function do_init (line 326) | inline void dotenv::do_init(int flags, const char* filename)

FILE: app/lib/CategorizationDialog.cpp
  type ScopedFlag (line 72) | struct ScopedFlag {
    method ScopedFlag (line 74) | explicit ScopedFlag(bool& target) : ref(target) { ref = true; }
  function to_lower_copy_str (line 84) | std::string to_lower_copy_str(std::string value) {
  function trim_copy (line 91) | std::string trim_copy(const std::string& value) {
  function is_missing_category_label (line 99) | bool is_missing_category_label(const std::string& value) {
  class BulkEditDialog (line 108) | class BulkEditDialog final : public QDialog {
    method BulkEditDialog (line 110) | explicit BulkEditDialog(bool allow_subcategory, QWidget* parent = null...
    method category (line 146) | std::string category() const {
    method subcategory (line 150) | std::string subcategory() const {
    method update_ok_state (line 158) | void update_ok_state() {
  function contains_only_allowed_chars (line 173) | bool contains_only_allowed_chars(const std::string& value) {
  function has_leading_or_trailing_space_or_dot (line 187) | bool has_leading_or_trailing_space_or_dot(const std::string& value) {
  function is_reserved_windows_name (line 196) | bool is_reserved_windows_name(const std::string& value) {
  function looks_like_extension_label (line 206) | bool looks_like_extension_label(const std::string& value) {
  function validate_labels (line 218) | bool validate_labels(const std::string& category,
  function to_system_clock (line 250) | std::chrono::system_clock::time_point to_system_clock(std::filesystem::f...
  type TestHooks (line 262) | namespace TestHooks {
    function set_categorization_move_probe (line 264) | void set_categorization_move_probe(CategorizationMoveProbe probe) {
    function reset_categorization_move_probe (line 268) | void reset_categorization_move_probe() {
  function QFileIconProvider (line 476) | QFileIconProvider& file_icon_provider()
  function QIcon (line 482) | QIcon fallback_image_icon()
  function icons_match (line 525) | bool icons_match(const QIcon& left, const QIcon& right, const QSize& size)
  function QIcon (line 544) | QIcon type_icon(const QString& code, const QString& file_path)
  function QIcon (line 576) | QIcon edit_icon()
  function QString (line 592) | QString edit_icon_html(int size)
  function is_supported_image_entry (line 608) | bool is_supported_image_entry(const std::string& file_path,
  function is_supported_document_entry (line 619) | bool is_supported_document_entry(const std::string& file_path,
  function build_suggested_target_dir (line 630) | std::filesystem::path build_suggested_target_dir(const CategorizedFile& ...
  type NumericSuffix (line 650) | struct NumericSuffix {
  function NumericSuffix (line 656) | NumericSuffix split_numeric_suffix(const std::string& stem) {
  type ParentheticalSuffix (line 690) | struct ParentheticalSuffix {
  function ParentheticalSuffix (line 696) | ParentheticalSuffix split_parenthetical_suffix(const std::string& stem) {
  function build_unique_suggested_name (line 739) | std::string build_unique_suggested_name(const std::string& desired_name,
  function build_unique_move_name (line 803) | std::string build_unique_move_name(const std::string& desired_name,
  function ensure_unique_image_suggested_names (line 855) | void ensure_unique_image_suggested_names(std::vector<CategorizedFile>& f...
  type RowEntry (line 921) | struct RowEntry {
  type CollisionState (line 1383) | struct CollisionState {

FILE: app/lib/CategorizationProgressDialog.cpp
  function QString (line 298) | QString CategorizationProgressDialog::stage_label(StageId stage_id) const
  function QString (line 327) | QString CategorizationProgressDialog::display_type_label(DisplayType dis...

FILE: app/lib/CategorizationService.cpp
  function trim_copy (line 39) | std::string trim_copy(std::string value) {
  function collapse_spaces_copy (line 46) | std::string collapse_spaces_copy(std::string value) {
  function strip_wrapping_punctuation (line 64) | std::string strip_wrapping_punctuation(std::string value) {
  function strip_trailing_parenthetical_gloss (line 97) | std::string strip_trailing_parenthetical_gloss(std::string value) {
  function find_case_insensitive (line 123) | std::size_t find_case_insensitive(const std::string& value, std::string_...
  function strip_explanatory_suffix (line 132) | std::string strip_explanatory_suffix(std::string value) {
  function extract_category_phrase (line 165) | std::string extract_category_phrase(std::string value) {
  function strip_inline_label_artifacts (line 200) | std::string strip_inline_label_artifacts(std::string value, bool categor...
  function normalize_candidate_label (line 237) | std::string normalize_candidate_label(std::string value, bool category_l...
  function strip_list_prefix (line 251) | std::string strip_list_prefix(std::string line) {
  function has_alpha (line 275) | bool has_alpha(const std::string& value) {
  function is_heading_like_label (line 281) | bool is_heading_like_label(const std::string& value) {
  function split_segments (line 308) | std::vector<std::string> split_segments(const std::string& line, std::st...
  function extract_labeled_value (line 325) | std::optional<std::string> extract_labeled_value(const std::string& line,
  function split_inline_pair (line 346) | bool split_inline_pair(const std::string& line, std::string& category, s...
  function split_category_subcategory (line 374) | std::pair<std::string, std::string> split_category_subcategory(const std...
  function parse_translated_category_response (line 434) | std::optional<std::pair<std::string, std::string>> parse_translated_cate...
  function to_lower_copy_str (line 459) | std::string to_lower_copy_str(std::string value) {
  function contains_only_allowed_chars (line 467) | bool contains_only_allowed_chars(const std::string& value) {
  function has_leading_or_trailing_space_or_dot (line 482) | bool has_leading_or_trailing_space_or_dot(const std::string& value) {
  function is_reserved_windows_name (line 493) | bool is_reserved_windows_name(const std::string& value) {
  function looks_like_extension_label (line 504) | bool looks_like_extension_label(const std::string& value) {
  type LabelValidationResult (line 517) | struct LabelValidationResult {
  function LabelValidationResult (line 523) | LabelValidationResult validate_labels(const std::string& category, const...
  function is_allowed (line 713) | bool is_allowed(const std::string& value, const std::vector<std::string>...
  function first_allowed_or_blank (line 727) | std::string first_allowed_or_blank(const std::vector<std::string>& allow...

FILE: app/lib/CategorizationSession.cpp
  function LLMClient (line 22) | LLMClient CategorizationSession::create_llm_client() const

FILE: app/lib/ConsistencyPassService.cpp
  function trim_whitespace (line 27) | std::string trim_whitespace(const std::string& value) {
  function try_parse_harmonized_entry (line 37) | bool try_parse_harmonized_entry(const std::string& line,
  function make_item_key (line 75) | std::string make_item_key(const CategorizedFile& item) {
  function canonical_category_text (line 81) | std::string canonical_category_text(const CategorizedFile& item) {
  function canonical_subcategory_text (line 85) | std::string canonical_subcategory_text(const CategorizedFile& item) {
  function build_items_by_key (line 89) | std::unordered_map<std::string, CategorizedFile*> build_items_by_key(std...
  function build_consistency_prompt (line 98) | std::string build_consistency_prompt(
  function parse_structured_lines (line 146) | bool parse_structured_lines(
  type HarmonizedUpdate (line 206) | struct HarmonizedUpdate {
  function extract_harmonized_update (line 213) | std::optional<HarmonizedUpdate> extract_harmonized_update(
  function apply_harmonized_update (line 263) | void apply_harmonized_update(
  function strip_list_prefix (line 342) | std::string strip_list_prefix(std::string line) {
  function split_key_value (line 351) | std::optional<std::pair<std::string, std::string>> split_key_value(const...
  function split_category_subcategory (line 365) | std::pair<std::string, std::string> split_category_subcategory(const std...
  function parse_ordered_line (line 374) | std::optional<std::pair<std::string, std::string>> parse_ordered_line(
  function parse_ordered_category_lines (line 407) | std::vector<std::pair<std::string, std::string>> parse_ordered_category_...
  function apply_ordered_fallback (line 437) | bool apply_ordered_fallback(

FILE: app/lib/CustomApiDialog.cpp
  function CustomApiEndpoint (line 109) | CustomApiEndpoint CustomApiDialog::result() const

FILE: app/lib/CustomLLMDialog.cpp
  function CustomLLM (line 94) | CustomLLM CustomLLMDialog::result() const

FILE: app/lib/DatabaseManager.cpp
  function db_log (line 26) | void db_log(spdlog::level::level_enum level, const char* fmt, Args&&... ...
  function is_duplicate_column_error (line 35) | bool is_duplicate_column_error(const char *error_msg) {
  function to_lower_copy (line 46) | std::string to_lower_copy(std::string value) {
  function language_storage_key (line 53) | std::string language_storage_key(CategoryLanguage language) {
  function extract_extension_lower (line 57) | std::string extract_extension_lower(const std::string& file_name) {
  type StatementDeleter (line 66) | struct StatementDeleter {
  function StatementPtr (line 76) | StatementPtr prepare_statement(sqlite3* db, const char* sql) {
  function trim_copy (line 84) | std::string trim_copy(std::string value) {
  function has_label_content (line 91) | bool has_label_content(const std::string& value) {
  function escape_like_pattern (line 95) | std::string escape_like_pattern(const std::string& value) {
  function build_recursive_dir_pattern (line 107) | std::string build_recursive_dir_pattern(const std::string& directory_pat...
  function build_categorized_entry (line 125) | std::optional<CategorizedFile> build_categorized_entry(sqlite3_stmt* stm...
  function strip_trailing_stopwords (line 500) | static std::string strip_trailing_stopwords(const std::string& normalize...
  type CanonicalCategoryLabel (line 538) | struct CanonicalCategoryLabel {
  function is_image_like_label (line 543) | bool is_image_like_label(const std::string& normalized) {
  function CanonicalCategoryLabel (line 563) | CanonicalCategoryLabel canonicalize_category_label(const std::string& no...
  function CategorizedFile (line 1019) | CategorizedFile DatabaseManager::localize_categorized_file(const Categor...

FILE: app/lib/DocumentTextAnalyzer.cpp
  function to_lower_copy (line 46) | std::string to_lower_copy(std::string value) {
  function trim_copy (line 53) | std::string trim_copy(const std::string& value) {
  function collapse_whitespace (line 61) | std::string collapse_whitespace(const std::string& value) {
  function QString (line 79) | QString sanitize_utf8_text(const std::string& value) {
  function split_words (line 85) | std::vector<std::string> split_words(const QString& value) {
  function strip_xml_tags (line 102) | std::string strip_xml_tags(const std::string& xml) {
  function replace_all (line 122) | void replace_all(std::string& value, std::string_view from, std::string_...
  function decode_basic_entities (line 133) | std::string decode_basic_entities(std::string value) {
  function append_node_text (line 143) | void append_node_text(const pugi::xml_node& node, std::string& out) {
  function extract_xml_text (line 154) | std::string extract_xml_text(const std::string& xml) {
  function run_process (line 168) | std::optional<std::string> run_process(const QString& program,
  function find_executable (line 192) | std::optional<QString> find_executable(const QString& name) {
  function extract_zip_member_libzip (line 201) | std::optional<std::string> extract_zip_member_libzip(const std::filesyst...
  function extract_zip_member (line 236) | std::optional<std::string> extract_zip_member(const std::filesystem::pat...
  function read_file_prefix (line 260) | std::string read_file_prefix(const std::filesystem::path& path, size_t m...
  function truncate_excerpt (line 273) | std::string truncate_excerpt(const std::string& text, size_t max_chars) {
  function normalize_date (line 282) | std::optional<std::string> normalize_date(const std::string& input) {
  function extract_docx_date (line 299) | std::optional<std::string> extract_docx_date(const std::filesystem::path...
  function extract_pdf_date (line 316) | std::optional<std::string> extract_pdf_date(const std::filesystem::path&...
  class PdfiumLibraryGuard (line 345) | class PdfiumLibraryGuard {
    method PdfiumLibraryGuard (line 347) | PdfiumLibraryGuard() { FPDF_InitLibrary(); }
  function PdfiumLibraryGuard (line 351) | PdfiumLibraryGuard& pdfium_library() {
    method PdfiumLibraryGuard (line 347) | PdfiumLibraryGuard() { FPDF_InitLibrary(); }
  function extract_pdf_text_pdfium (line 356) | std::string extract_pdf_text_pdfium(const std::filesystem::path& path, s...
  type ParsedAnalysis (line 422) | struct ParsedAnalysis {
  function parse_analysis_json (line 427) | std::optional<ParsedAnalysis> parse_analysis_json(const std::string& res...
  function first_words (line 470) | std::string first_words(const std::string& text, size_t max_words) {
  function DocumentAnalysisResult (line 509) | DocumentAnalysisResult DocumentTextAnalyzer::analyze(const std::filesyst...

FILE: app/lib/FileScanner.cpp
  type FileScanner::ScanContext (line 23) | struct FileScanner::ScanContext {

FILE: app/lib/GeminiClient.cpp
  function WriteCallback (line 29) | size_t WriteCallback(void* contents, size_t size, size_t nmemb, std::str...
  function escape_json (line 36) | std::string escape_json(const std::string& input) {
  type CurlRequest (line 53) | struct CurlRequest {
    method CurlRequest (line 57) | CurlRequest() = default;
    method CurlRequest (line 58) | CurlRequest(const CurlRequest&) = delete;
    method CurlRequest (line 59) | CurlRequest& operator=(const CurlRequest&) = delete;
    method CurlRequest (line 61) | CurlRequest(CurlRequest&& other) noexcept
    method CurlRequest (line 69) | CurlRequest& operator=(CurlRequest&& other) noexcept
    method cleanup (line 86) | void cleanup()
  function CurlRequest (line 99) | CurlRequest create_curl_request(const std::shared_ptr<spdlog::logger>& l...
    method CurlRequest (line 57) | CurlRequest() = default;
    method CurlRequest (line 58) | CurlRequest(const CurlRequest&) = delete;
    method CurlRequest (line 59) | CurlRequest& operator=(const CurlRequest&) = delete;
    method CurlRequest (line 61) | CurlRequest(CurlRequest&& other) noexcept
    method CurlRequest (line 69) | CurlRequest& operator=(CurlRequest&& other) noexcept
    method cleanup (line 86) | void cleanup()
  function configure_request_payload (line 121) | void configure_request_payload(CurlRequest& request,
  function perform_request (line 138) | long perform_request(CurlRequest& request, const std::shared_ptr<spdlog:...
  function parse_text_response (line 153) | std::string parse_text_response(const std::string& payload,

FILE: app/lib/GgmlRuntimePaths.cpp
  type GgmlRuntimePaths (line 6) | namespace GgmlRuntimePaths {
    function ends_with (line 10) | bool ends_with(const std::string& value, const std::string& suffix) {
    function has_payload (line 19) | bool has_payload(const std::filesystem::path& dir) {
    function macos_candidate_dirs (line 44) | std::vector<std::filesystem::path> macos_candidate_dirs(
    function resolve_macos_backend_dir (line 67) | std::optional<std::filesystem::path> resolve_macos_backend_dir(

FILE: app/lib/ImageRenameMetadataService.cpp
  type TiffEntry (line 55) | struct TiffEntry {
  type ParsedExifMetadata (line 63) | struct ParsedExifMetadata {
  function write_callback (line 69) | size_t write_callback(void* contents, size_t size, size_t nmemb, void* u...
  function configure_tls (line 77) | void configure_tls(CURL* curl)
  function read_byte (line 87) | bool read_byte(std::ifstream& in, uint8_t& value)
  function read_exact (line 97) | bool read_exact(std::ifstream& in, uint8_t* data, size_t size)
  function read_jpeg_exif_payload (line 106) | std::optional<std::vector<uint8_t>> read_jpeg_exif_payload(const std::fi...
  function read_file_bytes (line 181) | std::optional<std::vector<uint8_t>> read_file_bytes(const std::filesyste...
  function starts_with_bytes (line 202) | bool starts_with_bytes(const std::vector<uint8_t>& data, const char* pre...
  function looks_like_tiff_payload (line 210) | bool looks_like_tiff_payload(const std::vector<uint8_t>& data)
  function read_tiff_exif_payload (line 228) | std::optional<std::vector<uint8_t>> read_tiff_exif_payload(const std::fi...
  function read_png_exif_payload (line 250) | std::optional<std::vector<uint8_t>> read_png_exif_payload(const std::fil...
  function to_lower_ascii (line 308) | std::string to_lower_ascii(std::string value)
  function file_extension_lower (line 316) | std::string file_extension_lower(const std::filesystem::path& path)
  function has_extension (line 321) | bool has_extension(const std::string& extension, std::initializer_list<c...
  function tiff_type_size (line 331) | size_t tiff_type_size(uint16_t type)
  function read_u16 (line 343) | std::optional<uint16_t> read_u16(const std::vector<uint8_t>& data,
  function read_u32 (line 358) | std::optional<uint32_t> read_u32(const std::vector<uint8_t>& data,
  function parse_ifd_entries (line 377) | bool parse_ifd_entries(const std::vector<uint8_t>& tiff,
  function TiffEntry (line 417) | const TiffEntry* find_entry(const std::vector<TiffEntry>& entries, uint1...
  function value_data_offset (line 427) | std::optional<size_t> value_data_offset(const std::vector<uint8_t>& tiff,
  function trim_copy (line 455) | std::string trim_copy(std::string value)
  function read_ascii_value (line 463) | std::optional<std::string> read_ascii_value(const std::vector<uint8_t>& ...
  function read_rational_triplet (line 492) | std::optional<std::array<double, 3>> read_rational_triplet(const std::ve...
  function decode_gps_coordinate (line 519) | std::optional<double> decode_gps_coordinate(const std::array<double, 3>&...
  function normalize_exif_date_value (line 541) | std::optional<std::string> normalize_exif_date_value(const std::string& ...
  function ParsedExifMetadata (line 560) | ParsedExifMetadata parse_tiff_metadata(const std::vector<uint8_t>& tiff)
  function shell_quote_argument (line 672) | std::string shell_quote_argument(const std::string& raw)
  function run_command_capture_output (line 703) | std::optional<std::string> run_command_capture_output(const std::string&...
  function json_string_field (line 735) | std::optional<std::string> json_string_field(const Json::Value& object, ...
  function json_number_field (line 747) | std::optional<double> json_number_field(const Json::Value& object, const...
  function ParsedExifMetadata (line 777) | ParsedExifMetadata extract_heif_metadata_with_exiftool(const std::filesy...
  function pick_place_name (line 837) | std::optional<std::string> pick_place_name(const Json::Value& root)

FILE: app/lib/IniConfig.cpp
  function ini_log (line 12) | void ini_log(spdlog::level::level_enum level, const char* fmt, Args&&......
  function trim_copy (line 21) | std::string trim_copy(const std::string& input)
  function should_skip_line (line 31) | bool should_skip_line(const std::string& line)
  function parse_section_header (line 36) | bool parse_section_header(const std::string& line, std::string& section)
  function parse_key_value (line 45) | std::optional<std::pair<std::string, std::string>> parse_key_value(const...

FILE: app/lib/LLMClient.cpp
  function WriteCallback (line 23) | static size_t WriteCallback(void *contents, size_t size, size_t nmemb, s...
  function escape_json (line 33) | std::string escape_json(const std::string& input) {
  function resolve_custom_timeout_seconds (line 50) | long resolve_custom_timeout_seconds() {
  function resolve_openai_timeout_seconds (line 62) | long resolve_openai_timeout_seconds() {
  function resolve_timeout_seconds (line 66) | long resolve_timeout_seconds(const std::string& base_url) {
  function trim_ws (line 74) | std::string trim_ws(const std::string& value) {
  function trim_trailing_slashes (line 84) | std::string trim_trailing_slashes(std::string value) {
  function ends_with (line 91) | bool ends_with(const std::string& value, const std::string& suffix) {
  type CurlRequest (line 98) | struct CurlRequest {
    method CurlRequest (line 102) | CurlRequest() = default;
    method CurlRequest (line 103) | CurlRequest(const CurlRequest&) = delete;
    method CurlRequest (line 104) | CurlRequest& operator=(const CurlRequest&) = delete;
    method CurlRequest (line 106) | CurlRequest(CurlRequest&& other) noexcept
    method CurlRequest (line 114) | CurlRequest& operator=(CurlRequest&& other) noexcept
    method cleanup (line 131) | void cleanup()
  function CurlRequest (line 144) | CurlRequest create_curl_request(const std::shared_ptr<spdlog::logger>& l...
    method CurlRequest (line 102) | CurlRequest() = default;
    method CurlRequest (line 103) | CurlRequest(const CurlRequest&) = delete;
    method CurlRequest (line 104) | CurlRequest& operator=(const CurlRequest&) = delete;
    method CurlRequest (line 106) | CurlRequest(CurlRequest&& other) noexcept
    method CurlRequest (line 114) | CurlRequest& operator=(CurlRequest&& other) noexcept
    method cleanup (line 131) | void cleanup()
  function configure_request_payload (line 166) | void configure_request_payload(CurlRequest& request,
  function perform_request (line 189) | long perform_request(CurlRequest& request, const std::shared_ptr<spdlog:...
  function parse_category_response (line 204) | std::string parse_category_response(const std::string& payload,

FILE: app/lib/LLMDownloader.cpp
  function replace_download_file (line 22) | bool replace_download_file(const std::filesystem::path& source,
  function FILE (line 529) | FILE* LLMDownloader::open_output_file(long resume_offset) const
  type TestHooks (line 728) | namespace TestHooks {
    function set_llm_download_probe (line 730) | void set_llm_download_probe(LLMDownloadProbe probe) {
    function reset_llm_download_probe (line 734) | void reset_llm_download_probe() {

FILE: app/lib/LLMSelectionDialog.cpp
  function QString (line 44) | QString format_markup_label(const QString& title, const QString& value, ...
  function local_file_size_or_zero (line 50) | long long local_file_size_or_zero(const std::string& path)
  function set_fixed_progress_width (line 60) | void set_fixed_progress_width(QProgressBar* bar, int multiplier)
  function apply_progress_style (line 80) | void apply_progress_style(QProgressBar* bar)
  function LLMChoice (line 586) | LLMChoice LLMSelectionDialog::get_selected_llm_choice() const

FILE: app/lib/LlavaImageAnalyzer.cpp
  function is_mtmd_prompt_log_line (line 51) | bool is_mtmd_prompt_log_line(std::string_view line) {
  function to_lower_copy (line 56) | std::string to_lower_copy(std::string value) {
  function read_env_bool (line 63) | std::optional<bool> read_env_bool(const char* key) {
  function read_env_value (line 79) | std::optional<std::string> read_env_value(const char* key) {
  function set_env_value (line 87) | void set_env_value(const char* key, const std::optional<std::string>& va...
  class ScopedEnvValue (line 103) | class ScopedEnvValue {
    method ScopedEnvValue (line 105) | ScopedEnvValue(const char* key, std::optional<std::string> value)
    method ScopedEnvValue (line 114) | ScopedEnvValue(const ScopedEnvValue&) = delete;
    method ScopedEnvValue (line 115) | ScopedEnvValue& operator=(const ScopedEnvValue&) = delete;
  function read_env_int (line 122) | std::optional<int> read_env_int(const char* key) {
  function resolve_visual_gpu_layer_override (line 141) | std::optional<int> resolve_visual_gpu_layer_override() {
  function read_env_lower (line 148) | std::string read_env_lower(const char* key) {
  function resolve_backend_name (line 156) | std::string resolve_backend_name() {
  function trim_copy (line 169) | std::string trim_copy(const std::string& value) {
  function QString (line 177) | QString sanitize_utf8_text(const std::string& value) {
  function split_words (line 183) | std::vector<std::string> split_words(const QString& value) {
  function case_insensitive_contains (line 207) | bool case_insensitive_contains(std::string_view text, std::string_view n...
  function resolve_default_visual_batch_size (line 222) | int32_t resolve_default_visual_batch_size(bool gpu_enabled, std::string_...
  function llama_model_params (line 241) | llama_model_params build_visual_model_params_for_path(
  type BackendMemoryInfo (line 275) | struct BackendMemoryInfo {
  function query_backend_memory (line 281) | std::optional<BackendMemoryInfo> query_backend_memory(std::string_view b...
  function should_enable_mmproj_gpu (line 322) | bool should_enable_mmproj_gpu(const std::filesystem::path& mmproj_path,
  type BitmapDeleter (line 370) | struct BitmapDeleter {
  type ChunkDeleter (line 378) | struct ChunkDeleter {
  function llama_token (line 389) | llama_token greedy_sample(const float* logits, int vocab_size, float tem...
  type LlavaImageAnalyzerTestAccess (line 407) | namespace LlavaImageAnalyzerTestAccess {
    function default_visual_batch_size (line 408) | int32_t default_visual_batch_size(bool gpu_enabled, std::string_view b...
    function visual_model_n_gpu_layers_for_model (line 412) | int32_t visual_model_n_gpu_layers_for_model(const std::string& model_p...
  function LlavaImageAnalysisResult (line 632) | LlavaImageAnalysisResult LlavaImageAnalyzer::analyze(const std::filesyst...
  type ggml_log_level (line 716) | enum ggml_log_level
  type LogGuard (line 778) | struct LogGuard {
    method LogGuard (line 780) | explicit LogGuard(LlavaImageAnalyzer* self) : active(true) {
  type ProgressGuard (line 805) | struct ProgressGuard {
    method ProgressGuard (line 807) | ProgressGuard(bool enabled, LlavaImageAnalyzer* self) : active(enabled) {

FILE: app/lib/LlmCatalog.cpp
  function QString (line 9) | QString resolved_llm_name(const DefaultLlmEntry& entry)
  function QString (line 31) | QString default_llm_label(const DefaultLlmEntry& entry)
  function QString (line 36) | QString default_llm_label_for_choice(LLMChoice choice)

FILE: app/lib/LocalLLMClient.cpp
  function set_env_var (line 38) | [[maybe_unused]] static void set_env_var(const char *key, const char *va...
  function set_env_var (line 42) | [[maybe_unused]] static void set_env_var(const char *key, const char *va...
  type GgufCtxDeleter (line 50) | struct GgufCtxDeleter {
  function try_parse_env_int (line 54) | bool try_parse_env_int(const char *key, int &out) {
  function resolve_gpu_layer_override (line 74) | int resolve_gpu_layer_override() {
  function gpu_layers_to_string (line 85) | std::string gpu_layers_to_string(int value) {
  function resolve_context_length (line 92) | int resolve_context_length() {
  function is_cpu_backend_requested (line 103) | bool is_cpu_backend_requested() {
  function allow_gpu_fallback (line 124) | bool allow_gpu_fallback(const LocalLLMClient::FallbackDecisionCallback& ...
  type MetalDeviceInfo (line 141) | struct MetalDeviceInfo {
    method valid (line 146) | bool valid() const {
  function MetalDeviceInfo (line 152) | MetalDeviceInfo query_primary_gpu_device() {
    method valid (line 146) | bool valid() const {
  function metal_backend_available (line 181) | bool metal_backend_available(const std::shared_ptr<spdlog::logger>& logg...
  function case_insensitive_contains (line 203) | bool case_insensitive_contains(std::string_view text, std::string_view n...
  function trim_copy (line 221) | std::string trim_copy(std::string value) {
  function collapse_spaces_copy (line 228) | std::string collapse_spaces_copy(std::string value) {
  function strip_wrapping_punctuation (line 246) | std::string strip_wrapping_punctuation(std::string value) {
  function strip_trailing_parenthetical_gloss (line 279) | std::string strip_trailing_parenthetical_gloss(std::string value) {
  function find_case_insensitive (line 305) | std::size_t find_case_insensitive(const std::string& value, std::string_...
  function strip_explanatory_suffix (line 314) | std::string strip_explanatory_suffix(std::string value) {
  function extract_category_phrase (line 347) | std::string extract_category_phrase(std::string value) {
  function strip_inline_label_artifacts (line 382) | std::string strip_inline_label_artifacts(std::string value, bool categor...
  function normalize_candidate_label (line 419) | std::string normalize_candidate_label(std::string value, bool category_l...
  function to_lower_copy (line 433) | std::string to_lower_copy(std::string value) {
  function has_alpha (line 440) | bool has_alpha(std::string_view value) {
  function is_heading_like_label (line 446) | bool is_heading_like_label(const std::string& value) {
  function split_segments (line 475) | std::vector<std::string> split_segments(const std::string& line, std::st...
  function extract_inline_pair_from_line (line 492) | std::optional<std::pair<std::string, std::string>> extract_inline_pair_f...
  function extract_labeled_value (line 517) | std::optional<std::string> extract_labeled_value(const std::string& line,
  function strip_code_fence (line 538) | std::string strip_code_fence(std::string output) {
  function sanitize_categorization_output (line 557) | std::string sanitize_categorization_output(std::string output) {
  function categorization_system_prompt (line 607) | std::string categorization_system_prompt() {
  function prompt_token_budget (line 619) | int prompt_token_budget(int context_tokens, int max_tokens) {
  function truncate_with_ellipsis (line 627) | std::string truncate_with_ellipsis(std::string value, std::size_t limit) {
  function shrink_user_prompt_for_context (line 640) | std::string shrink_user_prompt_for_context(const std::string& prompt, in...
  function is_probably_integrated_gpu (line 685) | bool is_probably_integrated_gpu(ggml_backend_dev_t device,
  function load_ggml_backends_once (line 712) | void load_ggml_backends_once(const std::shared_ptr<spdlog::logger>& logg...
  function BackendMemoryProbe (line 736) | BackendMemoryProbe& backend_memory_probe_slot() {
  function BackendAvailabilityProbe (line 741) | BackendAvailabilityProbe& backend_availability_probe_slot() {
  function query_backend_available_impl (line 746) | bool query_backend_available_impl(std::string_view backend_name) {
  function resolve_backend_available (line 760) | bool resolve_backend_available(std::string_view backend_name) {
  function backend_name_matches (line 767) | bool backend_name_matches(const char *name, std::string_view backend_nam...
  function build_backend_memory_info (line 774) | std::optional<BackendMemoryInfo> build_backend_memory_info(ggml_backend_...
  function query_backend_memory_metrics_impl (line 807) | std::optional<BackendMemoryInfo> query_backend_memory_metrics_impl(std::...
  function resolve_backend_memory (line 830) | [[maybe_unused]] std::optional<BackendMemoryInfo> resolve_backend_memory...
  type TestHooks (line 839) | namespace TestHooks {
    function set_backend_memory_probe (line 841) | void set_backend_memory_probe(BackendMemoryProbe probe) {
    function reset_backend_memory_probe (line 845) | void reset_backend_memory_probe() {
    function set_backend_availability_probe (line 849) | void set_backend_availability_probe(BackendAvailabilityProbe probe) {
    function reset_backend_availability_probe (line 853) | void reset_backend_availability_probe() {
  function read_file_prefix (line 861) | bool read_file_prefix(std::ifstream& file,
  function read_le32 (line 907) | uint32_t read_le32(const char* ptr)
  function read_le64 (line 914) | uint64_t read_le64(const char* ptr)
  function read_uint_value (line 921) | std::optional<int32_t> read_uint_value(uint32_t type,
  function read_gguf_numeric (line 944) | std::optional<int32_t> read_gguf_numeric(gguf_context* ctx, int64_t id)
  function try_block_count_keys (line 959) | std::optional<int32_t> try_block_count_keys(gguf_context* ctx,
  function infer_block_count_from_tensors (line 974) | std::optional<int32_t> infer_block_count_from_tensors(gguf_context* ctx)
  function format_prompt (line 1004) | bool format_prompt(llama_model* model,
  function tokenize_prompt (line 1070) | bool tokenize_prompt(const llama_vocab* vocab,
  function run_generation_loop (line 1107) | std::string run_generation_loop(llama_context* ctx,
  function parse_block_count_entry (line 1181) | std::optional<int32_t> parse_block_count_entry(const std::vector<char>& ...
  function extract_block_count_gguf (line 1210) | std::optional<int32_t> extract_block_count_gguf(const std::string& model...
  function extract_block_count (line 1239) | std::optional<int32_t> extract_block_count(const std::string & model_pat...
  type AutoGpuLayerEstimation (line 1291) | struct AutoGpuLayerEstimation {
  function AutoGpuLayerEstimation (line 1297) | AutoGpuLayerEstimation estimate_gpu_layers_for_metal(const std::string &...
  type LayerMetrics (line 1361) | struct LayerMetrics {
  function populate_layer_metrics (line 1366) | bool populate_layer_metrics(const std::string& model_path,
  type CudaBudget (line 1391) | struct CudaBudget {
  function compute_cuda_budget (line 1397) | bool compute_cuda_budget(const Utils::CudaMemoryInfo& memory_info,
  function finalize_cuda_estimate (line 1446) | bool finalize_cuda_estimate(const LayerMetrics& metrics,
  function AutoGpuLayerEstimation (line 1473) | [[maybe_unused]] AutoGpuLayerEstimation estimate_gpu_layers_for_cuda(con...
  type PreferredBackend (line 1494) | enum class PreferredBackend {
  function PreferredBackend (line 1501) | [[maybe_unused]] PreferredBackend detect_preferred_backend() {
  function determine_metal_layers (line 1523) | int determine_metal_layers(const std::string& model_path,
  function apply_cpu_backend (line 1551) | bool apply_cpu_backend(llama_model_params& params,
  function apply_vulkan_override (line 1565) | bool apply_vulkan_override(llama_model_params& params,
  function cap_integrated_gpu_memory (line 1589) | Utils::CudaMemoryInfo cap_integrated_gpu_memory(const BackendMemoryInfo&...
  function log_vulkan_estimation (line 1608) | void log_vulkan_estimation(const Utils::CudaMemoryInfo& memory,
  function finalize_vulkan_layers (line 1628) | bool finalize_vulkan_layers(const AutoGpuLayerEstimation& estimation,
  function apply_vulkan_backend (line 1649) | bool apply_vulkan_backend(const std::string& model_path,
  function handle_cuda_forced_off (line 1686) | bool handle_cuda_forced_off(bool cuda_forced_off,
  function disable_cuda_backend (line 1704) | void disable_cuda_backend(llama_model_params& params,
  function ensure_cuda_available (line 1715) | bool ensure_cuda_available(llama_model_params& params,
  function apply_ngl_override (line 1726) | bool apply_ngl_override(int override_layers,
  type NglEstimationResult (line 1751) | struct NglEstimationResult {
  function NglEstimationResult (line 1756) | NglEstimationResult estimate_ngl_from_cuda_info(const std::string& model...
  function fallback_ngl (line 1798) | int fallback_ngl(int heuristic_layers, const std::shared_ptr<spdlog::log...
  function configure_cuda_backend (line 1812) | bool configure_cuda_backend(const std::string& model_path,
  function silent_logger (line 1844) | void silent_logger(enum ggml_log_level, const char *, void *) {}
  function llama_debug_logger (line 1847) | void llama_debug_logger(enum ggml_log_level level, const char *text, voi...
  function llama_logs_enabled_from_env (line 1856) | bool llama_logs_enabled_from_env()
  function llama_model_params (line 1912) | llama_model_params build_model_params_for_path(const std::string& model_...
  function llama_model_params (line 1988) | llama_model_params LocalLLMClient::prepare_model_params(const std::share...
  function PreferredBackend (line 1996) | PreferredBackend to_internal_backend(LocalLLMTestAccess::BackendPreferen...
  function to_external_backend (line 2007) | LocalLLMTestAccess::BackendPreference to_external_backend(PreferredBacke...
  type LocalLLMTestAccess (line 2020) | namespace LocalLLMTestAccess {
    function BackendPreference (line 2022) | BackendPreference detect_preferred_backend() {
    function apply_cpu_backend (line 2026) | bool apply_cpu_backend(llama_model_params& params, BackendPreference p...
    function apply_vulkan_backend (line 2030) | bool apply_vulkan_backend(const std::string& model_path, llama_model_p...
    function handle_cuda_forced_off (line 2034) | bool handle_cuda_forced_off(bool cuda_forced_off,
    function configure_cuda_backend (line 2040) | bool configure_cuda_backend(const std::string& model_path, llama_model...
    function llama_model_params (line 2044) | llama_model_params prepare_model_params_for_testing(const std::string&...
    function sanitize_output_for_testing (line 2054) | std::string sanitize_output_for_testing(const std::string& output) {
  type LocalLLMTestAccess (line 2052) | namespace LocalLLMTestAccess {
    function BackendPreference (line 2022) | BackendPreference detect_preferred_backend() {
    function apply_cpu_backend (line 2026) | bool apply_cpu_backend(llama_model_params& params, BackendPreference p...
    function apply_vulkan_backend (line 2030) | bool apply_vulkan_backend(const std::string& model_path, llama_model_p...
    function handle_cuda_forced_off (line 2034) | bool handle_cuda_forced_off(bool cuda_forced_off,
    function configure_cuda_backend (line 2040) | bool configure_cuda_backend(const std::string& model_path, llama_model...
    function llama_model_params (line 2044) | llama_model_params prepare_model_params_for_testing(const std::string&...
    function sanitize_output_for_testing (line 2054) | std::string sanitize_output_for_testing(const std::string& output) {
  function llama_model_params (line 2062) | llama_model_params LocalLLMClient::load_model_or_throw(llama_model_param...
  type ContextAttempt (line 2153) | struct ContextAttempt {

FILE: app/lib/MainApp.cpp
  function trim_ws_copy (line 102) | std::string trim_ws_copy(const std::string& value) {
  function expand_user_path (line 112) | std::string expand_user_path(const std::string& value) {
  function normalize_directory_path (line 131) | std::string normalize_directory_path(const std::string& value) {
  function resolve_document_prompt_name (line 148) | std::string resolve_document_prompt_name(const std::string& original_name,
  function build_document_prompt_path (line 153) | std::string build_document_prompt_path(const std::string& full_path,
  function schedule_next_support_prompt (line 167) | void schedule_next_support_prompt(Settings& settings, int total_files) {
  function maybe_show_support_prompt (line 172) | void maybe_show_support_prompt(Settings& settings,
  function record_categorized_metrics_impl (line 210) | void record_categorized_metrics_impl(Settings& settings,
  function to_utf8 (line 223) | std::string to_utf8(const QString& value)
  function to_lower_copy (line 229) | std::string to_lower_copy(std::string value) {
  function should_offer_visual_cpu_fallback (line 235) | bool should_offer_visual_cpu_fallback(const std::string& reason) {
  type VisualLlmPaths (line 257) | struct VisualLlmPaths {
  function default_text_llm_files_available (line 262) | bool default_text_llm_files_available()
  function resolve_mmproj_path (line 291) | std::optional<std::filesystem::path> resolve_mmproj_path(const std::file...
  function resolve_visual_llm_paths (line 311) | std::optional<VisualLlmPaths> resolve_visual_llm_paths(std::string* erro...
  function should_use_visual_gpu (line 343) | bool should_use_visual_gpu() {
  function read_env_bool (line 355) | std::optional<bool> read_env_bool(const char* key) {
  function read_env_int (line 373) | std::optional<int> read_env_int(const char* key) {
  function resolve_local_context_tokens (line 389) | int resolve_local_context_tokens() {
  function resolve_document_char_budget (line 399) | size_t resolve_document_char_budget(bool using_local_llm, int max_output...
  function split_entries_for_analysis (line 409) | void split_entries_for_analysis(const std::vector<FileEntry>& files,
  function sync_disclosure_button (line 495) | void sync_disclosure_button(QToolButton* button, bool expanded)
  function QString (line 1220) | QString MainAppTestAccess::analyze_button_text(const MainApp& app) {
  function QString (line 1224) | QString MainAppTestAccess::path_label_text(const MainApp& app) {
  function QCheckBox (line 1228) | QCheckBox* MainAppTestAccess::categorize_files_checkbox(MainApp& app) {
  function QCheckBox (line 1232) | QCheckBox* MainAppTestAccess::analyze_images_checkbox(MainApp& app) {
  function QCheckBox (line 1236) | QCheckBox* MainAppTestAccess::process_images_only_checkbox(MainApp& app) {
  function QCheckBox (line 1240) | QCheckBox* MainAppTestAccess::add_image_date_to_category_checkbox(MainAp...
  function QCheckBox (line 1244) | QCheckBox* MainAppTestAccess::add_image_date_place_to_filename_checkbox(...
  function QCheckBox (line 1248) | QCheckBox* MainAppTestAccess::add_audio_video_metadata_to_filename_check...
  function QCheckBox (line 1252) | QCheckBox* MainAppTestAccess::offer_rename_images_checkbox(MainApp& app) {
  function QCheckBox (line 1256) | QCheckBox* MainAppTestAccess::rename_images_only_checkbox(MainApp& app) {
  function QCheckBox (line 1260) | QCheckBox* MainAppTestAccess::analyze_documents_checkbox(MainApp& app) {
  function QCheckBox (line 1264) | QCheckBox* MainAppTestAccess::process_documents_only_checkbox(MainApp& a...
  function QCheckBox (line 1268) | QCheckBox* MainAppTestAccess::rename_documents_only_checkbox(MainApp& ap...
  function QToolButton (line 1272) | QToolButton* MainAppTestAccess::image_options_toggle_button(MainApp& app) {
  function QToolButton (line 1276) | QToolButton* MainAppTestAccess::document_options_toggle_button(MainApp& ...
  function FileScanOptions (line 1609) | FileScanOptions MainApp::effective_scan_options() const
  type ImageAnalysisInfo (line 2888) | struct ImageAnalysisInfo {
  type DocumentAnalysisInfo (line 2894) | struct DocumentAnalysisInfo {

FILE: app/lib/MainAppEditActions.cpp
  function QString (line 58) | QString MainAppEditActions::get_selection(QLineEdit* line_edit, bool del...

FILE: app/lib/MainAppHelpActions.cpp
  function QString (line 19) | QString support_page_url_string()
  function open_external_url (line 24) | bool open_external_url(const QUrl& url)
  function QString (line 148) | QString MainAppHelpActions::support_page_url()

FILE: app/lib/MainAppUiBuilder.cpp
  class DisclosureToggleButton (line 58) | class DisclosureToggleButton final : public QToolButton {
    method DisclosureToggleButton (line 60) | explicit DisclosureToggleButton(QWidget* parent = nullptr)
    method paintEvent (line 72) | void paintEvent(QPaintEvent*) override
  function QColor (line 88) | QColor with_enabled_alpha(QColor color, bool enabled, int disabled_alpha...
  function QIcon (line 96) | QIcon draw_menu_icon(MainApp& app, const MenuIconPainter& painter_fn)
  function QPainterPath (line 123) | QPainterPath sparkle_path(const QPointF& center, qreal outer_radius, qre...
  function draw_card_label (line 139) | void draw_card_label(QPainter& painter,
  function draw_translation_cards (line 153) | void draw_translation_cards(QPainter& painter,
  function QIcon (line 215) | QIcon llm_menu_icon(MainApp& app)
  function QIcon (line 244) | QIcon interface_language_menu_icon(MainApp& app)
  function QIcon (line 262) | QIcon category_language_menu_icon(MainApp& app)
  function QPainterPath (line 280) | QPainterPath tag_path(const QRectF& rect)
  function QIcon (line 292) | QIcon whitelist_menu_icon(MainApp& app)
  function QIcon (line 831) | QIcon MainAppUiBuilder::icon_for(MainApp& app, const char* name, QStyle:...

FILE: app/lib/MediaRenameMetadataService.cpp
  function trim_copy (line 38) | std::string trim_copy(std::string value)
  function to_lower_copy (line 49) | std::string to_lower_copy(std::string value)
  function is_supported_audio (line 76) | bool is_supported_audio(const std::filesystem::path& path)
  function is_supported_video (line 85) | bool is_supported_video(const std::filesystem::path& path)
  function has_metadata_parts (line 94) | bool has_metadata_parts(const MediaRenameMetadataService::MetadataFields...
  function read_exact (line 105) | bool read_exact(std::istream& input, char* destination, std::size_t size)
  function read_u32_be (line 114) | std::uint32_t read_u32_be(const std::uint8_t* bytes)
  function read_u32_le (line 122) | std::uint32_t read_u32_le(const std::uint8_t* bytes)
  function read_u24_be (line 130) | std::uint32_t read_u24_be(const std::uint8_t* bytes)
  function read_u64_be (line 137) | std::uint64_t read_u64_be(const std::uint8_t* bytes)
  function read_synchsafe_u32 (line 149) | std::uint32_t read_synchsafe_u32(const std::uint8_t* bytes)
  function sanitize_metadata_value (line 157) | std::string sanitize_metadata_value(std::string value)
  function assign_if_missing (line 176) | void assign_if_missing(std::optional<std::string>& target, const std::op...
  function assign_vorbis_comment_field (line 183) | void assign_vorbis_comment_field(const std::string& key,
  function decode_id3_text_frame (line 209) | std::optional<std::string> decode_id3_text_frame(const std::uint8_t* byt...
  function remove_unsynchronization (line 266) | std::vector<std::uint8_t> remove_unsynchronization(const std::vector<std...
  function parse_vorbis_comment_payload (line 282) | bool parse_vorbis_comment_payload(const std::uint8_t* bytes,
  function parse_id3v2_frames (line 334) | bool parse_id3v2_frames(const std::vector<std::uint8_t>& tag_data,
  function parse_id3v2_from_file (line 437) | bool parse_id3v2_from_file(const std::filesystem::path& media_path,
  function parse_id3v1_from_file (line 472) | bool parse_id3v1_from_file(const std::filesystem::path& media_path,
  function parse_flac_vorbis_comments (line 515) | bool parse_flac_vorbis_comments(const std::filesystem::path& media_path,
  function parse_ogg_comments (line 557) | bool parse_ogg_comments(const std::filesystem::path& media_path,
  function make_fourcc (line 644) | constexpr std::uint32_t make_fourcc(std::uint8_t c0,
  function seek_to (line 677) | bool seek_to(std::istream& input, std::uint64_t offset)
  function read_at (line 690) | bool read_at(std::istream& input, std::uint64_t offset, std::uint8_t* de...
  function is_mp4_container_atom (line 701) | bool is_mp4_container_atom(std::uint32_t atom_type)
  function is_mp4_metadata_key_atom (line 716) | bool is_mp4_metadata_key_atom(std::uint32_t atom_type)
  function decode_utf16_ascii_fallback (line 729) | std::string decode_utf16_ascii_fallback(const std::uint8_t* bytes, std::...
  function parse_mp4_data_text (line 768) | std::optional<std::string> parse_mp4_data_text(const std::vector<std::ui...
  function assign_mp4_metadata_field (line 806) | void assign_mp4_metadata_field(std::uint32_t atom_type,
  function parse_mp4_atoms (line 831) | void parse_mp4_atoms(std::istream& input,
  function parse_mp4_style_metadata (line 919) | bool parse_mp4_style_metadata(const std::filesystem::path& media_path,
  function parse_media_metadata_without_mediainfo (line 942) | std::optional<MediaRenameMetadataService::MetadataFields> parse_media_me...
  function media_info_to_utf8 (line 980) | std::string media_info_to_utf8(const MediaInfoCompat::String& value)
  function query_field (line 990) | std::string query_field(MediaInfoCompat::MediaInfo& media_info,
  function query_first_field (line 1003) | std::optional<std::string> query_first_field(MediaInfoCompat::MediaInfo&...
  function query_first_available (line 1017) | std::optional<std::string> query_first_available(MediaInfoCompat::MediaI...

FILE: app/lib/MovableCategorizedFile.cpp
  function with_core_logger (line 12) | void with_core_logger(Callable callable)
  function to_lower_copy_str (line 19) | std::string to_lower_copy_str(std::string value) {
  function contains_only_allowed_chars (line 26) | bool contains_only_allowed_chars(const std::string& value) {
  function has_leading_or_trailing_space_or_dot (line 40) | bool has_leading_or_trailing_space_or_dot(const std::string& value) {
  function is_reserved_windows_name (line 50) | bool is_reserved_windows_name(const std::string& value) {
  function looks_like_extension_label (line 60) | bool looks_like_extension_label(const std::string& value) {
  function validate_labels (line 72) | bool validate_labels(const std::string& category,

FILE: app/lib/Settings.cpp
  function settings_log (line 28) | void settings_log(spdlog::level::level_enum level, const char* fmt, Args...
  function parse_int_or (line 37) | int parse_int_or(const std::string& value, int fallback) {
  function parse_list (line 45) | std::vector<std::string> parse_list(const std::string& value) {
  function trim_copy (line 60) | std::string trim_copy(const std::string& value) {
  function join_list (line 68) | std::string join_list(const std::vector<std::string>& items) {
  function to_bool_string (line 79) | std::string to_bool_string(bool value) {
  function encode_multiline (line 83) | std::string encode_multiline(const std::string& value) {
  function decode_multiline (line 98) | std::string decode_multiline(const std::string& value) {
  function llm_choice_to_string (line 121) | std::string llm_choice_to_string(LLMChoice choice) {
  function set_bool_setting (line 134) | void set_bool_setting(IniConfig& config, const std::string& section, con...
  function set_optional_setting (line 138) | void set_optional_setting(IniConfig& config, const std::string& section,...
  function generate_custom_llm_id (line 144) | std::string generate_custom_llm_id() {
  function generate_custom_api_id (line 154) | std::string generate_custom_api_id() {
  function Language (line 164) | Language system_default_language()
  function path_from_env_url (line 178) | std::string path_from_env_url(const char* env_key)
  function file_exists_for_env_url (line 191) | bool file_exists_for_env_url(const char* env_key)
  function LLMChoice (line 262) | LLMChoice Settings::parse_llm_choice() const
  function LLMChoice (line 591) | LLMChoice Settings::get_llm_choice() const
  function CustomLLM (line 689) | CustomLLM Settings::find_custom_llm(const std::string& id) const
  function CustomApiEndpoint (line 741) | CustomApiEndpoint Settings::find_custom_api_endpoint(const std::string& ...
  function CategoryLanguage (line 788) | CategoryLanguage Settings::get_category_language() const
  function Language (line 1110) | Language Settings::get_language() const

FILE: app/lib/SuitabilityBenchmarkDialog.cpp
  type VisualLlmPaths (line 56) | struct VisualLlmPaths {
  type PerfClass (line 63) | enum class PerfClass {
  type PerfThresholds (line 69) | struct PerfThresholds {
  function trim_copy (line 74) | std::string trim_copy(const std::string& value)
  function format_duration (line 83) | std::string format_duration(std::chrono::steady_clock::duration elapsed)
  function duration_seconds (line 92) | double duration_seconds(std::chrono::steady_clock::duration elapsed)
  function format_seconds (line 98) | std::string format_seconds(double seconds)
  function read_env_double (line 105) | double read_env_double(const char* key, double fallback)
  function PerfThresholds (line 124) | PerfThresholds thresholds_for_choice(LLMChoice choice)
  function PerfThresholds (line 146) | PerfThresholds thresholds_for_document_choice(LLMChoice choice)
  function PerfThresholds (line 168) | PerfThresholds image_thresholds()
  function PerfClass (line 175) | PerfClass classify_perf(double seconds, const PerfThresholds& thresholds)
  function perf_rank (line 186) | int perf_rank(PerfClass perf)
  function PerfClass (line 199) | PerfClass worst_perf(PerfClass a, PerfClass b)
  function QString (line 204) | QString perf_color(PerfClass perf)
  function QString (line 217) | QString highlight_figures(const QString& text)
  function QString (line 241) | QString bold_llm_label(const std::string& label)
  function QString (line 246) | QString colored_seconds(double seconds, PerfClass perf)
  function QString (line 253) | QString colored_seconds_list(const std::vector<double>& seconds,
  function format_mib (line 265) | std::string format_mib(size_t bytes)
  function to_lower_copy (line 273) | std::string to_lower_copy(std::string value)
  function read_env_lower (line 281) | std::string read_env_lower(const char* key)
  function read_env_value (line 290) | std::optional<std::string> read_env_value(const char* key)
  function set_env_value (line 299) | void set_env_value(const char* key, const std::optional<std::string>& va...
  function case_insensitive_contains (line 316) | bool case_insensitive_contains(std::string_view haystack, std::string_vi...
  function format_timestamp (line 326) | std::string format_timestamp(std::chrono::system_clock::time_point point)
  type DefaultModel (line 340) | struct DefaultModel {
  type BackendTarget (line 346) | struct BackendTarget {
  type BenchmarkBackendInfo (line 351) | struct BenchmarkBackendInfo {
  type EnvEntry (line 360) | struct EnvEntry {
  class EnvSnapshot (line 365) | class EnvSnapshot {
    method EnvSnapshot (line 367) | static EnvSnapshot capture(const std::array<const char*, 3>& keys)
    method restore (line 376) | void restore() const
  class ScopedEnvRestore (line 387) | class ScopedEnvRestore {
    method ScopedEnvRestore (line 389) | explicit ScopedEnvRestore(const EnvSnapshot& snapshot)
  function BackendTarget (line 403) | BackendTarget resolve_backend_target(std::string_view override_value)
  function format_backend_label (line 435) | std::string format_backend_label(std::string_view name)
  function resolve_default_model_path (line 456) | std::optional<std::filesystem::path> resolve_default_model_path(const ch...
  function collect_default_models (line 473) | std::vector<DefaultModel> collect_default_models()
  function detect_blas_backend_label (line 493) | std::optional<std::string> detect_blas_backend_label()
  type BackendMemorySnapshot (line 540) | struct BackendMemorySnapshot {
  function load_ggml_backends_once (line 546) | void load_ggml_backends_once()
  function query_backend_memory (line 562) | std::optional<BackendMemorySnapshot> query_backend_memory(std::string_vi...
  function is_backend_available (line 606) | bool is_backend_available(std::string_view backend_name)
  function QString (line 617) | QString build_cpu_backend_note(const QString& reason,
  function QString (line 633) | QString build_gpu_backend_note(const BackendTarget& target)
  function QString (line 638) | QString build_backend_note(const BackendTarget& target,
  function join_duration_list (line 666) | std::string join_duration_list(const std::vector<double>& seconds)
  function median_seconds (line 678) | double median_seconds(std::vector<double> seconds)
  function has_visual_llm_files (line 691) | bool has_visual_llm_files()
  function has_any_llm_available (line 696) | bool has_any_llm_available()
  function create_temp_dir (line 701) | std::filesystem::path create_temp_dir()
  function write_sample_document (line 760) | bool write_sample_document(const std::filesystem::path& path)
  function write_sample_image (line 779) | bool write_sample_image(const std::filesystem::path& path)
  function resolve_mmproj_path (line 795) | std::optional<std::filesystem::path> resolve_mmproj_path(const std::file...
  function resolve_visual_llm_paths (line 816) | std::optional<VisualLlmPaths> resolve_visual_llm_paths(std::string* error)
  function should_use_visual_gpu (line 857) | bool should_use_visual_gpu()
  function parse_category_pair (line 870) | std::optional<std::pair<std::string, std::string>> parse_category_pair(c...
  type StepResult (line 929) | struct StepResult {
  type TextModelOutcome (line 936) | struct TextModelOutcome {
    type ModelPerf (line 942) | struct ModelPerf {
  function StepResult (line 953) | StepResult run_categorization_test(ILLMClient& llm, const std::filesyste...
  function StepResult (line 976) | StepResult run_document_test(ILLMClient& llm, const std::filesystem::pat...
  function StepResult (line 1005) | StepResult run_image_test(const std::filesystem::path& temp_dir)
  function TextModelOutcome (line 1049) | TextModelOutcome run_text_model_checks(const std::vector<DefaultModel>& ...
    type ModelPerf (line 942) | struct ModelPerf {
  function QString (line 1301) | QString perf_label_qt(PerfClass perf)
  function QString (line 1314) | QString colored_perf_label(PerfClass perf)
  function QString (line 1321) | QString build_recommended_list(const QStringList& labels)
  function QStringList (line 1344) | QStringList build_result_lines(const TextModelOutcome& text_models,

FILE: app/lib/SupportCodeManager.cpp
  function trim_ascii (line 52) | std::string trim_ascii(std::string_view value) {
  function QByteArray (line 68) | QByteArray appendable_base64url(std::string_view segment) {
  function QByteArray (line 81) | QByteArray decode_base64url(std::string_view segment) {
  function is_supported_payload (line 91) | bool is_supported_payload(const QByteArray& payload) {
  function verify_signature (line 118) | bool verify_signature(const QByteArray& payload, const QByteArray& signa...
  function QByteArray (line 148) | QByteArray to_byte_array(std::uint32_t value) {
  function from_little_endian_u32 (line 157) | std::uint32_t from_little_endian_u32(const unsigned char* data) {
  function leading_u32 (line 164) | std::uint32_t leading_u32(const QByteArray& value) {
  function QByteArray (line 172) | QByteArray sha256_labeled(std::string_view label, std::initializer_list<...
  function random_salt (line 183) | std::array<unsigned char, kSaltSize> random_salt() {
  function QByteArray (line 195) | QByteArray to_byte_array(const std::array<unsigned char, kSaltSize>& val...
  function blob_filename (line 200) | std::filesystem::path blob_filename() {

FILE: app/lib/TranslationManager.cpp
  function build_languages (line 14) | std::vector<LanguageInfo> build_languages()
  function LanguageInfo (line 28) | const LanguageInfo* find_language_info(const std::vector<LanguageInfo>& ...
  function QStringList (line 39) | QStringList translation_search_paths()
  function TranslationManager (line 62) | TranslationManager& TranslationManager::instance()
  function Language (line 118) | Language TranslationManager::current_language() const

FILE: app/lib/UiTranslator.cpp
  function Widget (line 30) | Widget* raw_ptr(const QPointer<Widget>& pointer)
  type MenuEntry (line 199) | struct MenuEntry {
  type ActionEntry (line 221) | struct ActionEntry {
  function QString (line 375) | QString UiTranslator::tr(const char* source) const

FILE: app/lib/UpdateArchiveExtractor.cpp
  function ascii_lower_copy (line 18) | std::string ascii_lower_copy(std::string value)
  function is_directory_entry (line 26) | bool is_directory_entry(const std::string& entry_name)
  function is_installer_entry (line 31) | bool is_installer_entry(const std::string& entry_name)
  function sanitize_archive_path (line 37) | std::optional<std::filesystem::path> sanitize_archive_path(const std::st...
  function archive_error_message (line 61) | std::string archive_error_message(zip_t* archive)
  function extract_entry (line 67) | UpdateArchiveExtractor::ExtractionResult extract_entry(zip_t* archive,

FILE: app/lib/UpdateFeed.cpp
  function trim_copy (line 18) | std::string trim_copy(const std::string& value)
  function normalized_sha256 (line 27) | std::string normalized_sha256(std::string value)
  function has_platform_streams (line 46) | bool has_platform_streams(const Json::Value& update)
  function string_member (line 81) | std::string string_member(const Json::Value& object, const char* key)

FILE: app/lib/UpdateInstaller.cpp
  function update_installer_log (line 36) | void update_installer_log(spdlog::level::level_enum level, const char* f...
  function ascii_lower_copy (line 46) | std::string ascii_lower_copy(std::string value)
  function configure_tls (line 54) | void configure_tls(CURL* curl)
  function normalize_sha256 (line 64) | std::string normalize_sha256(std::string value)
  function safe_version_fragment (line 75) | std::string safe_version_fragment(std::string version)
  function installer_file_name_from_url (line 86) | std::string installer_file_name_from_url(const std::string& url)
  function is_archive_package (line 96) | bool is_archive_package(const std::filesystem::path& path)
  function replace_file (line 101) | bool replace_file(const std::filesystem::path& source,
  function FILE (line 124) | FILE* open_binary_file_for_write(const std::filesystem::path& path)
  function write_data (line 133) | size_t write_data(void* ptr, size_t size, size_t nmemb, FILE* stream)
  type DownloadContext (line 138) | struct DownloadContext {
  function progress_callback (line 143) | int progress_callback(void* clientp,
  function UpdatePreparationResult (line 193) | UpdatePreparationResult UpdateInstaller::prepare(const UpdateInfo& info,

FILE: app/lib/Updater.cpp
  function updater_log (line 35) | void updater_log(spdlog::level::level_enum level, const char* fmt, Args&...
  function trim_copy (line 44) | std::string trim_copy(const std::string& value)
  function env_string (line 53) | std::optional<std::string> env_string(const char* key)
  function env_flag_enabled (line 66) | bool env_flag_enabled(const char* key)
  function normalized_sha256_copy (line 80) | std::string normalized_sha256_copy(std::string value)
  function throw_for_http_status (line 91) | void throw_for_http_status(long http_code)
  function configure_tls (line 107) | void configure_tls(CURL* curl)
  function open_download_url (line 117) | void open_download_url(const std::string& url)
  function UpdatePreparationResult (line 320) | UpdatePreparationResult Updater::prepare_installer_update(const UpdateIn...
  function WriteCallback (line 438) | size_t WriteCallback(void* contents, size_t size, size_t nmemb, void* us...
  type curl_slist (line 471) | struct curl_slist
  function Version (line 498) | Version Updater::string_to_Version(const std::string& version_str) {

FILE: app/lib/UpdaterLiveTestConfig.cpp
  function trim_copy (line 13) | std::string trim_copy(const std::string& value)
  function read_ini_value (line 23) | std::optional<std::string> read_ini_value(const IniConfig& config,
  function read_live_test_value (line 39) | std::optional<std::string> read_live_test_value(const IniConfig& config,
  function find_updater_live_test_ini (line 50) | std::optional<std::filesystem::path> find_updater_live_test_ini(const st...
  function load_missing_values_from_live_test_ini (line 73) | std::optional<std::filesystem::path> load_missing_values_from_live_test_...

FILE: app/lib/Utils.cpp
  function log_core (line 26) | void log_core(spdlog::level::level_enum level, const char* fmt, Args&&.....
  function to_forward_slashes (line 35) | std::string to_forward_slashes(std::string value) {
  function trim_leading_separators (line 40) | std::string trim_leading_separators(std::string value) {
  function try_utf8_to_path (line 49) | std::optional<std::filesystem::path> try_utf8_to_path(const std::string&...
  function collect_user_prefixes (line 57) | std::vector<std::string> collect_user_prefixes() {
  function strip_prefix (line 94) | std::optional<std::string> strip_prefix(const std::string& path,
  function LibraryHandle (line 149) | LibraryHandle loadLibrary(const char* name) {
  function closeLibrary (line 157) | void closeLibrary(LibraryHandle lib) {
  function LibraryHandle (line 163) | LibraryHandle loadLibrary(const char* name) {
  function closeLibrary (line 171) | void closeLibrary(LibraryHandle lib) {
  function hex_char_value (line 361) | int hex_char_value(char c)
  function combine_hex_pair (line 375) | unsigned char combine_hex_pair(char high, char low)
  type DevicePropShim (line 519) | struct DevicePropShim {
  function packaged_llm_path (line 574) | std::optional<std::filesystem::path> packaged_llm_path()
  function LibraryHandle (line 674) | LibraryHandle open_cuda_runtime() {
  function resolve_cuda_symbols (line 689) | bool resolve_cuda_symbols(LibraryHandle handle,
  type TestHooks (line 756) | namespace TestHooks {
    function set_cuda_availability_probe (line 758) | void set_cuda_availability_probe(CudaAvailabilityProbe probe) {
    function reset_cuda_availability_probe (line 762) | void reset_cuda_availability_probe() {
    function set_cuda_memory_probe (line 766) | void set_cuda_memory_probe(CudaMemoryProbe probe) {
    function reset_cuda_memory_probe (line 770) | void reset_cuda_memory_probe() {
  function trim_ws (line 874) | std::string trim_ws(const std::string& value) {

FILE: app/lib/WhitelistManagerDialog.cpp
  function QString (line 16) | QString join_lines(const std::vector<std::string>& items) {
  function split_lines (line 24) | std::vector<std::string> split_lines(const QString& text) {
  type EditDialogResult (line 35) | struct EditDialogResult {
  function show_edit_dialog (line 41) | std::optional<EditDialogResult> show_edit_dialog(QWidget* parent,

FILE: app/lib/WhitelistStore.cpp
  function split_csv (line 9) | std::vector<std::string> split_csv(const QString& value) {
  function QString (line 21) | QString join_csv(const std::vector<std::string>& values) {

FILE: app/main.cpp
  function initialize_loggers (line 47) | bool initialize_loggers()
  type ParsedArguments (line 64) | struct ParsedArguments {
  function consume_prefixed_value (line 72) | bool consume_prefixed_value(const char* argument,
  function env_has_value (line 84) | bool env_has_value(const char* key)
  function set_process_env (line 90) | void set_process_env(const char* key, const std::string& value)
  function apply_updater_live_test_environment (line 99) | void apply_updater_live_test_environment(const UpdaterLiveTestConfig& args)
  function ParsedArguments (line 132) | ParsedArguments parse_command_line(int argc, char** argv)
  function ensure_ggml_backend_dir (line 189) | void ensure_ggml_backend_dir()
  function allow_direct_launch (line 220) | bool allow_direct_launch(int argc, char** argv)
  function enable_per_monitor_dpi_awareness (line 235) | void enable_per_monitor_dpi_awareness()
  function attach_console_if_requested (line 257) | void attach_console_if_requested(bool enable)
  function QPixmap (line 271) | [[maybe_unused]] QPixmap build_splash_pixmap()
  class SplashController (line 298) | class SplashController {
    method SplashController (line 300) | explicit SplashController(QApplication& app)
    method set_target (line 306) | void set_target(QWidget* target)
    method keep_visible_for (line 311) | void keep_visible_for(int minimum_duration_ms)
    method finish (line 316) | void finish()
  function file_exists (line 327) | bool file_exists(const std::string& path)
  function has_local_model_for_env (line 336) | bool has_local_model_for_env(const char* env_key)
  function llm_choice_is_ready (line 353) | bool llm_choice_is_ready(const Settings& settings)
  function ensure_llm_choice (line 405) | bool ensure_llm_choice(Settings& settings, const std::function<void()>& ...
  function run_application (line 439) | int run_application(const ParsedArguments& parsed_args)
  function main (line 485) | int main(int argc, char **argv) {

FILE: app/scripts/gen_run_wrapper.py
  function main (line 7) | def main():

FILE: app/startapp_linux.cpp
  type BackendSelection (line 12) | enum class BackendSelection {
  function getExecutableDirectory (line 18) | std::string getExecutableDirectory() {
  function fileExists (line 27) | bool fileExists(const std::string& path) {
  function addToLdLibraryPath (line 33) | void addToLdLibraryPath(const std::string& dir) {
  function isCudaInstalled (line 43) | bool isCudaInstalled() {
  function isVulkanAvailable (line 47) | bool isVulkanAvailable() {
  function collect_environment_variables (line 62) | std::vector<std::string> collect_environment_variables()
  function ensure_executable (line 71) | void ensure_executable(const std::string& exePath)
  function set_or_append_env (line 80) | void set_or_append_env(std::vector<std::string>& envVars,
  function build_envp (line 93) | std::vector<char*> build_envp(std::vector<std::string>& envVars)
  function build_argv (line 104) | std::vector<char*> build_argv(const std::string& exePath, int argc, char...
  function launch_with_env (line 123) | void launch_with_env(const std::string& exePath,
  function launchMainApp (line 133) | void launchMainApp(const std::string& exeDir,
  type BackendOverrideFlags (line 166) | struct BackendOverrideFlags {
  function BackendOverrideFlags (line 171) | BackendOverrideFlags parse_backend_overrides(int argc, char* argv[])
  function validate_overrides (line 185) | bool validate_overrides(const BackendOverrideFlags& overrides)
  type BackendState (line 195) | struct BackendState {
  function BackendState (line 204) | BackendState decide_backend(const BackendOverrideFlags& overrides,
  function main (line 255) | int main(int argc, char* argv[]) {

FILE: app/startapp_windows.cpp
  type BackendOverride (line 29) | enum class BackendOverride {
  type BackendSelection (line 35) | enum class BackendSelection {
  function BackendOverride (line 41) | BackendOverride parseBackendOverride(QString value) {
  function enableSecureDllSearch (line 52) | bool enableSecureDllSearch()
  function addDllDirectoryChecked (line 69) | void addDllDirectoryChecked(const QString& directory)
  function tryLoadLibrary (line 87) | bool tryLoadLibrary(const QString& name) {
  function QStringList (line 96) | QStringList candidateGgmlDirectories(const QString& exeDir, const QStrin...
  function isCudaRuntimePresent (line 121) | bool isCudaRuntimePresent(const QList<int>& versions, QString *loadedRun...
  function isCudaAvailable (line 135) | bool isCudaAvailable(QString *loadedRuntime = nullptr) {
  function isRequiredCudaRuntimePresent (line 139) | bool isRequiredCudaRuntimePresent(QString *loadedRuntime = nullptr) {
  function loadVulkanLibrary (line 143) | bool loadVulkanLibrary(const QString& path) {
  function isVulkanRuntimeAvailable (line 153) | bool isVulkanRuntimeAvailable(const QString& exeDir) {
  function isNvidiaDriverAvailable (line 180) | bool isNvidiaDriverAvailable() {
  function appendToProcessPath (line 195) | void appendToProcessPath(const QString& directory) {
  function promptCudaDownload (line 210) | bool promptCudaDownload() {
  function launchMainExecutable (line 227) | bool launchMainExecutable(const QString& executablePath,
  function QString (line 258) | QString resolveExecutableName(const QString& baseDir) {
  type BackendOverrides (line 274) | struct BackendOverrides {
  type UpdaterLiveTestArgs (line 280) | struct UpdaterLiveTestArgs {
  type BackendAvailability (line 288) | struct BackendAvailability {
  function BackendOverrides (line 299) | BackendOverrides parse_backend_overrides(int argc, char* argv[])
  function consume_flag_value (line 314) | bool consume_flag_value(const QString& argument, const char* prefix, QSt...
  function UpdaterLiveTestArgs (line 324) | UpdaterLiveTestArgs parse_updater_live_test_args(int argc, char* argv[])
  function QProcessEnvironment (line 349) | QProcessEnvironment build_updater_live_test_environment(const UpdaterLiv...
  function log_observed_arguments (line 372) | void log_observed_arguments(const QStringList& args)
  function maybe_prompt_cuda_download (line 380) | bool maybe_prompt_cuda_download(const BackendOverrides& overrides,
  function validate_override_conflict (line 405) | bool validate_override_conflict(const BackendOverrides& overrides)
  function BackendAvailability (line 417) | BackendAvailability detect_backend_availability(const QString& exeDir,
  function apply_override_flags (line 444) | void apply_override_flags(const BackendOverrides& overrides,
  function BackendSelection (line 457) | BackendSelection resolve_backend_selection(const BackendOverrides& overr...
  function QString (line 482) | QString incompatible_runtime_message(const BackendAvailability& availabi...
  function QString (line 490) | QString cpu_backend_message(const BackendAvailability& availability)
  function enable_per_monitor_dpi_awareness (line 504) | void enable_per_monitor_dpi_awareness()
  function log_runtime_availability (line 525) | void log_runtime_availability(const BackendAvailability& availability,
  function QString (line 548) | QString ggml_variant_for_selection(BackendSelection selection)
  function QString (line 561) | QString resolve_ggml_directory(const QString& exeDir,
  function configure_runtime_paths (line 587) | void configure_runtime_paths(const QString& exeDir,
  function QStringList (line 619) | QStringList build_forwarded_args(int argc, char* argv[], bool &console_l...
  function QString (line 637) | QString backend_tag_for_selection(BackendSelection selection)
  function QString (line 647) | QString llama_device_for_selection(BackendSelection selection)
  function launch_main_process (line 657) | bool launch_main_process(const QString& mainExecutable,
  function main (line 683) | int main(int argc, char* argv[]) {

FILE: external/libzip/examples/add-compressed-data.c
  type ctx (line 46) | struct ctx {
  function zip_int64_t (line 52) | zip_int64_t callback(zip_source_t* src, void *ud, void* data, zip_uint64...
  function zip_source_t (line 82) | zip_source_t* create_layered_compressed_source(zip_source_t* source, zip...
  function main (line 121) | int

FILE: external/libzip/examples/autoclose-archive.c
  type ctx (line 46) | struct ctx {
  function zip_int64_t (line 50) | zip_int64_t callback(zip_source_t* src, void *ud, void* data, zip_uint64...
  function zip_source_t (line 67) | zip_source_t* create_layered_autoclose(zip_source_t* source, zip_t *arch...
  function main (line 92) | int

FILE: external/libzip/examples/cmake-project/cmake-example.c
  function main (line 36) | int

FILE: external/libzip/examples/in-memory.c
  function get_data (line 42) | static int
  function modify_archive (line 85) | static int
  function use_data (line 92) | static int
  function main (line 123) | int

FILE: external/libzip/examples/windows-open.c
  function zip_t (line 36) | zip_t *

FILE: external/libzip/lib/compat.h
  type zip_int64_t (line 129) | typedef zip_int64_t zip_off_t;
  type zip_os_stat_t (line 130) | typedef struct _stat64 zip_os_stat_t;
  type zip_os_stat_t (line 140) | typedef struct stat zip_os_stat_t;
  type off_t (line 146) | typedef off_t zip_off_t;
  type zip_off_t (line 168) | typedef long zip_off_t;

FILE: external/libzip/lib/zip.h
  type zip_source_cmd (line 248) | enum zip_source_cmd {
  type zip_source_cmd_t (line 272) | typedef enum zip_source_cmd zip_source_cmd_t;
  type zip_source_args_seek (line 304) | struct zip_source_args_seek {
  type zip_source_args_seek_t (line 309) | typedef struct zip_source_args_seek zip_source_args_seek_t;
  type zip_error (line 315) | struct zip_error {
  type zip_stat (line 331) | struct zip_stat {
  type zip_buffer_fragment (line 344) | struct zip_buffer_fragment {
  type zip_file_attributes (line 349) | struct zip_file_attributes {
  type zip (line 366) | struct zip
  type zip_file (line 367) | struct zip_file
  type zip_source (line 368) | struct zip_source
  type zip_t (line 370) | typedef struct zip zip_t;
  type zip_error_t (line 371) | typedef struct zip_error zip_error_t;
  type zip_file_t (line 372) | typedef struct zip_file zip_file_t;
  type zip_file_attributes_t (line 373) | typedef struct zip_file_attributes zip_file_attributes_t;
  type zip_source_t (line 374) | typedef struct zip_source zip_source_t;
  type zip_stat_t (line 375) | typedef struct zip_stat zip_stat_t;
  type zip_buffer_fragment_t (line 376) | typedef struct zip_buffer_fragment zip_buffer_fragment_t;
  type zip_uint32_t (line 378) | typedef zip_uint32_t zip_flags_t;
  type zip_int64_t (line 380) | typedef zip_int64_t (*zip_source_callback)(void *_Nullable, void *_Nulla...
  type zip_int64_t (line 381) | typedef zip_int64_t (*zip_source_layered_callback)(zip_source_t *_Nonnul...

FILE: external/libzip/lib/zip_add.c
  function ZIP_EXTERN (line 46) | ZIP_EXTERN zip_int64_t

FILE: external/libzip/lib/zip_add_dir.c
  function ZIP_EXTERN (line 41) | ZIP_EXTERN zip_int64_t

FILE: external/libzip/lib/zip_add_entry.c
  function zip_int64_t (line 42) | zip_int64_t

FILE: external/libzip/lib/zip_algorithm_bzip2.c
  type ctx (line 40) | struct ctx {
  function zip_uint64_t (line 49) | static zip_uint64_t
  type ctx (line 62) | struct ctx
  type ctx (line 64) | struct ctx
  function deallocate (line 100) | static void
  function zip_uint16_t (line 108) | static zip_uint16_t
  function map_error (line 115) | static int
  function start (line 145) | static bool
  function end (line 174) | static bool
  function input (line 195) | static bool
  function end_of_input (line 211) | static bool end_of_input(void *ud) {
  function zip_compression_status_t (line 219) | static zip_compression_status_t

FILE: external/libzip/lib/zip_algorithm_deflate.c
  type ctx (line 40) | struct ctx {
  function zip_uint64_t (line 50) | static zip_uint64_t
  type ctx (line 65) | struct ctx
  type ctx (line 67) | struct ctx
  function deallocate (line 105) | static void
  function zip_uint16_t (line 113) | static zip_uint16_t
  function start (line 131) | static bool
  function end (line 162) | static bool
  function input (line 183) | static bool
  function end_of_input (line 199) | static bool end_of_input(void *ud) {
  function zip_compression_status_t (line 207) | static zip_compression_status_t

FILE: external/libzip/lib/zip_algorithm_xz.c
  type header_state (line 42) | enum header_state { INCOMPLETE, OUTPUT, DONE }
  type ctx (line 53) | struct ctx {
  function zip_uint64_t (line 85) | static zip_uint64_t
  type ctx (line 108) | struct ctx
  type ctx (line 110) | struct ctx
  function deallocate (line 150) | static void
  function zip_uint16_t (line 157) | static zip_uint16_t
  function map_error (line 173) | static int
  function start (line 192) | static bool
  function end (line 239) | static bool
  function input (line 248) | static bool
  function end_of_input (line 305) | static bool end_of_input(void *ud) {
  function zip_compression_status_t (line 313) | static zip_compression_status_t

FILE: external/libzip/lib/zip_algorithm_zstd.c
  type ctx (line 40) | struct ctx {
  function zip_uint64_t (line 51) | static zip_uint64_t
  type ctx (line 59) | struct ctx
  type ctx (line 61) | struct ctx
  function deallocate (line 101) | static void
  function zip_uint16_t (line 108) | static zip_uint16_t
  function map_error (line 114) | static int
  function start (line 139) | static bool
  function end (line 177) | static bool
  function input (line 200) | static bool
  function end_of_input (line 214) | static bool end_of_input(void *ud) {
  function zip_compression_status_t (line 222) | static zip_compression_status_t

FILE: external/libzip/lib/zip_buffer.c
  function zip_uint8_t (line 39) | zip_uint8_t *
  function _zip_buffer_free (line 45) | void
  function _zip_buffer_eof (line 59) | bool
  function zip_uint8_t (line 65) | zip_uint8_t *
  function zip_uint16_t (line 79) | zip_uint16_t
  function zip_uint32_t (line 91) | zip_uint32_t
  function zip_uint64_t (line 103) | zip_uint64_t
  function zip_uint8_t (line 115) | zip_uint8_t
  function zip_uint64_t (line 127) | zip_uint64_t
  function zip_uint64_t (line 133) | zip_uint64_t
  function zip_buffer_t (line 152) | zip_buffer_t *
  function zip_buffer_t (line 186) | zip_buffer_t *
  function zip_uint64_t (line 204) | zip_uint64_t
  function _zip_buffer_ok (line 210) | bool
  function zip_uint8_t (line 216) | zip_uint8_t *
  function _zip_buffer_put (line 229) | int
  function _zip_buffer_put_16 (line 242) | int
  function _zip_buffer_put_32 (line 257) | int
  function _zip_buffer_put_64 (line 274) | int
  function _zip_buffer_put_8 (line 295) | int
  function _zip_buffer_set_offset (line 309) | int _zip_buffer_set_offset(zip_buffer_t *buffer, zip_uint64_t offset) {
  function _zip_buffer_skip (line 322) | int
  function zip_uint64_t (line 333) | zip_uint64_t

FILE: external/libzip/lib/zip_close.c
  function ZIP_EXTERN (line 52) | ZIP_EXTERN int
  function add_data (line 304) | static int add_data(zip_t *za, zip_source_t *src, zip_dirent_t *de) {
  function copy_data (line 618) | static int
  function copy_source (line 654) | static int
  function write_cdir (line 705) | static int
  function _zip_changed (line 723) | int
  function write_data_descriptor (line 751) | static int
  function torrentzip_compare_names (line 786) | static int torrentzip_compare_names(const void *a, const void *b) {

FILE: external/libzip/lib/zip_crypto_commoncrypto.c
  function _zip_crypto_aes_free (line 43) | void
  function _zip_crypto_aes_encrypt_block (line 53) | bool
  function _zip_crypto_aes_t (line 61) | _zip_crypto_aes_t *
  function _zip_crypto_hmac_free (line 87) | void
  function _zip_crypto_hmac_t (line 98) | _zip_crypto_hmac_t *

FILE: external/libzip/lib/zip_crypto_gnutls.c
  function _zip_crypto_aes_t (line 40) | _zip_crypto_aes_t *
  function _zip_crypto_aes_encrypt_block (line 70) | bool
  function _zip_crypto_aes_free (line 87) | void
  function _zip_crypto_hmac_t (line 98) | _zip_crypto_hmac_t *
  function _zip_crypto_hmac_free (line 117) | void
  function ZIP_EXTERN (line 131) | ZIP_EXTERN bool

FILE: external/libzip/lib/zip_crypto_gnutls.h
  type _zip_crypto_aes_t (line 46) | typedef struct {

FILE: external/libzip/lib/zip_crypto_mbedtls.c
  function _zip_crypto_aes_t (line 46) | _zip_crypto_aes_t *
  function _zip_crypto_aes_free (line 61) | void
  function _zip_crypto_hmac_t (line 72) | _zip_crypto_hmac_t *
  function _zip_crypto_hmac_free (line 104) | void
  function _zip_crypto_pbkdf2 (line 115) | bool
  type zip_random_context_t (line 144) | typedef struct {
  function ZIP_EXTERN (line 149) | ZIP_EXTERN bool

FILE: external/libzip/lib/zip_crypto_openssl.c
  function _zip_crypto_hmac_t (line 44) | static _zip_crypto_hmac_t* hmac_new() {
  function hmac_free (line 52) | static void hmac_free(_zip_crypto_hmac_t* hmac) {
  function _zip_crypto_aes_t (line 65) | _zip_crypto_aes_t *
  function _zip_crypto_aes_free (line 111) | void
  function _zip_crypto_aes_encrypt_block (line 127) | bool
  function _zip_crypto_hmac_t (line 138) | _zip_crypto_hmac_t *
  function _zip_crypto_hmac_free (line 197) | void
  function _zip_crypto_hmac_output (line 215) | bool
  function ZIP_EXTERN (line 227) | ZIP_EXTERN bool

FILE: external/libzip/lib/zip_crypto_openssl.h
  type _zip_crypto_hmac_t (line 52) | struct _zip_crypto_hmac_t {
  type _zip_crypto_hmac_t (line 56) | typedef struct _zip_crypto_hmac_t _zip_crypto_hmac_t;

FILE: external/libzip/lib/zip_crypto_win.c
  function _zip_crypto_pbkdf2 (line 87) | bool
  type PRF_CTX (line 110) | typedef struct {
  function hmacFree (line 119) | static void
  function BOOL (line 131) | static BOOL
  function BOOL (line 149) | static BOOL
  function BOOL (line 189) | static BOOL
  function BOOL (line 210) | static BOOL
  function myxor (line 218) | static void
  function BOOL (line 224) | BOOL
  function _zip_crypto_pbkdf2 (line 291) | bool
  type _zip_crypto_aes_s (line 299) | struct _zip_crypto_aes_s {
  function _zip_crypto_aes_t (line 306) | _zip_crypto_aes_t *
  function _zip_crypto_aes_free (line 348) | void
  function _zip_crypto_aes_encrypt_block (line 369) | bool
  type _zip_crypto_hmac_s (line 376) | struct _zip_crypto_hmac_s {
  function _zip_crypto_hmac_t (line 387) | _zip_crypto_hmac_t *
  function _zip_crypto_hmac_free (line 446) | void
  function _zip_crypto_hmac (line 471) | bool
  function _zip_crypto_hmac_output (line 480) | bool
  function ZIP_EXTERN (line 489) | ZIP_EXTERN bool

FILE: external/libzip/lib/zip_crypto_win.h
  type _zip_crypto_aes_t (line 39) | typedef struct _zip_crypto_aes_s _zip_crypto_aes_t;
  type _zip_crypto_hmac_t (line 40) | typedef struct _zip_crypto_hmac_s _zip_crypto_hmac_t;

FILE: external/libzip/lib/zip_delete.c
  function ZIP_EXTERN (line 38) | ZIP_EXTERN int

FILE: external/libzip/lib/zip_dir_add.c
  function ZIP_EXTERN (line 43) | ZIP_EXTERN zip_int64_t

FILE: external/libzip/lib/zip_dirent.c
  function _zip_cdir_free (line 49) | void
  function zip_cdir_t (line 65) | zip_cdir_t *
  function _zip_cdir_grow (line 84) | bool
  function zip_int64_t (line 106) | zip_int64_t
  function zip_dirent_t (line 214) | zip_dirent_t *
  function _zip_dirent_finalize (line 233) | void
  function _zip_dirent_free (line 257) | void
  function _zip_dirent_merge (line 267) | bool
  function _zip_dirent_init (line 316) | void
  function _zip_dirent_needs_zip64 (line 346) | bool
  function zip_dirent_t (line 355) | zip_dirent_t *
  function zip_int64_t (line 377) | zip_int64_t
  function zip_dirent_process_ef_zip64 (line 642) | bool
  function zip_string_t (line 703) | static zip_string_t *
  function _zip_dirent_process_winzip_aes (line 746) | static bool
  function zip_int32_t (line 828) | zip_int32_t
  function _zip_dirent_write (line 872) | int
  function time_t (line 1120) | time_t
  function zip_extra_field_t (line 1141) | static zip_extra_field_t *
  function zip_dirent_t (line 1180) | zip_dirent_t *
  function _zip_u2d_time (line 1206) | int
  function _zip_dirent_apply_attributes (line 1231) | bool
  function zip_dirent_torrentzip_normalize (line 1308) | void
  function zip_dirent_check_consistency (line 1322) | int
  function time_t (line 1352) | time_t

FILE: external/libzip/lib/zip_discard.c
  function zip_discard (line 44) | void

FILE: external/libzip/lib/zip_entry.c
  function _zip_entry_finalize (line 37) | void
  function _zip_entry_init (line 45) | void

FILE: external/libzip/lib/zip_error.c
  function ZIP_EXTERN (line 39) | ZIP_EXTERN int
  function ZIP_EXTERN (line 45) | ZIP_EXTERN int
  function ZIP_EXTERN (line 51) | ZIP_EXTERN void
  function ZIP_EXTERN (line 58) | ZIP_EXTERN void
  function ZIP_EXTERN (line 65) | ZIP_EXTERN void
  function ZIP_EXTERN (line 82) | ZIP_EXTERN int
  function _zip_error_clear (line 91) | void
  function _zip_error_copy (line 101) | void
  function _zip_error_get (line 112) | void
  function zip_error_set (line 125) | void
  function zip_error_set_from_source (line 134) | void
  function zip_int64_t (line 145) | zip_int64_t

FILE: external/libzip/lib/zip_error_clear.c
  function ZIP_EXTERN (line 38) | ZIP_EXTERN void

FILE: external/libzip/lib/zip_error_get.c
  function ZIP_EXTERN (line 39) | ZIP_EXTERN void
  function ZIP_EXTERN (line 45) | ZIP_EXTERN zip_error_t *
  function ZIP_EXTERN (line 51) | ZIP_EXTERN zip_error_t *

FILE: external/libzip/lib/zip_error_get_sys_type.c
  function ZIP_EXTERN (line 38) | ZIP_EXTERN int

FILE: external/libzip/lib/zip_error_strerror.c
  function ZIP_EXTERN (line 42) | ZIP_EXTERN const char *

FILE: external/libzip/lib/zip_error_to_str.c
  function ZIP_EXTERN (line 42) | ZIP_EXTERN int

FILE: external/libzip/lib/zip_extra_field.c
  function zip_extra_field_t (line 40) | zip_extra_field_t *
  function zip_extra_field_t (line 66) | zip_extra_field_t *
  function _zip_ef_free (line 102) | void
  function zip_uint8_t (line 115) | const zip_uint8_t *
  function zip_extra_field_t (line 143) | zip_extra_field_t *
  function zip_extra_field_t (line 177) | zip_extra_field_t *
  function _zip_ef_parse (line 201) | bool
  function zip_extra_field_t (line 271) | zip_extra_field_t *
  function zip_uint16_t (line 300) | zip_uint16_t
  function _zip_ef_write (line 314) | int
  function _zip_read_local_ef (line 351) | int

FILE: external/libzip/lib/zip_extra_field_api.c
  function ZIP_EXTERN (line 38) | ZIP_EXTERN int
  function ZIP_EXTERN (line 70) | ZIP_EXTERN int
  function ZIP_EXTERN (line 106) | ZIP_EXTERN const zip_uint8_t *
  function ZIP_EXTERN (line 150) | ZIP_EXTERN const zip_uint8_t *
  function ZIP_EXTERN (line 170) | ZIP_EXTERN zip_int16_t
  function ZIP_EXTERN (line 197) | ZIP_EXTERN zip_int16_t
  function ZIP_EXTERN (line 224) | ZIP_EXTERN int
  function _zip_file_extra_field_prepare_for_change (line 330) | int

FILE: external/libzip/lib/zip_fclose.c
  function ZIP_EXTERN (line 40) | ZIP_EXTERN int

FILE: external/libzip/lib/zip_fdopen.c
  function ZIP_EXTERN (line 41) | ZIP_EXTERN zip_t *

FILE: external/libzip/lib/zip_file_add.c
  function ZIP_EXTERN (line 44) | ZIP_EXTERN zip_int64_t

FILE: external/libzip/lib/zip_file_error_clear.c
  function ZIP_EXTERN (line 38) | ZIP_EXTERN void

FILE: external/libzip/lib/zip_file_error_get.c
  function ZIP_EXTERN (line 38) | ZIP_EXTERN void

FILE: external/libzip/lib/zip_file_get_comment.c
  function ZIP_EXTERN (line 39) | ZIP_EXTERN const char *

FILE: external/libzip/lib/zip_file_get_external_attributes.c
  function zip_file_get_external_attributes (line 36) | int

FILE: external/libzip/lib/zip_file_get_offset.c
  function zip_uint64_t (line 47) | zip_uint64_t
  function zip_uint64_t (line 76) | zip_uint64_t

FILE: external/libzip/lib/zip_file_rename.c
  function ZIP_EXTERN (line 40) | ZIP_EXTERN int

FILE: external/libzip/lib/zip_file_replace.c
  function ZIP_EXTERN (line 38) | ZIP_EXTERN int
  function zip_int64_t (line 54) | zip_int64_t

FILE: external/libzip/lib/zip_file_set_comment.c
  function ZIP_EXTERN (line 40) | ZIP_EXTERN int

FILE: external/libzip/lib/zip_file_set_encryption.c
  function ZIP_EXTERN (line 40) | ZIP_EXTERN int

FILE: external/libzip/lib/zip_file_set_external_attributes.c
  function ZIP_EXTERN (line 36) | ZIP_EXTERN int

FILE: external/libzip/lib/zip_file_set_mtime.c
  function zip_file_set_time (line 36) | static int zip_file_set_time(zip_t *za, zip_uint64_t idx, zip_uint16_t d...
  function ZIP_EXTERN (line 80) | ZIP_EXTERN int zip_file_set_dostime(zip_t *za, zip_uint64_t idx, zip_uin...
  function ZIP_EXTERN (line 85) | ZIP_EXTERN int zip_file_set_mtime(zip_t *za, zip_uint64_t idx, time_t mt...

FILE: external/libzip/lib/zip_file_strerror.c
  function ZIP_EXTERN (line 38) | ZIP_EXTERN const char *

FILE: external/libzip/lib/zip_fopen.c
  function ZIP_EXTERN (line 38) | ZIP_EXTERN zip_file_t *

FILE: external/libzip/lib/zip_fopen_encrypted.c
  function ZIP_EXTERN (line 38) | ZIP_EXTERN zip_file_t *

FILE: external/libzip/lib/zip_fopen_index.c
  function ZIP_EXTERN (line 38) | ZIP_EXTERN zip_file_t *

FILE: external/libzip/lib/zip_fopen_index_encrypted.c
  function ZIP_EXTERN (line 43) | ZIP_EXTERN zip_file_t *
  function zip_file_t (line 72) | static zip_file_t *

FILE: external/libzip/lib/zip_fread.c
  function ZIP_EXTERN (line 38) | ZIP_EXTERN zip_int64_t

FILE: external/libzip/lib/zip_fseek.c
  function ZIP_EXTERN (line 37) | ZIP_EXTERN zip_int8_t
  function ZIP_EXTERN (line 56) | ZIP_EXTERN int

FILE: external/libzip/lib/zip_ftell.c
  function ZIP_EXTERN (line 37) | ZIP_EXTERN zip_int64_t

FILE: external/libzip/lib/zip_get_archive_comment.c
  function ZIP_EXTERN (line 40) | ZIP_EXTERN const char *

FILE: external/libzip/lib/zip_get_archive_flag.c
  function ZIP_EXTERN (line 38) | ZIP_EXTERN int

FILE: external/libzip/lib/zip_get_encryption_implementation.c
  function zip_encryption_implementation (line 38) | zip_encryption_implementation
  function ZIP_EXTERN (line 56) | ZIP_EXTERN int

FILE: external/libzip/lib/zip_get_file_comment.c
  function ZIP_EXTERN (line 39) | ZIP_EXTERN const char *

FILE: external/libzip/lib/zip_get_name.c
  function ZIP_EXTERN (line 40) | ZIP_EXTERN const char *

FILE: external/libzip/lib/zip_get_num_entries.c
  function ZIP_EXTERN (line 38) | ZIP_EXTERN zip_int64_t

FILE: external/libzip/lib/zip_get_num_files.c
  function ZIP_EXTERN (line 40) | ZIP_EXTERN int

FILE: external/libzip/lib/zip_hash.c
  type zip_hash_entry (line 50) | struct zip_hash_entry {
  type zip_hash_entry_t (line 57) | typedef struct zip_hash_entry zip_hash_entry_t;
  type zip_hash (line 59) | struct zip_hash {
  function free_list (line 67) | static void
  function zip_uint32_t (line 78) | static zip_uint32_t
  function hash_resize (line 96) | static bool
  function zip_uint32_t (line 135) | static zip_uint32_t
  function zip_hash_t (line 166) | zip_hash_t *
  function _zip_hash_free (line 183) | void
  function _zip_hash_add (line 204) | bool
  function _zip_hash_delete (line 263) | bool
  function zip_int64_t (line 311) | zip_int64_t
  function _zip_hash_reserve_capacity (line 346) | bool
  function _zip_hash_revert (line 368) | bool

FILE: external/libzip/lib/zip_io_util.c
  function _zip_read (line 41) | int
  function zip_uint8_t (line 64) | zip_uint8_t *
  function zip_string_t (line 108) | zip_string_t *
  function _zip_write (line 122) | int

FILE: external/libzip/lib/zip_libzip_version.c
  function ZIP_EXTERN (line 38) | ZIP_EXTERN const char *

FILE: external/libzip/lib/zip_name_locate.c
  function ZIP_EXTERN (line 43) | ZIP_EXTERN zip_int64_t
  function zip_int64_t (line 49) | zip_int64_t

FILE: external/libzip/lib/zip_new.c
  function zip_t (line 44) | zip_t *

FILE: external/libzip/lib/zip_open.c
  type exists_t (line 41) | typedef enum {
  type cdir_status_t (line 46) | typedef enum {
  function ZIP_EXTERN (line 67) | ZIP_EXTERN zip_t *
  function ZIP_EXTERN (line 92) | ZIP_EXTERN zip_t *
  function _is_truncated_zip (line 159) | static bool
  function zip_t (line 180) | zip_t *
  function _zip_set_open_error (line 266) | void
  function _zip_read_cdir (line 292) | static bool _zip_read_cdir(zip_t *za, zip_buffer_t *buffer, zip_uint64_t...
  function check_magic (line 503) | static bool check_magic(zip_uint64_t offset, zip_buffer_t *buffer, zip_u...
  function zip_int64_t (line 528) | static zip_int64_t
  function _zip_headercomp (line 598) | static int
  function zip_t (line 629) | static zip_t *
  function exists_t (line 655) | static exists_t
  function zip_cdir_t (line 673) | static zip_cdir_t *
  function zip_cdir_t (line 760) | static zip_cdir_t *
  function check_eocd (line 790) | static bool
  function cdir_status_t (line 810) | cdir_status_t _zip_read_eocd64(zip_cdir_t *cdir, zip_source_t *src, zip_...
  function decode_hex (line 948) | static int
  function zip_check_torrentzip (line 964) | static void

FILE: external/libzip/lib/zip_pkware.c
  function update_keys (line 45) | static void
  function zip_uint8_t (line 54) | static zip_uint8_t
  function _zip_pkware_keys_reset (line 63) | void
  function _zip_pkware_encrypt (line 71) | void
  function _zip_pkware_decrypt (line 94) | void

FILE: external/libzip/lib/zip_progress.c
  type zip_progress (line 41) | struct zip_progress {
  function _zip_progress_end (line 67) | void
  function _zip_progress_free (line 73) | void
  function zip_progress_t (line 86) | static zip_progress_t *
  function _zip_progress_free_progress_callback (line 109) | static void
  function _zip_progress_free_cancel_callback (line 120) | static void
  function _zip_progress_set_progress_callback (line 131) | static void
  function _zip_progress_set_cancel_callback (line 141) | void
  function _zip_progress_start (line 150) | int
  function _zip_progress_subrange (line 171) | int
  function _zip_progress_update (line 183) | int
  function ZIP_EXTERN (line 210) | ZIP_EXTERN int
  function ZIP_EXTERN (line 237) | ZIP_EXTERN int
  type legacy_ud (line 264) | struct legacy_ud {
  function _zip_legacy_progress_callback (line 269) | static void
  function ZIP_EXTERN (line 276) | ZIP_EXTERN void

FILE: external/libzip/lib/zip_random_unix.c
  function ZIP_EXTERN (line 45) | ZIP_EXTERN bool
  function zip_uint32_t (line 53) | zip_uint32_t
  function ZIP_EXTERN (line 65) | ZIP_EXTERN bool
  function zip_uint32_t (line 91) | zip_uint32_t

FILE: external/libzip/lib/zip_random_uwp.c
  function ZIP_EXTERN (line 45) | ZIP_EXTERN bool
  function zip_uint32_t (line 65) | zip_uint32_t

FILE: external/libzip/lib/zip_random_win32.c
  function ZIP_EXTERN (line 46) | ZIP_EXTERN bool
  function zip_uint32_t (line 65) | zip_uint32_t

FILE: external/libzip/lib/zip_realloc.c
  function zip_realloc (line 38) | bool zip_realloc(void **memory, zip_uint64_t *alloced_elements, zip_uint...

FILE: external/libzip/lib/zip_rename.c
  function ZIP_EXTERN (line 39) | ZIP_EXTERN int

FILE: external/libzip/lib/zip_replace.c
  function ZIP_EXTERN (line 39) | ZIP_EXTERN int

FILE: external/libzip/lib/zip_set_archive_comment.c
  function ZIP_EXTERN (line 40) | ZIP_EXTERN int

FILE: external/libzip/lib/zip_set_archive_flag.c
  function ZIP_EXTERN (line 38) | ZIP_EXTERN int

FILE: external/libzip/lib/zip_set_default_password.c
  function ZIP_EXTERN (line 41) | ZIP_EXTERN int

FILE: external/libzip/lib/zip_set_file_comment.c
  function ZIP_EXTERN (line 39) | ZIP_EXTERN int

FILE: external/libzip/lib/zip_set_file_compression.c
  function ZIP_EXTERN (line 38) | ZIP_EXTERN int

FILE: external/libzip/lib/zip_set_name.c
  function _zip_set_name (line 41) | int

FILE: external/libzip/lib/zip_source_accept_empty.c
  function zip_source_accept_empty (line 38) | bool

FILE: external/libzip/lib/zip_source_begin_write.c
  function ZIP_EXTERN (line 38) | ZIP_EXTERN int

FILE: external/libzip/lib/zip_source_begin_write_cloning.c
  function ZIP_EXTERN (line 38) | ZIP_EXTERN int

FILE: external/libzip/lib/zip_source_buffer.c
  type buffer (line 43) | struct buffer {
  type buffer_t (line 59) | typedef struct buffer buffer_t;
  type read_data (line 61) | struct read_data {
  function ZIP_EXTERN (line 87) | ZIP_EXTERN zip_source_t *
  function ZIP_EXTERN (line 96) | ZIP_EXTERN zip_source_t *
  function zip_source_t (line 102) | zip_source_t *
  function ZIP_EXTERN (line 122) | ZIP_EXTERN zip_source_t *
  function ZIP_EXTERN (line 132) | ZIP_EXTERN zip_source_t *
  function zip_source_t (line 137) | zip_source_t *
  function zip_source_t (line 179) | zip_source_t *
  function zip_int64_t (line 184) | static zip_int64_t
  function buffer_t (line 321) | static buffer_t *
  function zip_uint64_t (line 377) | static zip_uint64_t
  function buffer_free (line 405) | static void
  function buffer_grow_fragments (line 429) | static bool
  function buffer_t (line 453) | static buffer_t *
  function zip_int64_t (line 514) | static zip_int64_t
  function buffer_seek (line 551) | static int
  function zip_int64_t (line 565) | static zip_int64_t

FILE: external/libzip/lib/zip_source_call.c
  function zip_int64_t (line 38) | zip_int64_t

FILE: external/libzip/lib/zip_source_close.c
  function zip_source_close (line 38) | int

FILE: external/libzip/lib/zip_source_commit_write.c
  function ZIP_EXTERN (line 38) | ZIP_EXTERN int

FILE: external/libzip/lib/zip_source_compress.c
  type context (line 39) | struct context {
  type implementation (line 59) | struct implementation {
  type implementation (line 65) | struct implementation
  type context (line 89) | struct context
  type context (line 90) | struct context
  type context (line 91) | struct context
  function zip_compression_algorithm_t (line 93) | zip_compression_algorithm_t *_zip_get_compression_algorithm(zip_int32_t ...
  function ZIP_EXTERN (line 111) | ZIP_EXTERN int zip_compression_method_supported(zip_int32_t method, int ...
  function zip_source_t (line 118) | zip_source_t *zip_source_compress(zip_t *za, zip_source_t *src, zip_int3...
  function zip_source_t (line 122) | zip_source_t *
  function zip_source_t (line 128) | static zip_source_t *compression_source_new(zip_t *za, zip_source_t *src...
  type context (line 157) | struct context
  type context (line 158) | struct context
  type context (line 160) | struct context
  function context_free (line 183) | static void
  function zip_int64_t (line 196) | static zip_int64_t
  function zip_int64_t (line 317) | static zip_int64_t

FILE: external/libzip/lib/zip_source_crc.c
  type crc_context (line 41) | struct crc_context {
  function zip_source_t (line 54) | zip_source_t *
  function zip_int64_t (line 79) | static zip_int64_t

FILE: external/libzip/lib/zip_source_error.c
  function zip_error_t (line 38) | zip_error_t *
  function _zip_source_had_error (line 43) | bool

FILE: external/libzip/lib/zip_source_file.h
  type zip_source_file_stat (line 37) | struct zip_source_file_stat {
  type zip_source_file_context_t (line 44) | typedef struct zip_source_file_context zip_source_file_context_t;
  type zip_source_file_operations_t (line 45) | typedef struct zip_source_file_operations zip_source_file_operations_t;
  type zip_source_file_stat_t (line 46) | typedef struct zip_source_file_stat zip_source_file_stat_t;
  type zip_source_file_context (line 48) | struct zip_source_file_context {
  type zip_source_file_operations (line 77) | struct zip_source_file_operations {

FILE: external/libzip/lib/zip_source_file_common.c
  function zip_source_file_stat_init (line 44) | static void
  function zip_source_t (line 52) | zip_source_t *
  function zip_int64_t (line 213) | static zip_int64_t

FILE: external/libzip/lib/zip_source_file_stdio.c
  function ZIP_EXTERN (line 68) | ZIP_EXTERN zip_source_t *
  function ZIP_EXTERN (line 78) | ZIP_EXTERN zip_source_t *
  function _zip_stdio_op_close (line 89) | void
  function zip_int64_t (line 95) | zip_int64_t
  function _zip_stdio_op_seek (line 115) | bool
  function _zip_stdio_op_stat (line 132) | bool
  function zip_int64_t (line 170) | zip_int64_t

FILE: external/libzip/lib/zip_source_file_stdio_named.c
  function ZIP_EXTERN (line 93) | ZIP_EXTERN zip_source_t *
  function ZIP_EXTERN (line 102) | ZIP_EXTERN zip_source_t *
  function zip_int64_t (line 113) | static zip_int64_t
  function zip_int64_t (line 128) | static zip_int64_t
  function zip_int64_t (line 149) | static zip_int64_t
  function _zip_stdio_op_open (line 241) | static bool
  function zip_int64_t (line 251) | static zip_int64_t
  function _zip_stdio_op_rollback_write (line 261) | static void
  function zip_int64_t (line 275) | static zip_int64_t
  function create_temp_file (line 290) | static int create_temp_file(zip_source_file_context_t *ctx, bool create_...
  function FILE (line 371) | static FILE *_zip_fopen_close_on_exec(const char *name, bool writeable) {

FILE: external/libzip/lib/zip_source_file_win32.c
  function ZIP_EXTERN (line 60) | ZIP_EXTERN zip_source_t *
  function ZIP_EXTERN (line 70) | ZIP_EXTERN zip_source_t *
  function _zip_win32_op_close (line 81) | void
  function zip_int64_t (line 87) | zip_int64_t
  function _zip_win32_op_seek (line 101) | bool
  function _zip_win32_op_stat (line 131) | static bool
  function zip_int64_t (line 137) | zip_int64_t
  function _zip_win32_error_to_errno (line 152) | int
  function _zip_stat_win32 (line 177) | static bool
  function _zip_filetime_to_time_t (line 212) | bool

FILE: external/libzip/lib/zip_source_file_win32.h
  type zip_win32_file_operations (line 52) | struct zip_win32_file_operations {
  type zip_win32_file_operations_t (line 65) | typedef struct zip_win32_file_operations zip_win32_file_operations_t;

FILE: external/libzip/lib/zip_source_file_win32_ansi.c
  function ZIP_EXTERN (line 61) | ZIP_EXTERN zip_source_t *
  function ZIP_EXTERN (line 70) | ZIP_EXTERN zip_source_t *
  function HANDLE (line 87) | static HANDLE __stdcall
  function BOOL (line 93) | static BOOL __stdcall
  function DWORD (line 99) | static DWORD __stdcall
  function BOOL (line 105) | static BOOL __stdcall
  function ansi_make_tempname (line 111) | static void
  function BOOL (line 116) | static BOOL __stdcall
  function BOOL (line 122) | static BOOL __stdcall
  function HANDLE (line 128) | static HANDLE __stdcall

FILE: external/libzip/lib/zip_source_file_win32_named.c
  function zip_int64_t (line 65) | static zip_int64_t
  function zip_int64_t (line 96) | static zip_int64_t
  function _zip_win32_named_op_open (line 155) | static bool
  function zip_int64_t (line 168) | static zip_int64_t
  function _zip_win32_named_op_rollback_write (line 181) | static void
  function _zip_win32_named_op_stat (line 192) | static bool
  function zip_int64_t (line 247) | static zip_int64_t
  function HANDLE (line 259) | static HANDLE

FILE: external/libzip/lib/zip_source_file_win32_utf16.c
  function ZIP_EXTERN (line 63) | ZIP_EXTERN zip_source_t *
  function ZIP_EXTERN (line 72) | ZIP_EXTERN zip_source_t *
  function HANDLE (line 91) | static HANDLE __stdcall utf16_create_file(const void *name, DWORD access...
  function BOOL (line 107) | static BOOL __stdcall
  function DWORD (line 113) | static DWORD __stdcall
  function BOOL (line 119) | static BOOL __stdcall
  function utf16_make_tempname (line 125) | static void
  function BOOL (line 130) | static BOOL __stdcall
  function BOOL (line 136) | static BOOL __stdcall
  function HANDLE (line 148) | static HANDLE __stdcall

FILE: external/libzip/lib/zip_source_file_win32_utf8.c
  function ZIP_EXTERN (line 36) | ZIP_EXTERN zip_source_t *
  function ZIP_EXTERN (line 46) | ZIP_EXTERN zip_source_t *

FILE: external/libzip/lib/zip_source_free.c
  function ZIP_EXTERN (line 40) | ZIP_EXTERN void

FILE: external/libzip/lib/zip_source_function.c
  function ZIP_EXTERN (line 40) | ZIP_EXTERN zip_source_t *
  function ZIP_EXTERN (line 50) | ZIP_EXTERN zip_source_t *
  function ZIP_EXTERN (line 70) | ZIP_EXTERN void
  function zip_source_t (line 76) | zip_source_t *

FILE: external/libzip/lib/zip_source_get_dostime.c
  function zip_source_get_dos_time (line 38) | int

FILE: external/libzip/lib/zip_source_get_file_attributes.c
  function ZIP_EXTERN (line 36) | ZIP_EXTERN void
  function zip_source_get_file_attributes (line 42) | int zip_source_get_file_attributes(zip_source_t *src, zip_file_attribute...

FILE: external/libzip/lib/zip_source_is_deleted.c
  function ZIP_EXTERN (line 38) | ZIP_EXTERN int

FILE: external/libzip/lib/zip_source_layered.c
  function zip_source_t (line 40) | zip_source_t *
  function zip_source_t (line 49) | zip_source_t *

FILE: external/libzip/lib/zip_source_open.c
  function ZIP_EXTERN (line 37) | ZIP_EXTERN int

FILE: external/libzip/lib/zip_source_pass_to_lower_layer.c
  function zip_int64_t (line 36) | zip_int64_t zip_source_pass_to_lower_layer(zip_source_t *src, void *data...

FILE: external/libzip/lib/zip_source_pkware_decode.c
  type trad_pkware (line 40) | struct trad_pkware {
  type trad_pkware (line 47) | struct trad_pkware
  type trad_pkware (line 49) | struct trad_pkware
  type trad_pkware (line 50) | struct trad_pkware
  function zip_source_t (line 53) | zip_source_t *
  function decrypt_header (line 80) | static int
  function zip_int64_t (line 131) | static zip_int64_t
  type trad_pkware (line 189) | struct trad_pkware
  type trad_pkware (line 191) | struct trad_pkware
  type trad_pkware (line 193) | struct trad_pkware
  function trad_pkware_free (line 210) | static void

FILE: external/libzip/lib/zip_source_pkware_encode.c
  type trad_pkware (line 40) | struct trad_pkware {
  type trad_pkware (line 50) | struct trad_pkware
  type trad_pkware (line 52) | struct trad_pkware
  type trad_pkware (line 53) | struct trad_pkware
  function zip_source_t (line 55) | zip_source_t *
  function encrypt_header (line 97) | static int
  function zip_int64_t (line 124) | static zip_int64_t
  type trad_pkware (line 233) | struct trad_pkware
  type trad_pkware (line 235) | struct trad_pkware
  type trad_pkware (line 237) | struct trad_pkware
  function trad_pkware_free (line 254) | static void

FILE: external/libzip/lib/zip_source_read.c
  function zip_int64_t (line 38) | zip_int64_t
  function _zip_source_eof (line 93) | bool

FILE: external/libzip/lib/zip_source_remove.c
  function zip_source_remove (line 38) | int

FILE: external/libzip/lib/zip_source_rollback_write.c
  function ZIP_EXTERN (line 38) | ZIP_EXTERN void

FILE: external/libzip/lib/zip_source_seek.c
  function ZIP_EXTERN (line 38) | ZIP_EXTERN int
  function zip_int64_t (line 62) | zip_int64_t

FILE: external/libzip/lib/zip_source_seek_write.c
  function ZIP_EXTERN (line 38) | ZIP_EXTERN int

FILE: external/libzip/lib/zip_source_stat.c
  function ZIP_EXTERN (line 38) | ZIP_EXTERN int

FILE: external/libzip/lib/zip_source_supports.c
  function zip_int64_t (line 40) | zip_int64_t
  function zip_source_supports_reopen (line 45) | bool
  function ZIP_EXTERN (line 50) | ZIP_EXTERN zip_int64_t
  function ZIP_EXTERN (line 72) | ZIP_EXTERN int zip_source_is_seekable(zip_source_t *src) {

FILE: external/libzip/lib/zip_source_tell.c
  function ZIP_EXTERN (line 38) | ZIP_EXTERN zip_int64_t

FILE: external/libzip/lib/zip_source_tell_write.c
  function ZIP_EXTERN (line 38) | ZIP_EXTERN zip_int64_t

FILE: external/libzip/lib/zip_source_window.c
  type window (line 40) | struct window {
  function ZIP_EXTERN (line 64) | ZIP_EXTERN zip_source_t *
  function zip_source_t (line 70) | zip_source_t *
  function _zip_source_set_source_archive (line 136) | int
  function _zip_source_invalidate (line 144) | void
  function zip_int64_t (line 154) | static zip_int64_t
  function _zip_deregister_source (line 346) | void
  function _zip_register_source (line 360) | int

FILE: external/libzip/lib/zip_source_winzip_aes_decode.c
  type winzip_aes (line 41) | struct winzip_aes {
  type winzip_aes (line 53) | struct winzip_aes
  type winzip_aes (line 54) | struct winzip_aes
  type winzip_aes (line 56) | struct winzip_aes
  function zip_source_t (line 59) | zip_source_t *
  function decrypt_header (line 102) | static int
  function verify_hmac (line 133) | static bool
  function zip_int64_t (line 157) | static zip_int64_t
  function winzip_aes_free (line 230) | static void
  type winzip_aes (line 244) | struct winzip_aes
  type winzip_aes (line 246) | struct winzip_aes
  type winzip_aes (line 248) | struct winzip_aes

FILE: external/libzip/lib/zip_source_winzip_aes_encode.c
  type winzip_aes (line 41) | struct winzip_aes {
  type winzip_aes (line 54) | struct winzip_aes
  type winzip_aes (line 55) | struct winzip_aes
  type winzip_aes (line 57) | struct winzip_aes
  function zip_source_t (line 60) | zip_source_t *
  function encrypt_header (line 83) | static int
  function zip_int64_t (line 106) | static zip_int64_t
  function winzip_aes_free (line 215) | static void
  type winzip_aes (line 230) | struct winzip_aes
  type winzip_aes (line 232) | struct winzip_aes
  type winzip_aes (line 234) | struct winzip_aes

FILE: external/libzip/lib/zip_source_write.c
  function ZIP_EXTERN (line 38) | ZIP_EXTERN zip_int64_t

FILE: external/libzip/lib/zip_source_zip.c
  function ZIP_EXTERN (line 40) | ZIP_EXTERN zip_source_t *zip_source_zip_create(zip_t *srcza, zip_uint64_...
  function ZIP_EXTERN (line 61) | ZIP_EXTERN zip_source_t *zip_source_zip(zip_t *za, zip_t *srcza, zip_uin...

FILE: external/libzip/lib/zip_source_zip_new.c
  function ZIP_EXTERN (line 41) | ZIP_EXTERN zip_source_t *zip_source_zip_file(zip_t* za, zip_t *srcza, zi...
  function ZIP_EXTERN (line 46) | ZIP_EXTERN zip_source_t *zip_source_zip_file_create(zip_t *srcza, zip_ui...
  function _zip_file_attributes_from_dirent (line 304) | static void

FILE: external/libzip/lib/zip_stat.c
  function ZIP_EXTERN (line 38) | ZIP_EXTERN int

FILE: external/libzip/lib/zip_stat_index.c
  function ZIP_EXTERN (line 38) | ZIP_EXTERN int

FILE: external/libzip/lib/zip_stat_init.c
  function ZIP_EXTERN (line 39) | ZIP_EXTERN void
  function _zip_stat_merge (line 53) | int

FILE: external/libzip/lib/zip_strerror.c
  function ZIP_EXTERN (line 38) | ZIP_EXTERN const char *

FILE: external/libzip/lib/zip_string.c
  function zip_uint32_t (line 41) | zip_uint32_t
  function _zip_string_equal (line 54) | int
  function _zip_string_free (line 68) | void
  function zip_uint8_t (line 79) | const zip_uint8_t *
  function _zip_string_is_ascii (line 112) | bool _zip_string_is_ascii(const zip_string_t *string) {
  function zip_uint16_t (line 127) | zip_uint16_t
  function zip_string_t (line 136) | zip_string_t *
  function _zip_string_write (line 188) | int

FILE: external/libzip/lib/zip_unchange.c
  function ZIP_EXTERN (line 40) | ZIP_EXTERN int
  function _zip_unchange (line 46) | int

FILE: external/libzip/lib/zip_unchange_all.c
  function ZIP_EXTERN (line 38) | ZIP_EXTERN int

FILE: external/libzip/lib/zip_unchange_archive.c
  function ZIP_EXTERN (line 40) | ZIP_EXTERN int

FILE: external/libzip/lib/zip_unchange_data.c
  function _zip_unchange_data (line 37) | void

FILE: external/libzip/lib/zip_utf-8.c
  function zip_encoding_type_t (line 99) | zip_encoding_type_t
  function zip_uint32_t (line 211) | static zip_uint32_t
  function zip_uint32_t (line 226) | static zip_uint32_t
  function zip_uint8_t (line 251) | zip_uint8_t *

FILE: external/libzip/lib/zip_winzip_aes.c
  type _zip_winzip_aes (line 45) | struct _zip_winzip_aes {
  function aes_crypt (line 53) | static bool
  function zip_winzip_aes_t (line 77) | zip_winzip_aes_t *
  function _zip_winzip_aes_encrypt (line 135) | bool
  function _zip_winzip_aes_decrypt (line 141) | bool
  function _zip_winzip_aes_finish (line 147) | bool
  function _zip_winzip_aes_free (line 153) | void

FILE: external/libzip/lib/zipint.h
  type zip_source_t (line 121) | typedef zip_source_t *(*zip_encryption_implementation)(zip_t *, zip_sour...
  type zip_compression_status (line 126) | enum zip_compression_status {
  type zip_compression_status_t (line 133) | typedef enum zip_compression_status zip_compression_status_t;
  type zip_compression_algorithm (line 135) | struct zip_compression_algorithm {
  type zip_compression_algorithm_t (line 163) | typedef struct zip_compression_algorithm zip_compression_algorithm_t;
  type zip_les (line 199) | enum zip_les { ZIP_LES_NONE, ZIP_LES_UPPER, ZIP_LES_LOWER, ZIP_LES_INVAL }
  type _zip_err_info (line 204) | struct _zip_err_info {
  type _zip_err_info (line 209) | struct _zip_err_info
  type _zip_err_info (line 211) | struct _zip_err_info
  type zip_encoding_type (line 268) | enum zip_encoding_type {
  type zip_encoding_type_t (line 277) | typedef enum zip_encoding_type zip_encoding_type_t;
  type zip_hash (line 279) | struct zip_hash
  type zip_progress (line 280) | struct zip_progress
  type zip_cdir_t (line 282) | typedef struct zip_cdir zip_cdir_t;
  type zip_dostime_t (line 283) | typedef struct zip_dostime zip_dostime_t;
  type zip_dirent_t (line 284) | typedef struct zip_dirent zip_dirent_t;
  type zip_entry_t (line 285) | typedef struct zip_entry zip_entry_t;
  type zip_extra_field_t (line 286) | typedef struct zip_extra_field zip_extra_field_t;
  type zip_string_t (line 287) | typedef struct zip_string zip_string_t;
  type zip_buffer_t (line 288) | typedef struct zip_buffer zip_buffer_t;
  type zip_hash_t (line 289) | typedef struct zip_hash zip_hash_t;
  type zip_progress_t (line 290) | typedef struct zip_progress zip_progress_t;
  type zip (line 294) | struct zip {
  type zip_file (line 326) | struct zip_file {
  type zip_dostime (line 343) | struct zip_dostime {
  type zip_dirent (line 348) | struct zip_dirent {
  type zip_cdir (line 381) | struct zip_cdir {
  type zip_extra_field (line 397) | struct zip_extra_field {
  type zip_source_write_state (line 405) | enum zip_source_write_state {
  type zip_source_write_state_t (line 411) | typedef enum zip_source_write_state zip_source_write_state_t;
  type zip_source (line 413) | struct zip_source {
  type zip_entry (line 438) | struct zip_entry {
  type zip_string (line 448) | struct zip_string {
  type zip_buffer (line 476) | struct zip_buffer {
  type zip_filelist (line 487) | struct zip_filelist {
  type zip_filelist_t (line 492) | typedef struct zip_filelist zip_filelist_t;
  type _zip_winzip_aes (line 494) | struct _zip_winzip_aes
  type zip_winzip_aes_t (line 495) | typedef struct _zip_winzip_aes zip_winzip_aes_t;
  type _zip_pkware_keys (line 497) | struct _zip_pkware_keys {
  type zip_pkware_keys_t (line 500) | typedef struct _zip_pkware_keys zip_pkware_keys_t;
  type zip_encoding_type (line 605) | enum zip_encoding_type
  type zip_encoding_type (line 605) | enum zip_encoding_type

FILE: external/libzip/ossfuzz/fuzz_main.c
  function main (line 9) | int

FILE: external/libzip/ossfuzz/zip_read_file_fuzzer.c
  function LLVMFuzzerTestOneInput (line 51) | int

FILE: external/libzip/ossfuzz/zip_read_fuzzer.c
  function LLVMFuzzerTestOneInput (line 9) | int

FILE: external/libzip/ossfuzz/zip_read_fuzzer_common.h
  function fuzzer_read (line 36) | void fuzzer_read(zip_t *za, zip_error_t *error, const char *password) {

FILE: external/libzip/ossfuzz/zip_write_encrypt_aes256_file_fuzzer.c
  function LLVMFuzzerTestOneInput (line 21) | int

FILE: external/libzip/ossfuzz/zip_write_encrypt_pkware_file_fuzzer.c
  function LLVMFuzzerTestOneInput (line 22) | int

FILE: external/libzip/regress/add_from_filep.c
  function main (line 43) | int

FILE: external/libzip/regress/can_clone_file.c
  function main (line 55) | int

FILE: external/libzip/regress/fopen_unchanged.c
  function main (line 44) | int

FILE: external/libzip/regress/fread.c
  type when (line 45) | enum when { WHEN_NEVER, WHEN_OPEN, WHEN_READ, WHEN_CLOSE }
  type when (line 49) | enum when
  function main (line 56) | int
  function do_read (line 167) | static int

FILE: external/libzip/regress/fseek.c
  function main (line 41) | int

FILE: external/libzip/regress/hole.c
  function copy_source (line 52) | static int
  function zip_source_t (line 96) | static zip_source_t *
  function zip_source_t (line 113) | static zip_source_t *
  function usage (line 130) | static void
  function main (line 138) | int

FILE: external/libzip/regress/liboverride-test.c
  function main (line 40) | int main(int argc, const char *argv[]) {
  function main (line 58) | int

FILE: external/libzip/regress/liboverride.c
  function zip_source_t (line 41) | zip_source_t *

FILE: external/libzip/regress/malloc.c
  function init (line 79) | static void

FILE: external/libzip/regress/nonrandomopen.c
  function zip_secure_random (line 39) | bool

FILE: external/libzip/regress/nonrandomopentest.c
  function main (line 39) | int

FILE: external/libzip/regress/source_hole.c
  type buffer_t (line 60) | typedef struct buffer {
  type hole_t (line 82) | typedef struct hole {
  function zip_source_t (line 93) | zip_source_t *
  function buffer_free (line 104) | static void
  function buffer_t (line 122) | static buffer_t *
  function buffer_t (line 153) | static buffer_t *
  function zip_int64_t (line 171) | static zip_int64_t
  function buffer_read_file (line 207) | static int
  function zip_int64_t (line 282) | static zip_int64_t
  function buffer_to_file (line 295) | static int
  function zip_int64_t (line 339) | static zip_int64_t
  function zip_uint64_t (line 403) | static zip_uint64_t
  function only_nul (line 413) | static int
  function write_nuls (line 427) | static int
  function write_u64 (line 436) | static int
  function hole_free (line 453) | static void
  function hole_t (line 466) | static hole_t *
  function zip_int64_t (line 493) | static zip_int64_t

FILE: external/libzip/regress/tryopen.c
  function main (line 53) | int

FILE: external/libzip/regress/ziptool_regress.c
  type source_type_t (line 9) | typedef enum { SOURCE_TYPE_NONE, SOURCE_TYPE_IN_MEMORY, SOURCE_TYPE_HOLE...
  function get_stdin_commands (line 96) | int get_stdin_commands(void) {
  function add_nul (line 133) | static int
  function cancel_callback (line 151) | static int
  function cancel (line 159) | static int
  function extract_as (line 176) | static int
  function is_seekable (line 196) | static int
  function regress_fseek (line 220) | static int
  function unchange_all (line 243) | static int
  function unchange_one (line 253) | static int
  function zin_close (line 267) | static int
  function regress_fopen (line 286) | static int
  function regress_fread (line 302) | static int
  function zip_t (line 349) | static zip_t *
  function get_whence (line 367) | static int get_whence(const char *str) {
  function zip_t (line 383) | static zip_t *
  type source_nul_t (line 494) | typedef struct source_nul {
  function zip_int64_t (line 500) | static zip_int64_t
  function zip_source_t (line 555) | static zip_source_t *
  function write_memory_src_to_file (line 578) | static int
  function zip_t (line 631) | zip_t *
  function ziptool_post_close (line 651) | int

FILE: external/libzip/src/diff_output.c
  function ensure_header (line 10) | static void
  function diff_output_init (line 20) | void
  function diff_output_start_file (line 31) | void
  function diff_output_end_file (line 39) | void
  function diff_output (line 44) | void
  function diff_output_file (line 66) | void
  function diff_output_data (line 83) | void

FILE: external/libzip/src/diff_output.h
  type diff_output_t (line 6) | typedef struct {

FILE: external/libzip/src/getopt.c
  function getopt (line 58) | int

FILE: external/libzip/src/zipcmp.c
  type archive (line 60) | struct archive {
  type ef (line 69) | struct ef {
  type entry (line 77) | struct entry {
  type enum_map_t (line 90) | typedef struct {
  type entry (line 189) | struct entry
  type entry (line 189) | struct entry
  type entry (line 192) | struct entry
  type archive (line 202) | struct archive
  type archive (line 204) | struct archive
  function main (line 213) | int
  function compare_zip (line 278) | static int
  function zip_int64_t (line 364) | static zip_int64_t
  function is_directory (line 394) | static int
  function list_directory (line 406) | static int
  function list_zip (line 529) | static int
  function comment_compare (line 589) | static int
  function compare_list (line 604) | static int
  function ef_read (line 660) | static int
  function ef_compare (line 695) | static int
  function ef_order (line 709) | static int
  function ef_print (line 726) | static void
  function entry_cmp (line 734) | static int
  function entry_ignore (line 761) | static int
  function entry_paranoia_checks (line 788) | static int
  function entry_print (line 818) | static void
  function entry_start_file (line 826) | static void
  function test_file (line 834) | static int

FILE: external/libzip/src/zipmerge.c
  function main (line 90) | int
  function confirm_replace (line 181) | static int
  function zip_t (line 224) | static zip_t *
  function copy_file (line 287) | static int copy_file(zip_t *destination_archive, zip_int64_t destination...
  function copy_extra_fields (line 321) | static void copy_extra_fields(zip_t *destination_archive, zip_uint64_t d...

FILE: external/libzip/src/ziptool.c
  type dispatch_table_t (line 60) | typedef struct dispatch_table_s {
  function cat_impl_backend (line 87) | static int
  function cat_impl (line 145) | static int
  function add (line 154) | static int
  function add_dir (line 171) | static int
  function add_file (line 181) | static int
  function add_from_zip (line 208) | static int
  function cat (line 244) | static int
  function cat_partial (line 253) | static int
  function count_extra (line 267) | static int
  function count_extra_by_id (line 284) | static int
  function delete (line 303) | static int delete (char *argv[]) {
  function delete_extra (line 313) | static int
  function delete_extra_by_id (line 328) | static int
  function get_archive_comment (line 344) | static int
  function get_archive_flag (line 356) | static int
  function get_extra (line 368) | static int
  function get_extra_by_id (line 391) | static int
  function get_file_comment (line 414) | static int
  function get_num_entries (line 432) | static int
  function name_locate (line 443) | static int
  type progress_userdata_s (line 459) | struct progress_userdata_s {
  type progress_userdata_s (line 464) | struct progress_userdata_s
  function progress_callback (line 466) | static void
  function print_progress (line 472) | static int
  function zrename (line 478) | static int
  function replace_file_contents (line 489) | static int
  function set_extra (line 505) | static int
  function set_archive_comment (line 523) | static int
  function set_archive_flag (line 532) | static int
  function set_file_comment (line 550) | static int
  function set_file_compression (line 561) | static int
  function set_file_encryption (line 576) | static int
  function set_file_dostime (line 594) | static int
  function set_file_mtime (line 609) | static int
  function set_file_mtime_all (line 623) | static int
  function set_password (line 644) | static int
  function zstat (line 654) | static int
  function parse_archive_flag (line 699) | static int parse_archive_flag(const char* arg) {
  function zip_flags_t (line 715) | static zip_flags_t
  function zip_int32_t (line 739) | static zip_int32_t
  function zip_uint16_t (line 773) | static zip_uint16_t
  function hexdump (line 790) | static void
  function zip_t (line 804) | static zip_t *
  function dispatch (line 874) | static int
  function usage (line 897) | static void
  function ziptool_post_close (line 982) | int
  function main (line 988) | int

FILE: external/pdfium/linux-x64/include/cpp/fpdf_deleters.h
  type FPDFAnnotationDeleter (line 20) | struct FPDFAnnotationDeleter {
  type FPDFAvailDeleter (line 24) | struct FPDFAvailDeleter {
  type FPDFBitmapDeleter (line 28) | struct FPDFBitmapDeleter {
  type FPDFClipPathDeleter (line 32) | struct FPDFClipPathDeleter {
  type FPDFDocumentDeleter (line 38) | struct FPDFDocumentDeleter {
  type FPDFFontDeleter (line 42) | struct FPDFFontDeleter {
  type FPDFFormHandleDeleter (line 46) | struct FPDFFormHandleDeleter {
  type FPDFJavaScriptActionDeleter (line 52) | struct FPDFJavaScriptActionDeleter {
  type FPDFPageDeleter (line 58) | struct FPDFPageDeleter {
  type FPDFPageLinkDeleter (line 62) | struct FPDFPageLinkDeleter {
  type FPDFPageObjectDeleter (line 68) | struct FPDFPageObjectDeleter {
  type FPDFStructTreeDeleter (line 74) | struct FPDFStructTreeDeleter {
  type FPDFTextFindDeleter (line 78) | struct FPDFTextFindDeleter {
  type FPDFTextPageDeleter (line 82) | struct FPDFTextPageDeleter {

FILE: external/pdfium/linux-x64/include/fpdf_annot.h
  type FPDFANNOT_COLORTYPE (line 95) | typedef enum FPDFANNOT_COLORTYPE {

FILE: external/pdfium/linux-x64/include/fpdf_dataavail.h
  type FX_FILEAVAIL (line 33) | typedef struct _FX_FILEAVAIL {
  type FX_DOWNLOADHINTS (line 71) | typedef struct _FX_DOWNLOADHINTS {

FILE: external/pdfium/linux-x64/include/fpdf_doc.h
  type FPDF_FILEIDTYPE (line 43) | typedef enum {

FILE: external/pdfium/linux-x64/include/fpdf_edit.h
  type FPDF_IMAGEOBJ_METADATA (line 77) | typedef struct FPDF_IMAGEOBJ_METADATA {

FILE: external/pdfium/linux-x64/include/fpdf_ext.h
  type UNSUPPORT_INFO (line 51) | typedef struct _UNSUPPORT_INFO {
  type tm (line 89) | struct tm

FILE: external/pdfium/linux-x64/include/fpdf_formfill.h
  type IPDF_JSPLATFORM (line 52) | typedef struct _IPDF_JsPlatform {
  type FPDF_SYSTEMTIME (line 319) | typedef struct _FPDF_SYSTEMTIME {
  type FPDF_FORMFILLINFO (line 350) | typedef struct _FPDF_FORMFILLINFO {

FILE: external/pdfium/linux-x64/include/fpdf_fwlevent.h
  type FWL_EVENTFLAG (line 18) | typedef enum {
  type FWL_VKEYCODE (line 31) | typedef enum {

FILE: external/pdfium/linux-x64/include/fpdf_progressive.h
  type IFSDK_PAUSE (line 25) | typedef struct _IFSDK_PAUSE {

FILE: external/pdfium/linux-x64/include/fpdf_save.h
  type FPDF_FILEWRITE (line 19) | typedef struct FPDF_FILEWRITE_ {

FILE: external/pdfium/linux-x64/include/fpdf_sysfontinfo.h
  type FPDF_SYSFONTINFO (line 48) | typedef struct _FPDF_SYSFONTINFO {
  type FPDF_CharsetFontMap (line 218) | typedef struct FPDF_CharsetFontMap_ {

FILE: external/pdfium/linux-x64/include/fpdfview.h
  type FPDF_TEXT_RENDERMODE (line 48) | typedef enum {
  type fpdf_action_t__ (line 62) | struct fpdf_action_t__
  type fpdf_annotation_t__ (line 63) | struct fpdf_annotation_t__
  type fpdf_attachment_t__ (line 64) | struct fpdf_attachment_t__
  type fpdf_avail_t__ (line 65) | struct fpdf_avail_t__
  type fpdf_bitmap_t__ (line 66) | struct fpdf_bitmap_t__
  type fpdf_bookmark_t__ (line 67) | struct fpdf_bookmark_t__
  type fpdf_clippath_t__ (line 68) | struct fpdf_clippath_t__
  type fpdf_dest_t__ (line 69) | struct fpdf_dest_t__
  type fpdf_document_t__ (line 70) | struct fpdf_document_t__
  type fpdf_font_t__ (line 71) | struct fpdf_font_t__
  type fpdf_form_handle_t__ (line 72) | struct fpdf_form_handle_t__
  type fpdf_glyphpath_t__ (line 73) | struct fpdf_glyphpath_t__
  type fpdf_javascript_action_t (line 74) | struct fpdf_javascript_action_t
  type fpdf_link_t__ (line 75) | struct fpdf_link_t__
  type fpdf_page_t__ (line 76) | struct fpdf_page_t__
  type fpdf_pagelink_t__ (line 77) | struct fpdf_pagelink_t__
  type fpdf_pageobject_t__ (line 78) | struct fpdf_pageobject_t__
  type fpdf_pageobjectmark_t__ (line 79) | struct fpdf_pageobjectmark_t__
  type fpdf_pagerange_t__ (line 80) | struct fpdf_pagerange_t__
  type fpdf_pathsegment_t (line 81) | struct fpdf_pathsegment_t
  type fpdf_schhandle_t__ (line 82) | struct fpdf_schhandle_t__
  type fpdf_signature_t__ (line 83) | struct fpdf_signature_t__
  type fpdf_structelement_t__ (line 85) | struct fpdf_structelement_t__
  type fpdf_structelement_attr_t__ (line 86) | struct fpdf_structelement_attr_t__
  type fpdf_structelement_attr_value_t__ (line 87) | struct fpdf_structelement_attr_value_t__
  type fpdf_structtree_t__ (line 89) | struct fpdf_structtree_t__
  type fpdf_textpage_t__ (line 90) | struct fpdf_textpage_t__
  type fpdf_widget_t__ (line 91) | struct fpdf_widget_t__
  type fpdf_xobject_t__ (line 92) | struct fpdf_xobject_t__
  type FPDF_BOOL (line 95) | typedef int FPDF_BOOL;
  type FPDF_RESULT (line 96) | typedef int FPDF_RESULT;
  type FPDF_DWORD (line 97) | typedef unsigned long FPDF_DWORD;
  type FS_FLOAT (line 98) | typedef float FS_FLOAT;
  type FPDF_DUPLEXTYPE (line 101) | typedef enum _FPDF_DUPLEXTYPE_ {
  type FPDF_WCHAR (line 109) | typedef unsigned short FPDF_WCHAR;
  type FPDF_WCHAR (line 119) | typedef const FPDF_WCHAR* FPDF_WIDESTRING;
  type FPDF_BSTR (line 124) | typedef struct FPDF_BSTR_ {
  type FS_MATRIX (line 146) | typedef struct _FS_MATRIX_ {
  type FS_RECTF (line 156) | typedef struct _FS_RECTF_ {
  type FS_RECTF (line 168) | typedef const FS_RECTF* FS_LPCRECTF;
  type FS_SIZEF (line 171) | typedef struct FS_SIZEF_ {
  type FS_SIZEF (line 177) | typedef const FS_SIZEF* FS_LPCSIZEF;
  type FS_POINTF (line 180) | typedef struct FS_POINTF_ {
  type FS_POINTF (line 186) | typedef const FS_POINTF* FS_LPCPOINTF;
  type FS_QUADPOINTSF (line 188) | typedef struct _FS_QUADPOINTSF {
  type FPDF_ANNOTATION_SUBTYPE (line 200) | typedef int FPDF_ANNOTATION_SUBTYPE;
  type FPDF_ANNOT_APPEARANCEMODE (line 201) | typedef int FPDF_ANNOT_APPEARANCEMODE;
  type FPDF_OBJECT_TYPE (line 204) | typedef int FPDF_OBJECT_TYPE;
  type FPDF_RENDERER_TYPE (line 233) | typedef enum {
  type FPDF_FONT_BACKEND_TYPE (line 242) | typedef enum {
  type FPDF_LIBRARY_CONFIG (line 250) | typedef struct FPDF_LIBRARY_CONFIG_ {
  type FPDF_FILEACCESS (line 461) | typedef struct {
  type FPDF_FILEHANDLER (line 486) | typedef struct FPDF_FILEHANDLER_ {
  type FPDF_COLORSCHEME (line 849) | typedef struct FPDF_COLORSCHEME_ {

FILE: external/pdfium/macos-arm64/include/cpp/fpdf_deleters.h
  type FPDFAnnotationDeleter (line 20) | struct FPDFAnnotationDeleter {
  type FPDFAvailDeleter (line 24) | struct FPDFAvailDeleter {
  type FPDFBitmapDeleter (line 28) | struct FPDFBitmapDeleter {
  type FPDFClipPathDeleter (line 32) | struct FPDFClipPathDeleter {
  type FPDFDocumentDeleter (line 38) | struct FPDFDocumentDeleter {
  type FPDFFontDeleter (line 42) | struct FPDFFontDeleter {
  type FPDFFormHandleDeleter (line 46) | struct FPDFFormHandleDeleter {
  type FPDFJavaScriptActionDeleter (line 52) | struct FPDFJavaScriptActionDeleter {
  type FPDFPageDeleter (line 58) | struct FPDFPageDeleter {
  type FPDFPageLinkDeleter (line 62) | struct FPDFPageLinkDeleter {
  type FPDFPageObjectDeleter (line 68) | struct FPDFPageObjectDeleter {
  type FPDFStructTreeDeleter (line 74) | struct FPDFStructTreeDeleter {
  type FPDFTextFindDeleter (line 78) | struct FPDFTextFindDeleter {
  type FPDFTextPageDeleter (line 82) | struct FPDFTextPageDeleter {

FILE: external/pdfium/macos-arm64/include/fpdf_annot.h
  type FPDFANNOT_COLORTYPE (line 95) | typedef enum FPDFANNOT_COLORTYPE {

FILE: external/pdfium/macos-arm64/include/fpdf_dataavail.h
  type FX_FILEAVAIL (line 33) | typedef struct _FX_FILEAVAIL {
  type FX_DOWNLOADHINTS (line 71) | typedef struct _FX_DOWNLOADHINTS {

FILE: external/pdfium/macos-arm64/include/fpdf_doc.h
  type FPDF_FILEIDTYPE (line 43) | typedef enum {

FILE: external/pdfium/macos-arm64/include/fpdf_edit.h
  type FPDF_IMAGEOBJ_METADATA (line 77) | typedef struct FPDF_IMAGEOBJ_METADATA {

FILE: external/pdfium/macos-arm64/include/fpdf_ext.h
  type UNSUPPORT_INFO (line 51) | typedef struct _UNSUPPORT_INFO {
  type tm (line 89) | struct tm

FILE: external/pdfium/macos-arm64/include/fpdf_formfill.h
  type IPDF_JSPLATFORM (line 52) | typedef struct _IPDF_JsPlatform {
  type FPDF_SYSTEMTIME (line 319) | typedef struct _FPDF_SYSTEMTIME {
  type FPDF_FORMFILLINFO (line 350) | typedef struct _FPDF_FORMFILLINFO {

FILE: external/pdfium/macos-arm64/include/fpdf_fwlevent.h
  type FWL_EVENTFLAG (line 18) | typedef enum {
  type FWL_VKEYCODE (line 31) | typedef enum {

FILE: external/pdfium/macos-arm64/include/fpdf_progressive.h
  type IFSDK_PAUSE (line 25) | typedef struct _IFSDK_PAUSE {

FILE: external/pdfium/macos-arm64/include/fpdf_save.h
  type FPDF_FILEWRITE (line 19) | typedef struct FPDF_FILEWRITE_ {

FILE: external/pdfium/macos-arm64/include/fpdf_sysfontinfo.h
  type FPDF_SYSFONTINFO (line 48) | typedef struct _FPDF_SYSFONTINFO {
  type FPDF_CharsetFontMap (line 218) | typedef struct FPDF_CharsetFontMap_ {

FILE: external/pdfium/macos-arm64/include/fpdfview.h
  type FPDF_TEXT_RENDERMODE (line 48) | typedef enum {
  type fpdf_action_t__ (line 62) | struct fpdf_action_t__
  type fpdf_annotation_t__ (line 63) | struct fpdf_annotation_t__
  type fpdf_attachment_t__ (line 64) | struct fpdf_attachment_t__
  type fpdf_avail_t__ (line 65) | struct fpdf_avail_t__
  type fpdf_bitmap_t__ (line 66) | struct fpdf_bitmap_t__
  type fpdf_bookmark_t__ (line 67) | struct fpdf_bookmark_t__
  type fpdf_clippath_t__ (line 68) | struct fpdf_clippath_t__
  type fpdf_dest_t__ (line 69) | struct fpdf_dest_t__
  type fpdf_document_t__ (line 70) | struct fpdf_document_t__
  type fpdf_font_t__ (line 71) | struct fpdf_font_t__
  type fpdf_form_handle_t__ (line 72) | struct fpdf_form_handle_t__
  type fpdf_glyphpath_t__ (line 73) | struct fpdf_glyphpath_t__
  type fpdf_javascript_action_t (line 74) | struct fpdf_javascript_action_t
  type fpdf_link_t__ (line 75) | struct fpdf_link_t__
  type fpdf_page_t__ (line 76) | struct fpdf_page_t__
  type fpdf_pagelink_t__ (line 77) | struct fpdf_pagelink_t__
  type fpdf_pageobject_t__ (line 78) | struct fpdf_pageobject_t__
  type fpdf_pageobjectmark_t__ (line 79) | struct fpdf_pageobjectmark_t__
  type fpdf_pagerange_t__ (line 80) | struct fpdf_pagerange_t__
  type fpdf_pathsegment_t (line 81) | struct fpdf_pathsegment_t
  type fpdf_schhandle_t__ (line 82) | struct fpdf_schhandle_t__
  type fpdf_signature_t__ (line 83) | struct fpdf_signature_t__
  type fpdf_structelement_t__ (line 85) | struct fpdf_structelement_t__
  type fpdf_structelement_attr_t__ (line 86) | struct fpdf_structelement_attr_t__
  type fpdf_structelement_attr_value_t__ (line 87) | struct fpdf_structelement_attr_value_t__
  type fpdf_structtree_t__ (line 89) | struct fpdf_structtree_t__
  type fpdf_textpage_t__ (line 90) | struct fpdf_textpage_t__
  type fpdf_widget_t__ (line 91) | struct fpdf_widget_t__
  type fpdf_xobject_t__ (line 92) | struct fpdf_xobject_t__
  type FPDF_BOOL (line 95) | typedef int FPDF_BOOL;
  type FPDF_RESULT (line 96) | typedef int FPDF_RESULT;
  type FPDF_DWORD (line 97) | typedef unsigned long FPDF_DWORD;
  type FS_FLOAT (line 98) | typedef float FS_FLOAT;
  type FPDF_DUPLEXTYPE (line 101) | typedef enum _FPDF_DUPLEXTYPE_ {
  type FPDF_WCHAR (line 109) | typedef unsigned short FPDF_WCHAR;
  type FPDF_WCHAR (line 119) | typedef const FPDF_WCHAR* FPDF_WIDESTRING;
  type FPDF_BSTR (line 124) | typedef struct FPDF_BSTR_ {
  type FS_MATRIX (line 146) | typedef struct _FS_MATRIX_ {
  type FS_RECTF (line 156) | typedef struct _FS_RECTF_ {
  type FS_RECTF (line 168) | typedef const FS_RECTF* FS_LPCRECTF;
  type FS_SIZEF (line 171) | typedef struct FS_SIZEF_ {
  type FS_SIZEF (line 177) | typedef const FS_SIZEF* FS_LPCSIZEF;
  type FS_POINTF (line 180) | typedef struct FS_POINTF_ {
  type FS_POINTF (line 186) | typedef const FS_POINTF* FS_LPCPOINTF;
  type FS_QUADPOINTSF (line 188) | typedef struct _FS_QUADPOINTSF {
  type FPDF_ANNOTATION_SUBTYPE (line 200) | typedef int FPDF_ANNOTATION_SUBTYPE;
  type FPDF_ANNOT_APPEARANCEMODE (line 201) | typedef int FPDF_ANNOT_APPEARANCEMODE;
  type FPDF_OBJECT_TYPE (line 204) | typedef int FPDF_OBJECT_TYPE;
  type FPDF_RENDERER_TYPE (line 233) | typedef enum {
  type FPDF_FONT_BACKEND_TYPE (line 242) | typedef enum {
  type FPDF_LIBRARY_CONFIG (line 250) | typedef struct FPDF_LIBRARY_CONFIG_ {
  type FPDF_FILEACCESS (line 461) | typedef struct {
  type FPDF_FILEHANDLER (line 486) | typedef struct FPDF_FILEHANDLER_ {
  type FPDF_COLORSCHEME (line 849) | typedef struct FPDF_COLORSCHEME_ {

FILE: external/pdfium/macos-x64/include/cpp/fpdf_deleters.h
  type FPDFAnnotationDeleter (line 20) | struct FPDFAnnotationDeleter {
  type FPDFAvailDeleter (line 24) | struct FPDFAvailDeleter {
  type FPDFBitmapDeleter (line 28) | struct FPDFBitmapDeleter {
  type FPDFClipPathDeleter (line 32) | struct FPDFClipPathDeleter {
  type FPDFDocumentDeleter (line 38) | struct FPDFDocumentDeleter {
  type FPDFFontDeleter (line 42) | struct FPDFFontDeleter {
  type FPDFFormHandleDeleter (line 46) | struct FPDFFormHandleDeleter {
  type FPDFJavaScriptActionDeleter (line 52) | struct FPDFJavaScriptActionDeleter {
  type FPDFPageDeleter (line 58) | struct FPDFPageDeleter {
  type FPDFPageLinkDeleter (line 62) | struct FPDFPageLinkDeleter {
  type FPDFPageObjectDeleter (line 68) | struct FPDFPageObjectDeleter {
  type FPDFStructTreeDeleter (line 74) | struct FPDFStructTreeDeleter {
  type FPDFTextFindDeleter (line 78) | struct FPDFTextFindDeleter {
  type FPDFTextPageDeleter (line 82) | struct FPDFTextPageDeleter {

FILE: external/pdfium/macos-x64/include/fpdf_annot.h
  type FPDFANNOT_COLORTYPE (line 95) | typedef enum FPDFANNOT_COLORTYPE {

FILE: external/pdfium/macos-x64/include/fpdf_dataavail.h
  type FX_FILEAVAIL (line 33) | typedef struct _FX_FILEAVAIL {
  type FX_DOWNLOADHINTS (line 71) | typedef struct _FX_DOWNLOADHINTS {

FILE: external/pdfium/macos-x64/include/fpdf_doc.h
  type FPDF_FILEIDTYPE (line 43) | typedef enum {

FILE: external/pdfium/macos-x64/include/fpdf_edit.h
  type FPDF_IMAGEOBJ_METADATA (line 77) | typedef struct FPDF_IMAGEOBJ_METADATA {

FILE: external/pdfium/macos-x64/include/fpdf_ext.h
  type UNSUPPORT_INFO (line 51) | typedef struct _UNSUPPORT_INFO {
  type tm (line 89) | struct tm

FILE: external/pdfium/macos-x64/include/fpdf_formfill.h
  type IPDF_JSPLATFORM (line 52) | typedef struct _IPDF_JsPlatform {
  type FPDF_SYSTEMTIME (line 319) | typedef struct _FPDF_SYSTEMTIME {
  type FPDF_FORMFILLINFO (line 350) | typedef struct _FPDF_FORMFILLINFO {

FILE: external/pdfium/macos-x64/include/fpdf_fwlevent.h
  type FWL_EVENTFLAG (line 18) | typedef enum {
  type FWL_VKEYCODE (line 31) | typedef enum {

FILE: external/pdfium/macos-x64/include/fpdf_progressive.h
  type IFSDK_PAUSE (line 25) | typedef struct _IFSDK_PAUSE {

FILE: external/pdfium/macos-x64/include/fpdf_save.h
  type FPDF_FILEWRITE (line 19) | typedef struct FPDF_FILEWRITE_ {

FILE: external/pdfium/macos-x64/include/fpdf_sysfontinfo.h
  type FPDF_SYSFONTINFO (line 48) | typedef struct _FPDF_SYSFONTINFO {
  type FPDF_CharsetFontMap (line 218) | typedef struct FPDF_CharsetFontMap_ {

FILE: external/pdfium/macos-x64/include/fpdfview.h
  type FPDF_TEXT_RENDERMODE (line 48) | typedef enum {
  type fpdf_action_t__ (line 62) | struct fpdf_action_t__
  type fpdf_annotation_t__ (line 63) | struct fpdf_annotation_t__
  type fpdf_attachment_t__ (line 64) | struct fpdf_attachment_t__
  type fpdf_avail_t__ (line 65) | struct fpdf_avail_t__
  type fpdf_bitmap_t__ (line 66) | struct fpdf_bitmap_t__
  type fpdf_bookmark_t__ (line 67) | struct fpdf_bookmark_t__
  type fpdf_clippath_t__ (line 68) | struct fpdf_clippath_t__
  type fpdf_dest_t__ (line 69) | struct fpdf_dest_t__
  type fpdf_document_t__ (line 70) | struct fpdf_document_t__
  type fpdf_font_t__ (line 71) | struct fpdf_font_t__
  type fpdf_form_handle_t__ (line 72) | struct fpdf_form_handle_t__
  type fpdf_glyphpath_t__ (line 73) | struct fpdf_glyphpath_t__
  type fpdf_javascript_action_t (line 74) | struct fpdf_javascript_action_t
  type fpdf_link_t__ (line 75) | struct fpdf_link_t__
  type fpdf_page_t__ (line 76) | struct fpdf_page_t__
  type fpdf_pagelink_t__ (line 77) | struct fpdf_pagelink_t__
  type fpdf_pageobject_t__ (line 78) | struct fpdf_pageobject_t__
  type fpdf_pageobjectmark_t__ (line 79) | struct fpdf_pageobjectmark_t__
  type fpdf_pagerange_t__ (line 80) | struct fpdf_pagerange_t__
  type fpdf_pathsegment_t (line 81) | struct fpdf_pathsegment_t
  type fpdf_schhandle_t__ (line 82) | struct fpdf_schhandle_t__
  type fpdf_signature_t__ (line 83) | struct fpdf_signature_t__
  type fpdf_structelement_t__ (line 85) | struct fpdf_structelement_t__
  type fpdf_structelement_attr_t__ (line 86) | struct fpdf_structelement_attr_t__
  type fpdf_structelement_attr_value_t__ (line 87) | struct fpdf_structelement_attr_value_t__
  type fpdf_structtree_t__ (line 89) | struct fpdf_structtree_t__
  type fpdf_textpage_t__ (line 90) | struct fpdf_textpage_t__
  type fpdf_widget_t__ (line 91) | struct fpdf_widget_t__
  type fpdf_xobject_t__ (line 92) | struct fpdf_xobject_t__
  type FPDF_BOOL (line 95) | typedef int FPDF_BOOL;
  type FPDF_RESULT (line 96) | typedef int FPDF_RESULT;
  type FPDF_DWORD (line 97) | typedef unsigned long FPDF_DWORD;
  type FS_FLOAT (line 98) | typedef float FS_FLOAT;
  type FPDF_DUPLEXTYPE (line 101) | typedef enum _FPDF_DUPLEXTYPE_ {
  type FPDF_WCHAR (line 109) | typedef unsigned short FPDF_WCHAR;
  type FPDF_WCHAR (line 119) | typedef const FPDF_WCHAR* FPDF_WIDESTRING;
  type FPDF_BSTR (line 124) | typedef struct FPDF_BSTR_ {
  type FS_MATRIX (line 146) | typedef struct _FS_MATRIX_ {
  type FS_RECTF (line 156) | typedef struct _FS_RECTF_ {
  type FS_RECTF (line 168) | typedef const FS_RECTF* FS_LPCRECTF;
  type FS_SIZEF (line 171) | typedef struct FS_SIZEF_ {
  type FS_SIZEF (line 177) | typedef const FS_SIZEF* FS_LPCSIZEF;
  type FS_POINTF (line 180) | typedef struct FS_POINTF_ {
  type FS_POINTF (line 186) | typedef const FS_POINTF* FS_LPCPOINTF;
  type FS_QUADPOINTSF (line 188) | typedef struct _FS_QUADPOINTSF {
  type FPDF_ANNOTATION_SUBTYPE (line 200) | typedef int FPDF_ANNOTATION_SUBTYPE;
  type FPDF_ANNOT_APPEARANCEMODE (line 201) | typedef int FPDF_ANNOT_APPEARANCEMODE;
  type FPDF_OBJECT_TYPE (line 204) | typedef int FPDF_OBJECT_TYPE;
  type FPDF_RENDERER_TYPE (line 233) | typedef enum {
  type FPDF_FONT_BACKEND_TYPE (line 242) | typedef enum {
  type FPDF_LIBRARY_CONFIG (line 250) | typedef struct FPDF_LIBRARY_CONFIG_ {
  type FPDF_FILEACCESS (line 461) | typedef struct {
  type FPDF_FILEHANDLER (line 486) | typedef struct FPDF_FILEHANDLER_ {
  type FPDF_COLORSCHEME (line 849) | typedef struct FPDF_COLORSCHEME_ {

FILE: external/pdfium/windows-x64/include/cpp/fpdf_deleters.h
  type FPDFAnnotationDeleter (line 20) | struct FPDFAnnotationDeleter {
  type FPDFAvailDeleter (line 24) | struct FPDFAvailDeleter {
  type FPDFBitmapDeleter (line 28) | struct FPDFBitmapDeleter {
  type FPDFClipPathDeleter (line 32) | struct FPDFClipPathDeleter {
  type FPDFDocumentDeleter (line 38) | struct FPDFDocumentDeleter {
  type FPDFFontDeleter (line 42) | struct FPDFFontDeleter {
  type FPDFFormHandleDeleter (line 46) | struct FPDFFormHandleDeleter {
  type FPDFJavaScriptActionDeleter (line 52) | struct FPDFJavaScriptActionDeleter {
  type FPDFPageDeleter (line 58) | struct FPDFPageDeleter {
  type FPDFPageLinkDeleter (line 62) | struct FPDFPageLinkDeleter {
  type FPDFPageObjectDeleter (line 68) | struct FPDFPageObjectDeleter {
  type FPDFStructTreeDeleter (line 74) | struct FPDFStructTreeDeleter {
  type FPDFTextFindDeleter (line 78) | struct FPDFTextFindDeleter {
  type FPDFTextPageDeleter (line 82) | struct FPDFTextPageDeleter {

FILE: external/pdfium/windows-x64/include/fpdf_annot.h
  type FPDFANNOT_COLORTYPE (line 95) | typedef enum FPDFANNOT_COLORTYPE {

FILE: external/pdfium/windows-x64/include/fpdf_dataavail.h
  type FX_FILEAVAIL (line 33) | typedef struct _FX_FILEAVAIL {
  type FX_DOWNLOADHINTS (line 71) | typedef struct _FX_DOWNLOADHINTS {

FILE: external/pdfium/windows-x64/include/fpdf_doc.h
  type FPDF_FILEIDTYPE (line 43) | typedef enum {

FILE: external/pdfium/windows-x64/include/fpdf_edit.h
  type FPDF_IMAGEOBJ_METADATA (line 77) | typedef struct FPDF_IMAGEOBJ_METADATA {

FILE: external/pdfium/windows-x64/include/fpdf_ext.h
  type UNSUPPORT_INFO (line 51) | typedef struct _UNSUPPORT_INFO {
  type tm (line 89) | struct tm

FILE: external/pdfium/windows-x64/include/fpdf_formfill.h
  type IPDF_JSPLATFORM (line 52) | typedef struct _IPDF_JsPlatform {
  type FPDF_SYSTEMTIME (line 319) | typedef struct _FPDF_SYSTEMTIME {
  type FPDF_FORMFILLINFO (line 350) | typedef struct _FPDF_FORMFILLINFO {

FILE: external/pdfium/windows-x64/include/fpdf_fwlevent.h
  type FWL_EVENTFLAG (line 18) | typedef enum {
  type FWL_VKEYCODE (line 31) | typedef enum {

FILE: external/pdfium/windows-x64/include/fpdf_progressive.h
  type IFSDK_PAUSE (line 25) | typedef struct _IFSDK_PAUSE {

FILE: external/pdfium/windows-x64/include/fpdf_save.h
  type FPDF_FILEWRITE (line 19) | typedef struct FPDF_FILEWRITE_ {

FILE: external/pdfium/windows-x64/include/fpdf_sysfontinfo.h
  type FPDF_SYSFONTINFO (line 48) | typedef struct _FPDF_SYSFONTINFO {
  type FPDF_CharsetFontMap (line 218) | typedef struct FPDF_CharsetFontMap_ {

FILE: external/pdfium/windows-x64/include/fpdfview.h
  type FPDF_TEXT_RENDERMODE (line 48) | typedef enum {
  type fpdf_action_t__ (line 62) | struct fpdf_action_t__
  type fpdf_annotation_t__ (line 63) | struct fpdf_annotation_t__
  type fpdf_attachment_t__ (line 64) | struct fpdf_attachment_t__
  type fpdf_avail_t__ (line 65) | struct fpdf_avail_t__
  type fpdf_bitmap_t__ (line 66) | struct fpdf_bitmap_t__
  type fpdf_bookmark_t__ (line 67) | struct fpdf_bookmark_t__
  type fpdf_clippath_t__ (line 68) | struct fpdf_clippath_t__
  type fpdf_dest_t__ (line 69) | struct fpdf_dest_t__
  type fpdf_document_t__ (line 70) | struct fpdf_document_t__
  type fpdf_font_t__ (line 71) | struct fpdf_font_t__
  type fpdf_form_handle_t__ (line 72) | struct fpdf_form_handle_t__
  type fpdf_glyphpath_t__ (line 73) | struct fpdf_glyphpath_t__
  type fpdf_javascript_action_t (line 74) | struct fpdf_javascript_action_t
  type fpdf_link_t__ (line 75) | struct fpdf_link_t__
  type fpdf_page_t__ (line 76) | struct fpdf_page_t__
  type fpdf_pagelink_t__ (line 77) | struct fpdf_pagelink_t__
  type fpdf_pageobject_t__ (line 78) | struct fpdf_pageobject_t__
  type fpdf_pageobjectmark_t__ (line 79) | struct fpdf_pageobjectmark_t__
  type fpdf_pagerange_t__ (line 80) | struct fpdf_pagerange_t__
  type fpdf_pathsegment_t (line 81) | struct fpdf_pathsegment_t
  type fpdf_schhandle_t__ (line 82) | struct fpdf_schhandle_t__
  type fpdf_signature_t__ (line 83) | struct fpdf_signature_t__
  type fpdf_structelement_t__ (line 85) | struct fpdf_structelement_t__
  type fpdf_structelement_attr_t__ (line 86) | struct fpdf_structelement_attr_t__
  type fpdf_structelement_attr_value_t__ (line 87) | struct fpdf_structelement_attr_value_t__
  type fpdf_structtree_t__ (line 89) | struct fpdf_structtree_t__
  type fpdf_textpage_t__ (line 90) | struct fpdf_textpage_t__
  type fpdf_widget_t__ (line 91) | struct fpdf_widget_t__
  type fpdf_xobject_t__ (line 92) | struct fpdf_xobject_t__
  type FPDF_BOOL (line 95) | typedef int FPDF_BOOL;
  type FPDF_RESULT (line 96) | typedef int FPDF_RESULT;
  type FPDF_DWORD (line 97) | typedef unsigned long FPDF_DWORD;
  type FS_FLOAT (line 98) | typedef float FS_FLOAT;
  type FPDF_DUPLEXTYPE (line 101) | typedef enum _FPDF_DUPLEXTYPE_ {
  type FPDF_WCHAR (line 109) | typedef unsigned short FPDF_WCHAR;
  type FPDF_WCHAR (line 119) | typedef const FPDF_WCHAR* FPDF_WIDESTRING;
  type FPDF_BSTR (line 124) | typedef struct FPDF_BSTR_ {
  type FS_MATRIX (line 146) | typedef struct _FS_MATRIX_ {
  type FS_RECTF (line 156) | typedef struct _FS_RECTF_ {
  type FS_RECTF (line 168) | typedef const FS_RECTF* FS_LPCRECTF;
  type FS_SIZEF (line 171) | typedef struct FS_SIZEF_ {
  type FS_SIZEF (line 177) | typedef const FS_SIZEF* FS_LPCSIZEF;
  type FS_POINTF (line 180) | typedef struct FS_POINTF_ {
  type FS_POINTF (line 186) | typedef const FS_POINTF* FS_LPCPOINTF;
  type FS_QUADPOINTSF (line 188) | typedef struct _FS_QUADPOINTSF {
  type FPDF_ANNOTATION_SUBTYPE (line 200) | typedef int FPDF_ANNOTATION_SUBTYPE;
  type FPDF_ANNOT_APPEARANCEMODE (line 201) | typedef int FPDF_ANNOT_APPEARANCEMODE;
  type FPDF_OBJECT_TYPE (line 204) | typedef int FPDF_OBJECT_TYPE;
  type FPDF_RENDERER_TYPE (line 233) | typedef enum {
  type FPDF_FONT_BACKEND_TYPE (line 242) | typedef enum {
  type FPDF_LIBRARY_CONFIG (line 250) | typedef struct FPDF_LIBRARY_CONFIG_ {
  type FPDF_FILEACCESS (line 461) | typedef struct {
  type FPDF_FILEHANDLER (line 486) | typedef struct FPDF_FILEHANDLER_ {
  type FPDF_COLORSCHEME (line 849) | typedef struct FPDF_COLORSCHEME_ {

FILE: external/pugixml/docs/samples/custom_memory_management.cpp
  function custom_deallocate (line 11) | void custom_deallocate(void* ptr)
  function main (line 17) | int main()

FILE: external/pugixml/docs/samples/include.cpp
  function preprocess (line 9) | bool preprocess(pugi::xml_node node)
  function load_preprocess (line 48) | bool load_preprocess(pugi::xml_document& doc, const char* path)
  function main (line 56) | int main()

FILE: external/pugixml/docs/samples/load_error_handling.cpp
  function check_xml (line 5) | void check_xml(const char* source)
  function main (line 24) | int main()

FILE: external/pugixml/docs/samples/load_file.cpp
  function main (line 5) | int main()

FILE: external/pugixml/docs/samples/load_memory.cpp
  function main (line 6) | int main()

FILE: external/pugixml/docs/samples/load_options.cpp
  function main (line 5) | int main()

FILE: external/pugixml/docs/samples/load_stream.cpp
  function print_doc (line 7) | void print_doc(const char* message, const pugi::xml_document& doc, const...
  function try_imbue (line 17) | bool try_imbue(std::wistream& stream, const char* name)
  function main (line 31) | int main()

FILE: external/pugixml/docs/samples/modify_add.cpp
  function main (line 5) | int main()

FILE: external/pugixml/docs/samples/modify_base.cpp
  function main (line 6) | int main()

FILE: external/pugixml/docs/samples/modify_remove.cpp
  function main (line 5) | int main()

FILE: external/pugixml/docs/samples/save_custom_writer.cpp
  type xml_string_writer (line 8) | struct xml_string_writer: pugi::xml_writer
    method write (line 12) | virtual void write(const void* data, size_t size)
  type xml_memory_writer (line 19) | struct xml_memory_writer: pugi::xml_writer
    method xml_memory_writer (line 26) | xml_memory_writer(): buffer(0), capacity(0), result(0)
    method xml_memory_writer (line 30) | xml_memory_writer(char* buffer, size_t capacity): buffer(buffer), capa...
    method written_size (line 34) | size_t written_size() const
    method write (line 39) | virtual void write(const void* data, size_t size)
  function node_to_string (line 52) | std::string node_to_string(pugi::xml_node node)
  function main (line 93) | int main()

FILE: external/pugixml/docs/samples/save_declaration.cpp
  function main (line 5) | int main()

FILE: external/pugixml/docs/samples/save_file.cpp
  function main (line 5) | int main()

FILE: external/pugixml/docs/samples/save_options.cpp
  function main (line 5) | int main()

FILE: external/pugixml/docs/samples/save_stream.cpp
  function main (line 5) | int main()

FILE: external/pugixml/docs/samples/save_subtree.cpp
  function main (line 5) | int main()

FILE: external/pugixml/docs/samples/text.cpp
  function main (line 5) | int main()

FILE: external/pugixml/docs/samples/traverse_base.cpp
  function main (line 6) | int main()

FILE: external/pugixml/docs/samples/traverse_iter.cpp
  function main (line 5) | int main()

FILE: external/pugixml/docs/samples/traverse_predicate.cpp
  function small_timeout (line 7) | bool small_timeout(pugi::xml_node node)
  type allow_remote_predicate (line 12) | struct allow_remote_predicate
  function main (line 26) | int main()

FILE: external/pugixml/docs/samples/traverse_rangefor.cpp
  function main (line 5) | int main()

FILE: external/pugixml/docs/samples/traverse_walker.cpp
  type simple_walker (line 11) | struct simple_walker: pugi::xml_tree_walker
    method for_each (line 13) | virtual bool for_each(pugi::xml_node& node)
  function main (line 24) | int main()

FILE: external/pugixml/docs/samples/xpath_error.cpp
  function main (line 5) | int main()

FILE: external/pugixml/docs/samples/xpath_query.cpp
  function main (line 6) | int main()

FILE: external/pugixml/docs/samples/xpath_select.cpp
  function main (line 5) | int main()

FILE: external/pugixml/docs/samples/xpath_variables.cpp
  function main (line 6) | int main()

FILE: external/pugixml/src/pugixml.cpp
  type pugi (line 188) | namespace pugi
    type xml_attribute_struct (line 1088) | struct xml_attribute_struct
      method xml_attribute_struct (line 1090) | xml_attribute_struct(impl::xml_memory_page* page): header(page, 0), ...
      method xml_attribute_struct (line 1135) | xml_attribute_struct(impl::xml_memory_page* page): name(NULL), value...
    type xml_node_struct (line 1106) | struct xml_node_struct
      method xml_node_struct (line 1108) | xml_node_struct(impl::xml_memory_page* page, xml_node_type type): he...
      method xml_node_struct (line 1151) | xml_node_struct(impl::xml_memory_page* page, xml_node_type type): na...
    type xml_attribute_struct (line 1133) | struct xml_attribute_struct
      method xml_attribute_struct (line 1090) | xml_attribute_struct(impl::xml_memory_page* page): header(page, 0), ...
      method xml_attribute_struct (line 1135) | xml_attribute_struct(impl::xml_memory_page* page): name(NULL), value...
    type xml_node_struct (line 1149) | struct xml_node_struct
      method xml_node_struct (line 1108) | xml_node_struct(impl::xml_memory_page* page, xml_node_type type): he...
      method xml_node_struct (line 1151) | xml_node_struct(impl::xml_memory_page* page, xml_node_type type): na...
  function PUGI_IMPL_NS_BEGIN (line 203) | PUGI_IMPL_NS_BEGIN
  function PUGI_IMPL_FN (line 209) | PUGI_IMPL_FN void default_deallocate(void* ptr)
  type xml_memory_management_function_storage (line 215) | struct xml_memory_management_function_storage
  function PUGI_IMPL_NS_END (line 227) | PUGI_IMPL_NS_END
  function PUGI_IMPL_FN (line 244) | PUGI_IMPL_FN bool strequal(const char_t* src, const char_t* dst)
  function PUGI_IMPL_FN (line 257) | PUGI_IMPL_FN bool stringview_equal(string_view_t srcview, const char_t* ...
  function PUGI_IMPL_FN (line 274) | PUGI_IMPL_FN bool strequalrange(const char_t* lhs, const char_t* rhs, si...
  function PUGI_IMPL_FN (line 284) | PUGI_IMPL_FN size_t strlength_wide(const wchar_t* s)
  function PUGI_IMPL_NS_END (line 296) | PUGI_IMPL_NS_END
  function PUGI_IMPL_NS_BEGIN (line 326) | PUGI_IMPL_NS_BEGIN
  function PUGI_IMPL_FN_NO_INLINE (line 432) | PUGI_IMPL_FN_NO_INLINE bool compact_hash_table::rehash(size_t count)
  type xml_allocator (line 494) | struct xml_allocator
    method xml_allocator (line 548) | xml_allocator(xml_memory_page* root): _root(root), _busy_size(root->bu...
    method xml_memory_page (line 555) | xml_memory_page* allocate_page(size_t data_size)
    method deallocate_page (line 573) | static void deallocate_page(xml_memory_page* page)
    method deallocate_memory (line 632) | void deallocate_memory(void* ptr, size_t size, xml_memory_page* page)
    method char_t (line 676) | char_t* allocate_string(size_t length)
    method deallocate_string (line 710) | void deallocate_string(char_t* string)
    method reserve (line 729) | bool reserve()
  type xml_memory_page (line 496) | struct xml_memory_page
    method xml_memory_page (line 498) | static xml_memory_page* construct(void* memory)
  type xml_memory_string_header (line 540) | struct xml_memory_string_header
  type xml_allocator (line 546) | struct xml_allocator
    method xml_allocator (line 548) | xml_allocator(xml_memory_page* root): _root(root), _busy_size(root->bu...
    method xml_memory_page (line 555) | xml_memory_page* allocate_page(size_t data_size)
    method deallocate_page (line 573) | static void deallocate_page(xml_memory_page* page)
    method deallocate_memory (line 632) | void deallocate_memory(void* ptr, size_t size, xml_memory_page* page)
    method char_t (line 676) | char_t* allocate_string(size_t length)
    method deallocate_string (line 710) | void deallocate_string(char_t* string)
    method reserve (line 729) | bool reserve()
  function PUGI_IMPL_FN_NO_INLINE (line 746) | PUGI_IMPL_FN_NO_INLINE void* xml_allocator::allocate_memory_oob(size_t s...
  class compact_header (line 790) | class compact_header
    method compact_header (line 793) | compact_header(xml_memory_page* page, unsigned int flags)
    method xml_memory_page (line 819) | xml_memory_page* get_page() const
  function PUGI_IMPL_FN (line 833) | PUGI_IMPL_FN xml_memory_page* compact_get_page(const void* object, int h...
  function PUGI_IMPL_FN_NO_INLINE (line 840) | PUGI_IMPL_FN_NO_INLINE T* compact_get_value(const void* object)
  function PUGI_IMPL_FN_NO_INLINE (line 845) | PUGI_IMPL_FN_NO_INLINE void compact_set_value(const void* object, T* value)
  class compact_pointer (line 850) | class compact_pointer
    method compact_pointer (line 853) | compact_pointer(): _data(0)
    method T (line 903) | T* operator->() const
  class compact_pointer_parent (line 912) | class compact_pointer_parent
    method compact_pointer_parent (line 915) | compact_pointer_parent(): _data(0)
    method T (line 983) | T* operator->() const
  class compact_string (line 992) | class compact_string
    method compact_string (line 995) | compact_string(): _data(0)
  type pugi (line 1086) | namespace pugi
    type xml_attribute_struct (line 1088) | struct xml_attribute_struct
      method xml_attribute_struct (line 1090) | xml_attribute_struct(impl::xml_memory_page* page): header(page, 0), ...
      method xml_attribute_struct (line 1135) | xml_attribute_struct(impl::xml_memory_page* page): name(NULL), value...
    type xml_node_struct (line 1106) | struct xml_node_struct
      method xml_node_struct (line 1108) | xml_node_struct(impl::xml_memory_page* page, xml_node_type type): he...
      method xml_node_struct (line 1151) | xml_node_struct(impl::xml_memory_page* page, xml_node_type type): na...
    type xml_attribute_struct (line 1133) | struct xml_attribute_struct
      method xml_attribute_struct (line 1090) | xml_attribute_struct(impl::xml_memory_page* page): header(page, 0), ...
      method xml_attribute_struct (line 1135) | xml_attribute_struct(impl::xml_memory_page* page): name(NULL), value...
    type xml_node_struct (line 1149) | struct xml_node_struct
      method xml_node_struct (line 1108) | xml_node_struct(impl::xml_memory_page* page, xml_node_type type): he...
      method xml_node_struct (line 1151) | xml_node_struct(impl::xml_memory_page* page, xml_node_type type): na...
  type pugi (line 1131) | namespace pugi
    type xml_attribute_struct (line 1088) | struct xml_attribute_struct
      method xml_attribute_struct (line 1090) | xml_attribute_struct(impl::xml_memory_page* page): header(page, 0), ...
      method xml_attribute_struct (line 1135) | xml_attribute_struct(impl::xml_memory_page* page): name(NULL), value...
    type xml_node_struct (line 1106) | struct xml_node_struct
      method xml_node_struct (line 1108) | xml_node_struct(impl::xml_memory_page* page, xml_node_type type): he...
      method xml_node_struct (line 1151) | xml_node_struct(impl::xml_memory_page* page, xml_node_type type): na...
    type xml_attribute_struct (line 1133) | struct xml_attribute_struct
      method xml_attribute_struct (line 1090) | xml_attribute_struct(impl::xml_memory_page* page): header(page, 0), ...
      method xml_attribute_struct (line 1135) | xml_attribute_struct(impl::xml_memory_page* page): name(NULL), value...
    type xml_node_struct (line 1149) | struct xml_node_struct
      method xml_node_struct (line 1108) | xml_node_struct(impl::xml_memory_page* page, xml_node_type type): he...
      method xml_node_struct (line 1151) | xml_node_struct(impl::xml_memory_page* page, xml_node_type type): na...
  function PUGI_IMPL_NS_BEGIN (line 1173) | PUGI_IMPL_NS_BEGIN
  type xml_document_struct (line 1180) | struct xml_document_struct: public xml_node_struct, public xml_allocator
    method xml_document_struct (line 1182) | xml_document_struct(xml_memory_page* page): xml_node_struct(page, node...
  function xml_allocator (line 1195) | inline xml_allocator& get_allocator(const Object* object)
    method xml_allocator (line 548) | xml_allocator(xml_memory_page* root): _root(root), _busy_size(root->bu...
    method xml_memory_page (line 555) | xml_memory_page* allocate_page(size_t data_size)
    method deallocate_page (line 573) | static void deallocate_page(xml_memory_page* page)
    method deallocate_memory (line 632) | void deallocate_memory(void* ptr, size_t size, xml_memory_page* page)
    method char_t (line 676) | char_t* allocate_string(size_t length)
    method deallocate_string (line 710) | void deallocate_string(char_t* string)
    method reserve (line 729) | bool reserve()
  function xml_document_struct (line 1202) | inline xml_document_struct& get_document(const Object* object)
    method xml_document_struct (line 1182) | xml_document_struct(xml_memory_page* page): xml_node_struct(page, node...
  function PUGI_IMPL_NS_END (line 1208) | PUGI_IMPL_NS_END
  function xml_node_struct (line 1221) | inline xml_node_struct* allocate_node(xml_allocator& alloc, xml_node_typ...
  function destroy_attribute (line 1230) | inline void destroy_attribute(xml_attribute_struct* a, xml_allocator& al...
  function destroy_node (line 1241) | inline void destroy_node(xml_node_struct* n, xml_allocator& alloc)
  function append_node (line 1270) | inline void append_node(xml_node_struct* child, xml_node_struct* node)
  function prepend_node (line 1291) | inline void prepend_node(xml_node_struct* child, xml_node_struct* node)
  function insert_node_after (line 1309) | inline void insert_node_after(xml_node_struct* child, xml_node_struct* n...
  function insert_node_before (line 1328) | inline void insert_node_before(xml_node_struct* child, xml_node_struct* ...
  function remove_node (line 1347) | inline void remove_node(xml_node_struct* node)
  function append_attribute (line 1369) | inline void append_attribute(xml_attribute_struct* attr, xml_node_struct...
  function prepend_attribute (line 1388) | inline void prepend_attribute(xml_attribute_struct* attr, xml_node_struc...
  function insert_attribute_after (line 1404) | inline void insert_attribute_after(xml_attribute_struct* attr, xml_attri...
  function insert_attribute_before (line 1418) | inline void insert_attribute_before(xml_attribute_struct* attr, xml_attr...
  function remove_attribute (line 1432) | inline void remove_attribute(xml_attribute_struct* attr, xml_node_struct...
  function PUGI_IMPL_FN_NO_INLINE (line 1451) | PUGI_IMPL_FN_NO_INLINE xml_node_struct* append_new_node(xml_node_struct*...
  function PUGI_IMPL_FN_NO_INLINE (line 1463) | PUGI_IMPL_FN_NO_INLINE xml_attribute_struct* append_new_attribute(xml_no...
  function PUGI_IMPL_NS_END (line 1474) | PUGI_IMPL_NS_END
  type opt_true (line 1483) | struct opt_true
  function PUGI_IMPL_NS_END (line 1487) | PUGI_IMPL_NS_END
  function endian_swap (line 1496) | inline uint32_t endian_swap(uint32_t value)
  type utf8_counter (line 1501) | struct utf8_counter
    method value_type (line 1505) | static value_type low(value_type result, uint32_t ch)
    method value_type (line 1515) | static value_type high(value_type result, uint32_t)
  type utf8_writer (line 1522) | struct utf8_writer
    method value_type (line 1526) | static value_type low(value_type result, uint32_t ch)
    method value_type (line 1551) | static value_type high(value_type result, uint32_t ch)
    method value_type (line 1561) | static value_type any(value_type result, uint32_t ch)
  type utf16_counter (line 1567) | struct utf16_counter
    method value_type (line 1571) | static value_type low(value_type result, uint32_t)
    method value_type (line 1576) | static value_type high(value_type result, uint32_t)
  type utf16_writer (line 1582) | struct utf16_writer
    method value_type (line 1586) | static value_type low(value_type result, uint32_t ch)
    method value_type (line 1593) | static value_type high(value_type result, uint32_t ch)
    method value_type (line 1604) | static value_type any(value_type result, uint32_t ch)
  type utf32_counter (line 1610) | struct utf32_counter
    method value_type (line 1614) | static value_type low(value_type result, uint32_t)
    method value_type (line 1619) | static value_type high(value_type result, uint32_t)
  type utf32_writer (line 1625) | struct utf32_writer
    method value_type (line 1629) | static value_type low(value_type result, uint32_t ch)
    method value_type (line 1636) | static value_type high(value_type result, uint32_t ch)
    method value_type (line 1643) | static value_type any(value_type result, uint32_t ch)
  type latin1_writer (line 1651) | struct latin1_writer
    method value_type (line 1655) | static value_type low(value_type result, uint32_t ch)
    method value_type (line 1662) | static value_type high(value_type result, uint32_t ch)
  type utf8_decoder (line 1672) | struct utf8_decoder
    method process (line 1676) | static inline typename Traits::value_type process(const uint8_t* data,...
  type utf16_decoder (line 1739) | struct utf16_decoder
    method process (line 1743) | static inline typename Traits::value_type process(const uint16_t* data...
  type utf32_decoder (line 1791) | struct utf32_decoder
    method process (line 1795) | static inline typename Traits::value_type process(const uint32_t* data...
  type latin1_decoder (line 1821) | struct latin1_decoder
    method process (line 1825) | static inline typename Traits::value_type process(const uint8_t* data,...
  type wchar_selector (line 1838) | struct wchar_selector
  type wchar_selector<2> (line 1840) | struct wchar_selector<2>
  type wchar_selector<4> (line 1848) | struct wchar_selector<4>
  type wchar_decoder (line 1859) | struct wchar_decoder
    method process (line 1863) | static inline typename Traits::value_type process(const wchar_t* data,...
  function PUGI_IMPL_FN (line 1872) | PUGI_IMPL_FN void convert_wchar_endian_swap(wchar_t* result, const wchar...
  type chartypex_t (line 1914) | enum chartypex_t
  function PUGI_IMPL_FN (line 1954) | PUGI_IMPL_FN bool is_little_endian()
  function PUGI_IMPL_FN (line 1961) | PUGI_IMPL_FN xml_encoding get_wchar_encoding()
  function PUGI_IMPL_FN (line 1971) | PUGI_IMPL_FN bool parse_declaration_encoding(const uint8_t* data, size_t...
  function PUGI_IMPL_FN (line 2025) | PUGI_IMPL_FN xml_encoding guess_buffer_encoding(const uint8_t* data, siz...
  function PUGI_IMPL_FN (line 2073) | PUGI_IMPL_FN xml_encoding get_buffer_encoding(xml_encoding encoding, con...
  function PUGI_IMPL_FN (line 2093) | PUGI_IMPL_FN bool get_mutable_buffer(char_t*& out_buffer, size_t& out_le...
  function PUGI_IMPL_FN (line 2122) | PUGI_IMPL_FN bool need_endian_swap_utf(xml_encoding le, xml_encoding re)
  function PUGI_IMPL_FN (line 2128) | PUGI_IMPL_FN bool convert_buffer_endian_swap(char_t*& out_buffer, size_t...
  function PUGI_IMPL_FN (line 2157) | PUGI_IMPL_FN bool convert_buffer_generic(char_t*& out_buffer, size_t& ou...
  function PUGI_IMPL_FN (line 2182) | PUGI_IMPL_FN bool convert_buffer(char_t*& out_buffer, size_t& out_length...
  function PUGI_IMPL_FN (line 2227) | PUGI_IMPL_FN bool convert_buffer_generic(char_t*& out_buffer, size_t& ou...
  function PUGI_IMPL_FN (line 2252) | PUGI_IMPL_FN size_t get_latin1_7bit_prefix_length(const uint8_t* data, s...
  function PUGI_IMPL_FN (line 2261) | PUGI_IMPL_FN bool convert_buffer_latin1(char_t*& out_buffer, size_t& out...
  function PUGI_IMPL_FN (line 2298) | PUGI_IMPL_FN bool convert_buffer(char_t*& out_buffer, size_t& out_length...
  function PUGI_IMPL_FN (line 2333) | PUGI_IMPL_FN size_t as_utf8_begin(const wchar_t* str, size_t length)
  function PUGI_IMPL_FN (line 2339) | PUGI_IMPL_FN void as_utf8_end(char* buffer, size_t size, const wchar_t* ...
  function PUGI_IMPL_FN (line 2351) | PUGI_IMPL_FN std::string as_utf8_impl(const wchar_t* str, size_t length)
  function PUGI_IMPL_FN (line 2366) | PUGI_IMPL_FN std::basic_string<wchar_t> as_wide_impl(const char* str, si...
  function strcpy_insitu_allow (line 2392) | inline bool strcpy_insitu_allow(size_t length, const Header& header, uin...
  function PUGI_IMPL_FN (line 2409) | PUGI_IMPL_FN bool strcpy_insitu(String& dest, Header& header, uintptr_t ...
  type gap (line 2459) | struct gap
    method gap (line 2464) | gap(): end(NULL), size(0)
    method push (line 2470) | void push(char_t*& s, size_t count)
    method char_t (line 2487) | char_t* flush(char_t* s)
  function PUGI_IMPL_FN (line 2501) | PUGI_IMPL_FN char_t* strconv_escape(char_t* s, gap& g)
  function PUGI_IMPL_FN (line 2654) | PUGI_IMPL_FN char_t* strconv_comment(char_t* s, char_t endch)
  function PUGI_IMPL_FN (line 2682) | PUGI_IMPL_FN char_t* strconv_cdata(char_t* s, char_t endch)
  type strconv_pcdata_impl (line 2712) | struct strconv_pcdata_impl
    method char_t (line 2714) | static char_t* parse(char_t* s)
  function PUGI_IMPL_FN (line 2763) | PUGI_IMPL_FN strconv_pcdata_t get_strconv_pcdata(unsigned int optmask)
  type strconv_attribute_impl (line 2783) | struct strconv_attribute_impl
    method char_t (line 2785) | static char_t* parse_wnorm(char_t* s, char_t end_quote)
    method char_t (line 2837) | static char_t* parse_wconv(char_t* s, char_t end_quote)
    method char_t (line 2873) | static char_t* parse_eol(char_t* s, char_t end_quote)
    method char_t (line 2905) | static char_t* parse_simple(char_t* s, char_t end_quote)
  function PUGI_IMPL_FN (line 2932) | PUGI_IMPL_FN strconv_attribute_t get_strconv_attribute(unsigned int optm...
  function xml_parse_result (line 2958) | inline xml_parse_result make_parse_result(xml_parse_status status, ptrdi...
  type xml_parser (line 2967) | struct xml_parser
    method xml_parser (line 2973) | xml_parser(xml_allocator* alloc_): alloc(alloc_), error_offset(NULL), ...
    method char_t (line 2984) | char_t* parse_doctype_primitive(char_t* s)
    method char_t (line 3017) | char_t* parse_doctype_ignore(char_t* s)
    method char_t (line 3048) | char_t* parse_doctype_group(char_t* s, char_t endch)
    method char_t (line 3094) | char_t* parse_exclamation(char_t* s, xml_node_struct* cursor, unsigned...
    method char_t (line 3203) | char_t* parse_question(char_t* s, xml_node_struct*& ref_cursor, unsign...
    method char_t (line 3297) | char_t* parse_tree(char_t* s, xml_node_struct* root, unsigned int optm...
    method char_t (line 3554) | static char_t* parse_skip_bom(char_t* s)
    method char_t (line 3560) | static char_t* parse_skip_bom(char_t* s)
    method has_element_node_siblings (line 3566) | static bool has_element_node_siblings(xml_node_struct* node)
    method xml_parse_result (line 3578) | static xml_parse_result parse(char_t* buffer, size_t length, xml_docum...
  function PUGI_IMPL_FN (line 3627) | PUGI_IMPL_FN xml_encoding get_write_native_encoding()
  function PUGI_IMPL_FN (line 3636) | PUGI_IMPL_FN xml_encoding get_write_encoding(xml_encoding encoding)
  function PUGI_IMPL_FN (line 3654) | PUGI_IMPL_FN size_t convert_buffer_output_generic(typename T::value_type...
  function PUGI_IMPL_FN (line 3663) | PUGI_IMPL_FN size_t convert_buffer_output_generic(typename T::value_type...
  function PUGI_IMPL_FN (line 3679) | PUGI_IMPL_FN size_t get_valid_length(const char_t* data, size_t length)
  function PUGI_IMPL_FN (line 3687) | PUGI_IMPL_FN size_t convert_buffer_output(char_t* r_char, uint8_t* r_u8,...
  function PUGI_IMPL_FN (line 3725) | PUGI_IMPL_FN size_t get_valid_length(const char_t* data, size_t length)
  function PUGI_IMPL_FN (line 3741) | PUGI_IMPL_FN size_t convert_buffer_output(char_t* /* r_char */, uint8_t*...
  class xml_buffered_writer (line 3765) | class xml_buffered_writer
    method xml_buffered_writer (line 3771) | xml_buffered_writer(xml_writer& writer_, xml_encoding user_encoding): ...
    method flush (line 3776) | size_t flush()
    method flush (line 3783) | void flush(const char_t* data, size_t size)
    method write_direct (line 3801) | void write_direct(const char_t* data, size_t length)
    method write_buffer (line 3840) | void write_buffer(const char_t* data, size_t length)
    method write_string (line 3855) | void write_string(const char_t* data)
    method write (line 3880) | void write(char_t d0)
    method write (line 3889) | void write(char_t d0, char_t d1)
    method write (line 3899) | void write(char_t d0, char_t d1, char_t d2)
    method write (line 3910) | void write(char_t d0, char_t d1, char_t d2, char_t d3)
    method write (line 3922) | void write(char_t d0, char_t d1, char_t d2, char_t d3, char_t d4)
    method write (line 3935) | void write(char_t d0, char_t d1, char_t d2, char_t d3, char_t d4, char...
  function PUGI_IMPL_FN (line 3979) | PUGI_IMPL_FN void text_output_escaped(xml_buffered_writer& writer, const...
  function PUGI_IMPL_FN (line 4031) | PUGI_IMPL_FN void text_output(xml_buffered_writer& writer, const char_t*...
  function PUGI_IMPL_FN (line 4039) | PUGI_IMPL_FN void text_output_cdata(xml_buffered_writer& writer, const c...
  function PUGI_IMPL_FN (line 4061) | PUGI_IMPL_FN void text_output_indent(xml_buffered_writer& writer, const ...
  function PUGI_IMPL_FN (line 4101) | PUGI_IMPL_FN void node_output_comment(xml_buffered_writer& writer, const...
  function PUGI_IMPL_FN (line 4126) | PUGI_IMPL_FN void node_output_pi_value(xml_buffered_writer& writer, cons...
  function PUGI_IMPL_FN (line 4147) | PUGI_IMPL_FN void node_output_attributes(xml_buffered_writer& writer, xm...
  function PUGI_IMPL_FN (line 4175) | PUGI_IMPL_FN bool node_output_start(xml_buffered_writer& writer, xml_nod...
  function PUGI_IMPL_FN (line 4237) | PUGI_IMPL_FN void node_output_end(xml_buffered_writer& writer, xml_node_...
  function PUGI_IMPL_FN (line 4247) | PUGI_IMPL_FN void node_output_simple(xml_buffered_writer& writer, xml_no...
  type indent_flags_t (line 4303) | enum indent_flags_t
  function PUGI_IMPL_FN (line 4309) | PUGI_IMPL_FN void node_output(xml_buffered_writer& writer, xml_node_stru...
  function PUGI_IMPL_FN (line 4402) | PUGI_IMPL_FN bool has_declaration(xml_node_struct* node)
  function PUGI_IMPL_FN (line 4415) | PUGI_IMPL_FN bool is_attribute_of(xml_attribute_struct* attr, xml_node_s...
  function PUGI_IMPL_FN (line 4424) | PUGI_IMPL_FN bool allow_insert_attribute(xml_node_type parent)
  function PUGI_IMPL_FN (line 4429) | PUGI_IMPL_FN bool allow_insert_child(xml_node_type parent, xml_node_type...
  function PUGI_IMPL_FN (line 4438) | PUGI_IMPL_FN bool allow_move(xml_node parent, xml_node child)
  function PUGI_IMPL_FN (line 4463) | PUGI_IMPL_FN void node_copy_string(String& dest, Header& header, uintptr...
  function PUGI_IMPL_FN (line 4482) | PUGI_IMPL_FN void node_copy_contents(xml_node_struct* dn, xml_node_struc...
  function PUGI_IMPL_FN (line 4499) | PUGI_IMPL_FN void node_copy_tree(xml_node_struct* dn, xml_node_struct* sn)
  function PUGI_IMPL_FN (line 4553) | PUGI_IMPL_FN void node_copy_attribute(xml_attribute_struct* da, xml_attr...
  function is_text_node (line 4562) | inline bool is_text_node(xml_node_struct* node)
  function PUGI_IMPL_FN (line 4570) | PUGI_IMPL_FN PUGI_IMPL_UNSIGNED_OVERFLOW U string_to_integer(const char_...
  function PUGI_IMPL_FN (line 4652) | PUGI_IMPL_FN int get_value_int(const char_t* value)
  function get_value_uint (line 4657) | PUGI_IMPL_FN unsigned int get_value_uint(const char_t* value)
  function PUGI_IMPL_FN (line 4662) | PUGI_IMPL_FN double get_value_double(const char_t* value)
  function PUGI_IMPL_FN (line 4671) | PUGI_IMPL_FN float get_value_float(const char_t* value)
  function PUGI_IMPL_FN (line 4680) | PUGI_IMPL_FN bool get_value_bool(const char_t* value)
  function get_value_llong (line 4690) | PUGI_IMPL_FN long long get_value_llong(const char_t* value)
  function get_value_ullong (line 4695) | PUGI_IMPL_FN unsigned long long get_value_ullong(const char_t* value)
  function PUGI_IMPL_FN (line 4701) | PUGI_IMPL_FN PUGI_IMPL_UNSIGNED_OVERFLOW char_t* integer_to_string(char_...
  function PUGI_IMPL_FN (line 4723) | PUGI_IMPL_FN bool set_value_ascii(String& dest, Header& header, uintptr_...
  function PUGI_IMPL_FN (line 4739) | PUGI_IMPL_FN bool set_value_integer(String& dest, Header& header, uintpt...
  function PUGI_IMPL_FN (line 4749) | PUGI_IMPL_FN bool set_value_convert(String& dest, Header& header, uintpt...
  function PUGI_IMPL_FN (line 4758) | PUGI_IMPL_FN bool set_value_convert(String& dest, Header& header, uintpt...
  function PUGI_IMPL_FN (line 4767) | PUGI_IMPL_FN bool set_value_bool(String& dest, Header& header, uintptr_t...
  function PUGI_IMPL_FN (line 4772) | PUGI_IMPL_FN xml_parse_result load_buffer_impl(xml_document_struct* doc,...
  function PUGI_IMPL_FN (line 4811) | PUGI_IMPL_FN xml_parse_status convert_file_size(T length, size_t& out_re...
  function PUGI_IMPL_FN (line 4826) | PUGI_IMPL_FN xml_parse_status get_file_size(FILE* file, size_t& out_result)
  function PUGI_IMPL_FN (line 4864) | PUGI_IMPL_FN size_t zero_terminate_buffer(void* buffer, size_t size, xml...
  function PUGI_IMPL_FN (line 4888) | PUGI_IMPL_FN xml_parse_result load_file_impl(xml_document_struct* doc, F...
  function PUGI_IMPL_FN (line 4917) | PUGI_IMPL_FN void close_file(FILE* file)
  type xml_stream_chunk (line 4923) | struct xml_stream_chunk
    method xml_stream_chunk (line 4925) | static xml_stream_chunk* create()
    method destroy (line 4933) | static void destroy(xml_stream_chunk* chunk)
    method xml_stream_chunk (line 4946) | xml_stream_chunk(): next(NULL), size(0)
  function PUGI_IMPL_FN (line 4956) | PUGI_IMPL_FN xml_parse_status load_stream_data_noseek(std::basic_istream...
  funct
Condensed preview — 1196 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (9,110K chars).
[
  {
    "path": ".clang-format",
    "chars": 309,
    "preview": "BasedOnStyle: Google\nIndentWidth: 4\nTabWidth: 4\nUseTab: Never\nColumnLimit: 120\nBreakBeforeBraces: Attach\nAllowShortFunct"
  },
  {
    "path": ".github/workflows/build.yml",
    "chars": 2046,
    "preview": "name: Build\n\non:\n  pull_request:\n    branches: [ main, dev ]\n\njobs:\n  build-linux:\n    runs-on: ${{ matrix.os }}\n    str"
  },
  {
    "path": ".gitignore",
    "chars": 2251,
    "preview": "# Created by https://www.toptal.com/developers/gitignore/api/c++,visualstudiocode\n# Edit at https://www.toptal.com/devel"
  },
  {
    "path": ".gitmodules",
    "chars": 250,
    "preview": "[submodule \"app/include/external/llama.cpp\"]\n\tpath = app/include/external/llama.cpp\n\turl = https://github.com/ggerganov/"
  },
  {
    "path": "CHANGELOG.md",
    "chars": 8563,
    "preview": "# Changelog\n\n## [1.7.3] - 2026-03-22\n\n- Non-English categorization is now more reliable: files are categorized canonica"
  },
  {
    "path": "LICENSE",
    "chars": 34524,
    "preview": "                    GNU AFFERO GENERAL PUBLIC LICENSE\n                       Version 3, 19 November 2007\n\n Copyright (C)"
  },
  {
    "path": "README.md",
    "chars": 52222,
    "preview": "<!-- markdownlint-disable MD046 -->\n# AI File Sorter\n\n[![Code Version](https://img.shields.io/badge/Code-1.7.3-blue)](#)"
  },
  {
    "path": "TESTS.md",
    "chars": 49005,
    "preview": "# Test Suite Guide\n\nThis document provides a detailed description of every test case in the project. It is organized by "
  },
  {
    "path": "TRADEMARKS.md",
    "chars": 2108,
    "preview": "# Trademarks\n\nThis project is open source, but its name and branding are not licensed for general reuse.\n\nThe project ow"
  },
  {
    "path": "app/CMakeLists.txt",
    "chars": 47711,
    "preview": "cmake_minimum_required(VERSION 3.21)\n\nproject(AIFileSorter LANGUAGES CXX)\n\n# C++ standard\nset(CMAKE_CXX_STANDARD 20)\nset"
  },
  {
    "path": "app/Makefile",
    "chars": 27318,
    "preview": "# Detect platform\nUNAME := $(shell uname | cut -d'-' -f1)\nUNAME_M := $(shell uname -m)\n\nBIN_DIR := ./bin\nOBJ_ROOT := ./o"
  },
  {
    "path": "app/build_windows.ps1",
    "chars": 18421,
    "preview": "param(\n    [string]$VcpkgRoot,\n    [ValidateSet(\"Debug\", \"Release\")]\n    [string]$Configuration = \"Release\",\n    [switch"
  },
  {
    "path": "app/include/AppInfo.hpp",
    "chars": 213,
    "preview": "#pragma once\n\n#include <QString>\n\n#ifndef AI_FILE_SORTER_APP_NAME\n#define AI_FILE_SORTER_APP_NAME \"AI File Sorter\"\n#endi"
  },
  {
    "path": "app/include/CategorizationDialog.hpp",
    "chars": 9802,
    "preview": "#ifndef CATEGORIZATIONDIALOG_HPP\n#define CATEGORIZATIONDIALOG_HPP\n\n#include \"CategoryLanguage.hpp\"\n#include \"Types.hpp\"\n"
  },
  {
    "path": "app/include/CategorizationProgressDialog.hpp",
    "chars": 3727,
    "preview": "#ifndef CATEGORIZATIONPROGRESSDIALOG_HPP\n#define CATEGORIZATIONPROGRESSDIALOG_HPP\n\n#include \"Types.hpp\"\n\n#include <QCore"
  },
  {
    "path": "app/include/CategorizationService.hpp",
    "chars": 17330,
    "preview": "#ifndef CATEGORIZATION_SERVICE_HPP\n#define CATEGORIZATION_SERVICE_HPP\n\n#include \"Types.hpp\"\n#include \"DatabaseManager.hp"
  },
  {
    "path": "app/include/CategorizationServiceTestAccess.hpp",
    "chars": 1006,
    "preview": "#pragma once\n\n#ifdef AI_FILE_SORTER_TEST_BUILD\n\n#include \"CategorizationService.hpp\"\n\n/**\n * @brief Test-only accessors "
  },
  {
    "path": "app/include/CategorizationSession.hpp",
    "chars": 492,
    "preview": "#ifndef CATEGORIZATIONSESSION_HPP\n#define CATEGORIZATIONSESSION_HPP\n\n#include <LLMClient.hpp>\n#include <string>\n\nclass C"
  },
  {
    "path": "app/include/CategoryLanguage.hpp",
    "chars": 1850,
    "preview": "#ifndef CATEGORYLANGUAGE_HPP\n#define CATEGORYLANGUAGE_HPP\n\n#include <QString>\n#include <string>\n#include <array>\n\nenum c"
  },
  {
    "path": "app/include/ConsistencyPassService.hpp",
    "chars": 3141,
    "preview": "#ifndef CONSISTENCY_PASS_SERVICE_HPP\n#define CONSISTENCY_PASS_SERVICE_HPP\n\n#include \"CategoryLanguage.hpp\"\n#include \"Dat"
  },
  {
    "path": "app/include/CustomApiDialog.hpp",
    "chars": 1747,
    "preview": "#ifndef CUSTOMAPIDIALOG_HPP\n#define CUSTOMAPIDIALOG_HPP\n\n#include \"Types.hpp\"\n\n#include <QCoreApplication>\n#include <QDi"
  },
  {
    "path": "app/include/CustomLLMDialog.hpp",
    "chars": 1709,
    "preview": "#ifndef CUSTOMLLMDIALOG_HPP\n#define CUSTOMLLMDIALOG_HPP\n\n#include \"Types.hpp\"\n\n#include <QCoreApplication>\n#include <QDi"
  },
  {
    "path": "app/include/DatabaseManager.hpp",
    "chars": 8193,
    "preview": "#ifndef DATABASEMANAGER_HPP\n#define DATABASEMANAGER_HPP\n\n#include \"CategoryLanguage.hpp\"\n#include \"Types.hpp\"\n#include <"
  },
  {
    "path": "app/include/DialogUtils.hpp",
    "chars": 222,
    "preview": "#ifndef DIALOGUTILS_HPP\n#define DIALOGUTILS_HPP\n\n#include <string>\n\nclass QWidget;\n\nclass DialogUtils {\npublic:\n    stat"
  },
  {
    "path": "app/include/DocumentTextAnalyzer.hpp",
    "chars": 3059,
    "preview": "#pragma once\n\n#include <filesystem>\n#include <optional>\n#include <string>\n\nclass ILLMClient;\n\nstruct DocumentAnalysisRes"
  },
  {
    "path": "app/include/DryRunPreviewDialog.hpp",
    "chars": 588,
    "preview": "#pragma once\n\n#include <QCoreApplication>\n#include <QDialog>\n#include <QTableWidget>\n\n#include <string>\n#include <vector"
  },
  {
    "path": "app/include/EmbeddedEnv.hpp",
    "chars": 386,
    "preview": "#ifndef EMBEDDED_ENV_H\n#define EMBEDDED_ENV_H\n\n#include <string>\n#include <stdexcept>\n\nclass EmbeddedEnv {\npublic:\n    e"
  },
  {
    "path": "app/include/ErrorMessages.hpp",
    "chars": 872,
    "preview": "/**\n * @file ErrorMessages.hpp\n * @brief Translatable error message constants used throughout the UI.\n */\n#ifndef ERRORM"
  },
  {
    "path": "app/include/FileScanner.hpp",
    "chars": 1807,
    "preview": "#ifndef FILE_SCANNER_HPP\n#define FILE_SCANNER_HPP\n\n#include <filesystem>\n#include <string>\n#include <vector>\n#include <o"
  },
  {
    "path": "app/include/GeminiClient.hpp",
    "chars": 1468,
    "preview": "#ifndef GEMINICLIENT_HPP\n#define GEMINICLIENT_HPP\n\n#include \"ILLMClient.hpp\"\n#include <Types.hpp>\n#include <string>\n\ncla"
  },
  {
    "path": "app/include/GgmlRuntimePaths.hpp",
    "chars": 553,
    "preview": "#pragma once\n\n#include <filesystem>\n#include <optional>\n#include <string_view>\n#include <vector>\n\nnamespace GgmlRuntimeP"
  },
  {
    "path": "app/include/ILLMClient.hpp",
    "chars": 596,
    "preview": "#pragma once\n#include \"Types.hpp\"\n#include <string>\n\nclass ILLMClient {\npublic:\n    virtual ~ILLMClient() = default;\n   "
  },
  {
    "path": "app/include/ImageRenameMetadataService.hpp",
    "chars": 6429,
    "preview": "#ifndef IMAGE_RENAME_METADATA_SERVICE_HPP\n#define IMAGE_RENAME_METADATA_SERVICE_HPP\n\n#include <chrono>\n#include <filesys"
  },
  {
    "path": "app/include/IniConfig.hpp",
    "chars": 624,
    "preview": "#ifndef INICONFIG_HPP\n#define INICONFIG_HPP\n\n#include <string>\n#include <map>\n#include <fstream>\n#include <sstream>\n\n\ncl"
  },
  {
    "path": "app/include/LLMClient.hpp",
    "chars": 1673,
    "preview": "#ifndef LLMCLIENT_HPP\n#define LLMCLIENT_HPP\n\n#include \"ILLMClient.hpp\"\n#include <Types.hpp>\n#include <string>\n\nclass LLM"
  },
  {
    "path": "app/include/LLMDownloader.hpp",
    "chars": 9892,
    "preview": "#pragma once\n#include \"Settings.hpp\"\n#include <atomic>\n#include <curl/system.h>\n#include <functional>\n#include <map>\n#in"
  },
  {
    "path": "app/include/LLMErrors.hpp",
    "chars": 428,
    "preview": "#ifndef LLM_ERRORS_HPP\n#define LLM_ERRORS_HPP\n\n#include <stdexcept>\n#include <string>\n\nclass BackoffError : public std::"
  },
  {
    "path": "app/include/LLMSelectionDialog.hpp",
    "chars": 7168,
    "preview": "#ifndef LLMSELECTIONDIALOG_HPP\n#define LLMSELECTIONDIALOG_HPP\n\n#include \"LLMDownloader.hpp\"\n#include \"Types.hpp\"\n\n#inclu"
  },
  {
    "path": "app/include/LLMSelectionDialogTestAccess.hpp",
    "chars": 943,
    "preview": "#pragma once\n\n#ifdef AI_FILE_SORTER_TEST_BUILD\n\n#include <optional>\n\n#include <QLabel>\n#include <QProgressBar>\n#include "
  },
  {
    "path": "app/include/Language.hpp",
    "chars": 1847,
    "preview": "#ifndef LANGUAGE_HPP\n#define LANGUAGE_HPP\n\n#include <QString>\n\nenum class Language {\n    English,\n    French,\n    German"
  },
  {
    "path": "app/include/LlamaModelParams.hpp",
    "chars": 279,
    "preview": "#pragma once\n\n#include \"llama.h\"\n#include <memory>\n#include <string>\n\nnamespace spdlog { class logger; }\n\nllama_model_pa"
  },
  {
    "path": "app/include/LlavaImageAnalyzer.hpp",
    "chars": 7016,
    "preview": "#pragma once\n\n#include <cstdint>\n#include <filesystem>\n#include <functional>\n#include <optional>\n#include <string>\n#incl"
  },
  {
    "path": "app/include/LlmCatalog.hpp",
    "chars": 986,
    "preview": "#ifndef LLMCATALOG_HPP\n#define LLMCATALOG_HPP\n\n#include \"Settings.hpp\"\n\n#include <QString>\n#include <vector>\n\n/**\n * @br"
  },
  {
    "path": "app/include/LocalLLMClient.hpp",
    "chars": 3535,
    "preview": "#pragma once\n\n#include \"ILLMClient.hpp\"\n#include \"Types.hpp\"\n#include \"llama.h\"\n#include <functional>\n#include <memory>\n"
  },
  {
    "path": "app/include/LocalLLMTestAccess.hpp",
    "chars": 938,
    "preview": "#pragma once\n\n#ifdef AI_FILE_SORTER_TEST_BUILD\n\n#include <string>\n#include \"llama.h\"\n\nnamespace LocalLLMTestAccess {\n\nen"
  },
  {
    "path": "app/include/Logger.hpp",
    "chars": 636,
    "preview": "#ifndef LOGGER_HPP\n#define LOGGER_HPP\n\n#include <spdlog/spdlog.h>\n#include <spdlog/sinks/stdout_color_sinks.h>\n#include "
  },
  {
    "path": "app/include/MainApp.hpp",
    "chars": 14109,
    "preview": "#ifndef MAINAPP_HPP\n#define MAINAPP_HPP\n\n#include \"CategorizationDialog.hpp\"\n#include \"CategorizationProgressDialog.hpp\""
  },
  {
    "path": "app/include/MainAppEditActions.hpp",
    "chars": 488,
    "preview": "#ifndef MAIN_APP_EDIT_ACTIONS_HPP\n#define MAIN_APP_EDIT_ACTIONS_HPP\n\n#include <QString>\n\nclass QLineEdit;\n\nclass MainApp"
  },
  {
    "path": "app/include/MainAppHelpActions.hpp",
    "chars": 350,
    "preview": "#ifndef MAIN_APP_HELP_ACTIONS_HPP\n#define MAIN_APP_HELP_ACTIONS_HPP\n\n#include <QString>\n\nclass QWidget;\n\nclass MainAppHe"
  },
  {
    "path": "app/include/MainAppTestAccess.hpp",
    "chars": 9601,
    "preview": "/**\n * @file MainAppTestAccess.hpp\n * @brief Test-only accessors and helpers for MainApp.\n */\n#pragma once\n\n#ifdef AI_FI"
  },
  {
    "path": "app/include/MainAppUiBuilder.hpp",
    "chars": 1198,
    "preview": "#ifndef MAIN_APP_UI_BUILDER_HPP\n#define MAIN_APP_UI_BUILDER_HPP\n\n#include <QIcon>\n#include <QStyle>\n#include \"UiTranslat"
  },
  {
    "path": "app/include/MediaRenameMetadataService.hpp",
    "chars": 2778,
    "preview": "/**\n * @file MediaRenameMetadataService.hpp\n * @brief Builds audio/video filename suggestions from embedded media metada"
  },
  {
    "path": "app/include/MovableCategorizedFile.hpp",
    "chars": 2304,
    "preview": "#ifndef MOVABLECATEGORIZEDFILE_HPP\n#define MOVABLECATEGORIZEDFILE_HPP\n\n#include <string>\n#include <filesystem>\n\nclass Mo"
  },
  {
    "path": "app/include/ResultsCoordinator.hpp",
    "chars": 3312,
    "preview": "#ifndef RESULTS_COORDINATOR_HPP\n#define RESULTS_COORDINATOR_HPP\n\n#include \"Types.hpp\"\n#include \"FileScanner.hpp\"\n\n#inclu"
  },
  {
    "path": "app/include/Settings.hpp",
    "chars": 22457,
    "preview": "#ifndef SETTINGS_HPP\n#define SETTINGS_HPP\n\n#include <IniConfig.hpp>\n#include <Types.hpp>\n#include <Language.hpp>\n#includ"
  },
  {
    "path": "app/include/SuitabilityBenchmarkDialog.hpp",
    "chars": 3212,
    "preview": "#ifndef SUITABILITY_BENCHMARK_DIALOG_HPP\n#define SUITABILITY_BENCHMARK_DIALOG_HPP\n\n#include <QCoreApplication>\n#include "
  },
  {
    "path": "app/include/SupportCodeManager.hpp",
    "chars": 2596,
    "preview": "/**\n * @file SupportCodeManager.hpp\n * @brief Offline donation-code validation and prompt suppression helpers.\n */\n#prag"
  },
  {
    "path": "app/include/TestHooks.hpp",
    "chars": 1603,
    "preview": "#pragma once\n\n#include <functional>\n#include <optional>\n#include <string>\n#include <string_view>\n#include <curl/curl.h>\n"
  },
  {
    "path": "app/include/TranslationManager.hpp",
    "chars": 967,
    "preview": "#ifndef TRANSLATIONMANAGER_HPP\n#define TRANSLATIONMANAGER_HPP\n\n#include \"Language.hpp\"\n\n#include <QObject>\n#include <QTr"
  },
  {
    "path": "app/include/Types.hpp",
    "chars": 2825,
    "preview": "#ifndef TYPES_HPP\n#define TYPES_HPP\n\n#include <string>\n\nenum class LLMChoice {\n    Unset,\n    Remote_OpenAI,\n    Remote_"
  },
  {
    "path": "app/include/UiTranslator.hpp",
    "chars": 7345,
    "preview": "#ifndef UI_TRANSLATOR_HPP\n#define UI_TRANSLATOR_HPP\n\n#include <QPointer>\n#include <QString>\n\n#include <functional>\n\n#inc"
  },
  {
    "path": "app/include/UndoManager.hpp",
    "chars": 870,
    "preview": "#pragma once\n\n#include <QString>\n#include <QStringList>\n#include <memory>\n#include <optional>\n#include <string>\n#include"
  },
  {
    "path": "app/include/UpdateArchiveExtractor.hpp",
    "chars": 849,
    "preview": "#pragma once\n\n#include <filesystem>\n#include <string>\n\nclass UpdateArchiveExtractor\n{\npublic:\n    struct ExtractionResul"
  },
  {
    "path": "app/include/UpdateFeed.hpp",
    "chars": 837,
    "preview": "#pragma once\n\n#include <optional>\n#include <string>\n\nstruct UpdateInfo\n{\n    std::string current_version;\n    std::strin"
  },
  {
    "path": "app/include/UpdateInstaller.hpp",
    "chars": 3135,
    "preview": "#pragma once\n\n#include \"Settings.hpp\"\n#include \"UpdateFeed.hpp\"\n\n#include <filesystem>\n#include <functional>\n#include <s"
  },
  {
    "path": "app/include/UpdateInstallerTestAccess.hpp",
    "chars": 271,
    "preview": "#pragma once\n\n#ifdef AI_FILE_SORTER_TEST_BUILD\n\n#include \"UpdateInstaller.hpp\"\n\nclass UpdateInstallerTestAccess {\npublic"
  },
  {
    "path": "app/include/Updater.hpp",
    "chars": 1712,
    "preview": "#ifndef UPDATER_HPP\n#define UPDATER_HPP\n\n#include \"Settings.hpp\"\n#include \"UpdateFeed.hpp\"\n#include \"UpdateInstaller.hpp"
  },
  {
    "path": "app/include/UpdaterBuildConfig.hpp",
    "chars": 651,
    "preview": "#pragma once\n\nnamespace UpdaterBuildConfig {\n\nenum class Mode {\n    AutoInstall,\n    NotifyOnly,\n    Disabled,\n};\n\nconst"
  },
  {
    "path": "app/include/UpdaterLaunchOptions.hpp",
    "chars": 928,
    "preview": "#pragma once\n\nnamespace UpdaterLaunchOptions {\n\ninline constexpr const char* kLiveTestFlag = \"--updater-live-test\";\ninli"
  },
  {
    "path": "app/include/UpdaterLiveTestConfig.hpp",
    "chars": 596,
    "preview": "#pragma once\n\n#include <filesystem>\n#include <optional>\n#include <string>\n\nstruct UpdaterLiveTestConfig\n{\n    bool enabl"
  },
  {
    "path": "app/include/UpdaterTestAccess.hpp",
    "chars": 1268,
    "preview": "#pragma once\n\n#ifdef AI_FILE_SORTER_TEST_BUILD\n\n#include \"UpdateFeed.hpp\"\n\n#include <QString>\n#include <functional>\n\ncla"
  },
  {
    "path": "app/include/Utils.hpp",
    "chars": 1929,
    "preview": "#ifndef UTILS_HPP\n#define UTILS_HPP\n\n#include <curl/system.h>\n#include <functional>\n#include <optional>\n#include <string"
  },
  {
    "path": "app/include/Version.hpp",
    "chars": 491,
    "preview": "#ifndef VERSION_HPP\n#define VERSION_HPP\n\n#include <initializer_list>\n#include <string>\n#include <vector>\n\n\nclass Version"
  },
  {
    "path": "app/include/WhitelistManagerDialog.hpp",
    "chars": 2516,
    "preview": "#ifndef WHITELIST_MANAGER_DIALOG_HPP\n#define WHITELIST_MANAGER_DIALOG_HPP\n\n#include <QCoreApplication>\n#include <QDialog"
  },
  {
    "path": "app/include/WhitelistStore.hpp",
    "chars": 1116,
    "preview": "#ifndef WHITELIST_STORE_HPP\n#define WHITELIST_STORE_HPP\n\n#include <string>\n#include <vector>\n#include <unordered_map>\n#i"
  },
  {
    "path": "app/include/app_version.hpp",
    "chars": 85,
    "preview": "#pragma once\n\n#include \"Version.hpp\"\n\n\nconst Version APP_VERSION = Version{1, 7, 3};\n"
  },
  {
    "path": "app/include/constants.hpp",
    "chars": 142,
    "preview": "#ifndef CONSTANTS_HPP\n#define CONSTANTS_HPP\n\nconstexpr auto APP_NAME = \"AI File Sorter\";\nconstexpr auto APP_NAME_DIR = \""
  },
  {
    "path": "app/include/external/dotenv.h",
    "chars": 11489,
    "preview": "// Copyright (c) 2018 Heikki Johannes Hildén <hildenjohannes@gmail.com>\n//\n// All rights reserved.\n//\n// Redistribution "
  },
  {
    "path": "app/includePaths.txt",
    "chars": 342,
    "preview": "# Useful, for example, for VS Code\n\n${workspaceFolder}/**\n/usr/include/qt\n/usr/include/qt/QtCore\n/usr/include/qt/QtGui\n/"
  },
  {
    "path": "app/lib/CategorizationDialog.cpp",
    "chars": 115001,
    "preview": "#include \"CategorizationDialog.hpp\"\n\n#include \"DatabaseManager.hpp\"\n#include \"Logger.hpp\"\n#include \"MovableCategorizedFi"
  },
  {
    "path": "app/lib/CategorizationProgressDialog.cpp",
    "chars": 21488,
    "preview": "#include \"CategorizationProgressDialog.hpp\"\n\n#include \"DocumentTextAnalyzer.hpp\"\n#include \"LlavaImageAnalyzer.hpp\"\n#incl"
  },
  {
    "path": "app/lib/CategorizationService.cpp",
    "chars": 52681,
    "preview": "#include \"CategorizationService.hpp\"\n\n#include \"Settings.hpp\"\n#include \"CategoryLanguage.hpp\"\n#include \"DatabaseManager."
  },
  {
    "path": "app/lib/CategorizationSession.cpp",
    "chars": 530,
    "preview": "#include \"CategorizationSession.hpp\"\n\n#include <algorithm>\n#include <utility>\n\n\nCategorizationSession::CategorizationSes"
  },
  {
    "path": "app/lib/ConsistencyPassService.cpp",
    "chars": 22739,
    "preview": "#include \"ConsistencyPassService.hpp\"\n\n#include \"ILLMClient.hpp\"\n\n#include <fmt/format.h>\n\n#include <spdlog/spdlog.h>\n\n#"
  },
  {
    "path": "app/lib/CustomApiDialog.cpp",
    "chars": 4157,
    "preview": "#include \"CustomApiDialog.hpp\"\n\n#include <QCheckBox>\n#include <QDialogButtonBox>\n#include <QFormLayout>\n#include <QHBoxL"
  },
  {
    "path": "app/lib/CustomLLMDialog.cpp",
    "chars": 3137,
    "preview": "#include \"CustomLLMDialog.hpp\"\n\n#include <QDialogButtonBox>\n#include <QFileDialog>\n#include <QFormLayout>\n#include <QHBo"
  },
  {
    "path": "app/lib/DatabaseManager.cpp",
    "chars": 65038,
    "preview": "#include \"DatabaseManager.hpp\"\n#include \"Types.hpp\"\n#include \"Logger.hpp\"\n#include \"Utils.hpp\"\n\n#include <algorithm>\n#in"
  },
  {
    "path": "app/lib/DialogUtils.cpp",
    "chars": 265,
    "preview": "#include \"DialogUtils.hpp\"\n\n#include <QMessageBox>\n#include <QObject>\n#include <QString>\n\nvoid DialogUtils::show_error_d"
  },
  {
    "path": "app/lib/DocumentTextAnalyzer.cpp",
    "chars": 25400,
    "preview": "#include \"DocumentTextAnalyzer.hpp\"\n\n#include \"ILLMClient.hpp\"\n\n#include <QProcess>\n#include <QStandardPaths>\n#include <"
  },
  {
    "path": "app/lib/DryRunPreviewDialog.cpp",
    "chars": 2090,
    "preview": "#include \"DryRunPreviewDialog.hpp\"\n\n#include <QHeaderView>\n#include <QHBoxLayout>\n#include <QPushButton>\n#include <QVBox"
  },
  {
    "path": "app/lib/EmbeddedEnv.cpp",
    "chars": 2934,
    "preview": "#include \"EmbeddedEnv.hpp\"\n#include \"Logger.hpp\"\n\n#include <QFile>\n#include <QIODevice>\n#include <QByteArray>\n#include <"
  },
  {
    "path": "app/lib/FileScanner.cpp",
    "chars": 9167,
    "preview": "#include \"FileScanner.hpp\"\n#include \"Logger.hpp\"\n#include \"Utils.hpp\"\n#include <algorithm>\n#include <iostream>\n#include "
  },
  {
    "path": "app/lib/GeminiClient.cpp",
    "chars": 13381,
    "preview": "#include \"GeminiClient.hpp\"\n\n#include \"Logger.hpp\"\n#include \"LLMErrors.hpp\"\n#include \"Utils.hpp\"\n\n#include <curl/curl.h>"
  },
  {
    "path": "app/lib/GgmlRuntimePaths.cpp",
    "chars": 2344,
    "preview": "#include \"GgmlRuntimePaths.hpp\"\n\n#include <algorithm>\n#include <array>\n\nnamespace GgmlRuntimePaths {\n\nnamespace {\n\nbool "
  },
  {
    "path": "app/lib/ImageRenameMetadataService.cpp",
    "chars": 38277,
    "preview": "#include \"ImageRenameMetadataService.hpp\"\n\n#include \"Utils.hpp\"\n\n#include <curl/curl.h>\n\n#if __has_include(<jsoncpp/json"
  },
  {
    "path": "app/lib/IniConfig.cpp",
    "chars": 3633,
    "preview": "#include \"IniConfig.hpp\"\n#include \"Logger.hpp\"\n#include <cstdio>\n#include <iostream>\n#include <optional>\n#include <utili"
  },
  {
    "path": "app/lib/LLMClient.cpp",
    "chars": 13130,
    "preview": "#include \"LLMClient.hpp\"\n#include \"Types.hpp\"\n#include \"Utils.hpp\"\n#include \"Logger.hpp\"\n#include <curl/curl.h>\n#include"
  },
  {
    "path": "app/lib/LLMDownloader.cpp",
    "chars": 21239,
    "preview": "#include \"LLMDownloader.hpp\"\n#include \"Utils.hpp\"\n#include \"Logger.hpp\"\n#include \"TestHooks.hpp\"\n#include <algorithm>\n#i"
  },
  {
    "path": "app/lib/LLMSelectionDialog.cpp",
    "chars": 67976,
    "preview": "#include \"LLMSelectionDialog.hpp\"\n\n#include \"DialogUtils.hpp\"\n#include \"LlmCatalog.hpp\"\n#include \"ErrorMessages.hpp\"\n#in"
  },
  {
    "path": "app/lib/LlavaImageAnalyzer.cpp",
    "chars": 32587,
    "preview": "#include \"LlavaImageAnalyzer.hpp\"\n\n#include \"Logger.hpp\"\n#include \"LlamaModelParams.hpp\"\n\n#include <QString>\n\n#include <"
  },
  {
    "path": "app/lib/LlmCatalog.cpp",
    "chars": 1522,
    "preview": "#include \"LlmCatalog.hpp\"\n\n#include <QObject>\n\n#include <algorithm>\n#include <cstdlib>\n\nnamespace {\nQString resolved_llm"
  },
  {
    "path": "app/lib/LocalLLMClient.cpp",
    "chars": 83591,
    "preview": "#include \"LocalLLMClient.hpp\"\n#include \"Logger.hpp\"\n#include \"Utils.hpp\"\n#include \"TestHooks.hpp\"\n#include \"LocalLLMTest"
  },
  {
    "path": "app/lib/Logger.cpp",
    "chars": 2973,
    "preview": "#include \"constants.hpp\"\n#include \"Logger.hpp\"\n#include \"Utils.hpp\"\n#include <cstdlib>\n#include <string>\n#include <files"
  },
  {
    "path": "app/lib/MainApp.cpp",
    "chars": 177445,
    "preview": "#include \"MainApp.hpp\"\n#include \"AppInfo.hpp\"\n\n#include \"CategorizationSession.hpp\"\n#include \"DialogUtils.hpp\"\n#include "
  },
  {
    "path": "app/lib/MainAppEditActions.cpp",
    "chars": 1547,
    "preview": "#include \"MainAppEditActions.hpp\"\n\n#include <QClipboard>\n#include <QGuiApplication>\n#include <QLineEdit>\n\nvoid MainAppEd"
  },
  {
    "path": "app/lib/MainAppHelpActions.cpp",
    "chars": 5513,
    "preview": "#include \"MainAppHelpActions.hpp\"\n#include \"AppInfo.hpp\"\n\n#include <app_version.hpp>\n\n#include <QDialog>\n#include <QDial"
  },
  {
    "path": "app/lib/MainAppUiBuilder.cpp",
    "chars": 37645,
    "preview": "#include \"MainAppUiBuilder.hpp\"\n#include \"AppInfo.hpp\"\n\n#include \"MainApp.hpp\"\n#include \"MainAppEditActions.hpp\"\n#includ"
  },
  {
    "path": "app/lib/MediaRenameMetadataService.cpp",
    "chars": 46323,
    "preview": "#include \"MediaRenameMetadataService.hpp\"\n\n#include \"Utils.hpp\"\n\n#include <algorithm>\n#include <array>\n#include <cctype>"
  },
  {
    "path": "app/lib/MovableCategorizedFile.cpp",
    "chars": 10176,
    "preview": "#include \"MovableCategorizedFile.hpp\"\n#include \"Utils.hpp\"\n#include \"Logger.hpp\"\n#include <filesystem>\n#include <cstdio>"
  },
  {
    "path": "app/lib/PugixmlBundle.cpp",
    "chars": 93,
    "preview": "#if defined(AI_FILE_SORTER_USE_PUGIXML)\n#include \"pugixml.hpp\"\n#include \"pugixml.cpp\"\n#endif\n"
  },
  {
    "path": "app/lib/ResultsCoordinator.cpp",
    "chars": 3059,
    "preview": "#include \"ResultsCoordinator.hpp\"\n\n#include <algorithm>\n#include <filesystem>\n\nResultsCoordinator::ResultsCoordinator(Fi"
  },
  {
    "path": "app/lib/Settings.cpp",
    "chars": 36816,
    "preview": "#include \"Settings.hpp\"\n#include \"Types.hpp\"\n#include \"Logger.hpp\"\n#include \"Language.hpp\"\n#include \"Utils.hpp\"\n#include"
  },
  {
    "path": "app/lib/SuitabilityBenchmarkDialog.cpp",
    "chars": 65522,
    "preview": "#include \"SuitabilityBenchmarkDialog.hpp\"\n\n#include \"DocumentTextAnalyzer.hpp\"\n#include \"ILLMClient.hpp\"\n#include \"Llava"
  },
  {
    "path": "app/lib/SupportCodeManager.cpp",
    "chars": 12894,
    "preview": "#include \"SupportCodeManager.hpp\"\n\n#include <QByteArray>\n#include <QCryptographicHash>\n#include <QRandomGenerator>\n#incl"
  },
  {
    "path": "app/lib/TranslationManager.cpp",
    "chars": 4397,
    "preview": "#include \"TranslationManager.hpp\"\n\n#include <QApplication>\n#include <QCoreApplication>\n#include <QDir>\n#include <QFileIn"
  },
  {
    "path": "app/lib/UiTranslator.cpp",
    "chars": 15567,
    "preview": "#include \"UiTranslator.hpp\"\n\n#include \"Language.hpp\"\n#include \"CategoryLanguage.hpp\"\n#include \"Settings.hpp\"\n\n#include <"
  },
  {
    "path": "app/lib/UndoManager.cpp",
    "chars": 4863,
    "preview": "#include \"UndoManager.hpp\"\n\n#include <QDir>\n#include <QFile>\n#include <QFileInfo>\n#include <QJsonArray>\n#include <QJsonD"
  },
  {
    "path": "app/lib/UpdateArchiveExtractor.cpp",
    "chars": 6862,
    "preview": "#include \"UpdateArchiveExtractor.hpp\"\n\n#include <algorithm>\n#include <array>\n#include <cctype>\n#include <cstdint>\n#inclu"
  },
  {
    "path": "app/lib/UpdateFeed.cpp",
    "chars": 4420,
    "preview": "#include \"UpdateFeed.hpp\"\n\n#include <algorithm>\n#include <cctype>\n#include <memory>\n#include <stdexcept>\n\n#if __has_incl"
  },
  {
    "path": "app/lib/UpdateInstaller.cpp",
    "chars": 13469,
    "preview": "#include \"UpdateInstaller.hpp\"\n\n#include \"UpdateArchiveExtractor.hpp\"\n#include \"Logger.hpp\"\n#include \"Utils.hpp\"\n\n#inclu"
  },
  {
    "path": "app/lib/Updater.cpp",
    "chars": 18590,
    "preview": "#include \"Updater.hpp\"\n#include \"Logger.hpp\"\n#include \"UpdaterBuildConfig.hpp\"\n#include \"UpdaterLaunchOptions.hpp\"\n#incl"
  },
  {
    "path": "app/lib/UpdaterLiveTestConfig.cpp",
    "chars": 3057,
    "preview": "#include \"UpdaterLiveTestConfig.hpp\"\n\n#include \"IniConfig.hpp\"\n#include \"Utils.hpp\"\n\n#include <filesystem>\n#include <opt"
  },
  {
    "path": "app/lib/Utils.cpp",
    "chars": 27193,
    "preview": "#include \"Utils.hpp\"\n#include \"Logger.hpp\"\n#include \"TestHooks.hpp\"\n#include <algorithm>\n#include <cstdio>\n#include <cst"
  },
  {
    "path": "app/lib/Version.cpp",
    "chars": 1582,
    "preview": "#include \"Version.hpp\"\n#include <algorithm>\n#include <sstream>\n#include <string>\n\n\nVersion::Version(std::initializer_lis"
  },
  {
    "path": "app/lib/WhitelistManagerDialog.cpp",
    "chars": 6051,
    "preview": "#include \"WhitelistManagerDialog.hpp\"\n\n#include <QListWidget>\n#include <QPushButton>\n#include <QVBoxLayout>\n#include <QH"
  },
  {
    "path": "app/lib/WhitelistStore.cpp",
    "chars": 4101,
    "preview": "#include \"WhitelistStore.hpp\"\n#include \"Logger.hpp\"\n#include \"Settings.hpp\"\n\n#include <QSettings>\n#include <algorithm>\n\n"
  },
  {
    "path": "app/main.cpp",
    "chars": 15359,
    "preview": "#include \"AppInfo.hpp\"\n#include \"EmbeddedEnv.hpp\"\n#include \"GgmlRuntimePaths.hpp\"\n#include \"Logger.hpp\"\n#include \"MainAp"
  },
  {
    "path": "app/resources/app.qrc",
    "chars": 314,
    "preview": "<!DOCTYPE RCC><RCC version=\"1.0\">\n  <qresource prefix=\"/net/quicknode/AIFileSorter\">\n    <file>images/logo.png</file>\n  "
  },
  {
    "path": "app/resources/certs/cacert.pem",
    "chars": 227915,
    "preview": "##\n## Bundle of CA Root Certificates\n##\n## Certificate data from Mozilla as of: Tue Sep  9 03:12:01 2025 GMT\n##\n## Find "
  },
  {
    "path": "app/resources/i18n/aifilesorter_de.ts",
    "chars": 107925,
    "preview": "<?xml version='1.0' encoding='utf-8'?>\n<TS version=\"2.1\" language=\"de_DE\">\n    <context>\n        <name>CategorizationDia"
  },
  {
    "path": "app/resources/i18n/aifilesorter_es.ts",
    "chars": 107556,
    "preview": "<?xml version='1.0' encoding='utf-8'?>\n<TS version=\"2.1\" language=\"es_ES\">\n    <context>\n        <name>CategorizationDia"
  },
  {
    "path": "app/resources/i18n/aifilesorter_fr.ts",
    "chars": 108211,
    "preview": "<?xml version='1.0' encoding='utf-8'?>\n<TS version=\"2.1\" language=\"fr_FR\">\n    <context>\n        <name>CategorizationDia"
  },
  {
    "path": "app/resources/i18n/aifilesorter_it.ts",
    "chars": 107483,
    "preview": "<?xml version='1.0' encoding='utf-8'?>\n<TS version=\"2.1\" language=\"it_IT\">\n    <context>\n        <name>CategorizationDia"
  },
  {
    "path": "app/resources/i18n/aifilesorter_ko.ts",
    "chars": 100257,
    "preview": "<?xml version='1.0' encoding='utf-8'?>\n<TS version=\"2.1\" language=\"ko_KR\">\n    <context>\n        <name>CategorizationDia"
  },
  {
    "path": "app/resources/i18n/aifilesorter_nl.ts",
    "chars": 107049,
    "preview": "<?xml version='1.0' encoding='utf-8'?>\n<TS version=\"2.1\" language=\"nl_NL\">\n    <context>\n        <name>CategorizationDia"
  },
  {
    "path": "app/resources/i18n/aifilesorter_tr.ts",
    "chars": 106211,
    "preview": "<?xml version='1.0' encoding='utf-8'?>\n<TS version=\"2.1\" language=\"tr_TR\">\n    <context>\n        <name>CategorizationDia"
  },
  {
    "path": "app/resources/windows/app_icon.rc.in",
    "chars": 58,
    "preview": "#include <windows.h>\n\nIDI_APP_ICON ICON \"@APP_ICON_PATH@\"\n"
  },
  {
    "path": "app/resources/windows/version.rc.in",
    "chars": 970,
    "preview": "#include <windows.h>\n\n#define VER_COMPANY      \"hyperfield\"\n#define VER_FILEDESC     \"AI File Sorter\"\n#define VER_PRODUC"
  },
  {
    "path": "app/scripts/README.md",
    "chars": 3465,
    "preview": "# Diagnostic Collection Scripts\n\nThis folder includes cross-platform scripts for collecting AI File Sorter diagnostics,\n"
  },
  {
    "path": "app/scripts/build_llama_linux.sh",
    "chars": 5340,
    "preview": "#!/bin/bash\nset -e\n\n# Resolve script directory\nSCRIPT_DIR=\"$(cd \"$(dirname \"${BASH_SOURCE[0]}\")\" && pwd)\"\nLLAMA_DIR=\"$SC"
  },
  {
    "path": "app/scripts/build_llama_macos.sh",
    "chars": 7926,
    "preview": "#!/bin/bash\nset -e\n\n# CLI flags\nusage() {\n    cat <<'USAGE'\nUsage: build_llama_macos.sh [options]\n\nOptions:\n  --arch <ar"
  },
  {
    "path": "app/scripts/build_llama_windows.ps1",
    "chars": 15437,
    "preview": "$ErrorActionPreference = \"Stop\"\n\n# --- Parse optional arguments ---\n$useCuda = \"OFF\"\n$useVulkan = \"OFF\"\n$useBlas = \"AUTO"
  },
  {
    "path": "app/scripts/collect_linux_diagnostics.sh",
    "chars": 10671,
    "preview": "#!/usr/bin/env bash\nset -euo pipefail\n\nusage() {\n    cat <<'EOF'\nCollect, redact, and zip AI File Sorter diagnostics on "
  },
  {
    "path": "app/scripts/collect_macos_diagnostics.sh",
    "chars": 9759,
    "preview": "#!/usr/bin/env bash\nset -euo pipefail\n\nusage() {\n    cat <<'EOF'\nCollect, redact, and zip AI File Sorter diagnostics on "
  },
  {
    "path": "app/scripts/collect_windows_diagnostics.ps1",
    "chars": 12629,
    "preview": "param(\n    [Alias(\"time-period\")]\n    [string]$TimePeriod,\n    [Alias(\"output-dir\")]\n    [string]$OutputDir = [System.En"
  },
  {
    "path": "app/scripts/gen_run_wrapper.py",
    "chars": 950,
    "preview": "#!/usr/bin/env python3\nimport argparse\nfrom pathlib import Path\n\nDEV_DECL = \"SCRIPT_DIR=\\\"$(cd \\\"$(dirname \\\"$0\\\")\\\" && "
  },
  {
    "path": "app/scripts/generate_icon.ps1",
    "chars": 1535,
    "preview": "param(\n    [Parameter(Mandatory = $true)][string]$BasePng,\n    [Parameter(Mandatory = $true)][string]$Ico\n)\n\n$ErrorActio"
  },
  {
    "path": "app/scripts/package_deb.sh",
    "chars": 11675,
    "preview": "#!/usr/bin/env bash\n\nset -euo pipefail\n\n# Builds a Debian package for AI File Sorter that bundles only the project-speci"
  },
  {
    "path": "app/scripts/rebuild_and_test.sh",
    "chars": 446,
    "preview": "#!/usr/bin/env bash\n\nset -euo pipefail\n\nscript_dir=\"$(cd \"$(dirname \"${BASH_SOURCE[0]}\")\" && pwd)\"\nrepo_root=\"$(cd \"${sc"
  },
  {
    "path": "app/scripts/run_aifilesorter.sh.in",
    "chars": 4972,
    "preview": "#!/bin/sh\n@APP_DIR_DECLARATION@\nCPU_LIB_DIR=\"$APP_DIR/lib/precompiled/cpu/bin\"\nCUDA_LIB_DIR=\"$APP_DIR/lib/precompiled/cu"
  },
  {
    "path": "app/scripts/vendor_doc_deps.ps1",
    "chars": 4350,
    "preview": "param(\n    [string]$LibzipVersion = \"1.11.4\",\n    [string]$PugixmlVersion = \"1.15\",\n    [string]$PdfiumRelease = \"latest"
  },
  {
    "path": "app/scripts/vendor_doc_deps.sh",
    "chars": 3003,
    "preview": "#!/usr/bin/env bash\nset -euo pipefail\n\nLIBZIP_VERSION=\"1.11.4\"\nPUGIXML_VERSION=\"1.15\"\nPDFIUM_RELEASE=\"latest\"\n\nROOT_DIR="
  },
  {
    "path": "app/startapp_linux.cpp",
    "chars": 8328,
    "preview": "#include <iostream>\n#include <cstdio>\n#include <cstdlib>\n#include <unistd.h>\n#include <limits.h>\n#include <string>\n#incl"
  },
  {
    "path": "app/startapp_windows.cpp",
    "chars": 27420,
    "preview": "#include <QApplication>\n#include <QCoreApplication>\n#include <QDir>\n#include <QFileInfo>\n#include <QDebug>\n#include <QMe"
  },
  {
    "path": "app/vcpkg.json",
    "chars": 378,
    "preview": "{\n  \"name\": \"ai-file-sorter\",\n  \"version-string\": \"0.1.0\",\n  \"description\": \"AI File Sorter (Qt6) - Windows build depend"
  },
  {
    "path": "external/README-doc-deps.md",
    "chars": 504,
    "preview": "# Vendored document-analysis dependencies\n\nThis repo vendors the following dependencies for embedded document extraction"
  },
  {
    "path": "external/THIRD_PARTY_LICENSES/libzip-LICENSE",
    "chars": 1454,
    "preview": "Copyright (C) 1999-2020 Dieter Baron and Thomas Klausner\n\nThe authors can be contacted at <info@libzip.org>\n\nRedistribut"
  },
  {
    "path": "external/THIRD_PARTY_LICENSES/pdfium-LICENSE",
    "chars": 1169,
    "preview": "Copyright 2014-2025 Benoit Blanchon\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of thi"
  },
  {
    "path": "external/THIRD_PARTY_LICENSES/pugixml-LICENSE.md",
    "chars": 1079,
    "preview": "MIT License\n\nCopyright (c) 2006-2025 Arseny Kapoulkine\n\nPermission is hereby granted, free of charge, to any person\nobta"
  },
  {
    "path": "external/libzip/.clang-format",
    "chars": 299,
    "preview": "BasedOnStyle: LLVM\nIndentWidth: 4\nColumnLimit: 2000\nAlwaysBreakAfterReturnType: TopLevelDefinitions\nKeepEmptyLinesAtTheS"
  },
  {
    "path": "external/libzip/.github/ISSUE_TEMPLATE/bug-report.md",
    "chars": 736,
    "preview": "---\nname: Bug Report\nabout: Report where libzip didn't behave like you expected.\ntitle: ''\nlabels: bug\nassignees: ''\n\n--"
  },
  {
    "path": "external/libzip/.github/ISSUE_TEMPLATE/compile-error.md",
    "chars": 641,
    "preview": "---\nname: Compile Error\nabout: Report when libzip does not compile.\ntitle: ''\nlabels: compile\nassignees: ''\n\n---\n\n**Comp"
  },
  {
    "path": "external/libzip/.github/ISSUE_TEMPLATE/feature-request.md",
    "chars": 697,
    "preview": "---\nname: Feature Request\nabout: Suggest an idea for this project.\ntitle: ''\nlabels: enhancement\nassignees: ''\n\n---\n\n**D"
  },
  {
    "path": "external/libzip/.github/ISSUE_TEMPLATE/other.md",
    "chars": 139,
    "preview": "---\nname: Other\nabout: If you have a question about libzip , consider using Discussions instead.\ntitle: ''\nlabels: ''\nas"
  },
  {
    "path": "external/libzip/.github/workflows/CIFuzz.yml",
    "chars": 631,
    "preview": "name: CIFuzz\non: [pull_request]\npermissions:\n  contents: read\njobs:\n  Fuzzing:\n    runs-on: ubuntu-latest\n    steps:\n   "
  },
  {
    "path": "external/libzip/.github/workflows/bsd.yml",
    "chars": 827,
    "preview": "name: BSD\non: [push]\npermissions:\n  contents: read\njobs:\n  NetBSD:\n    runs-on: ubuntu-latest\n    steps:\n    - name: che"
  },
  {
    "path": "external/libzip/.github/workflows/build.yml",
    "chars": 2340,
    "preview": "name: build\non: [push]\npermissions:\n  contents: read\njobs:\n  all:\n    runs-on: ${{ matrix.os }}\n    name: ${{ matrix.os "
  },
  {
    "path": "external/libzip/.github/workflows/codeql-analysis.yml",
    "chars": 2471,
    "preview": "# For most projects, this workflow file will not need changing; you simply need\n# to commit it to your repository.\n#\n# Y"
  },
  {
    "path": "external/libzip/.github/workflows/coverity.yml",
    "chars": 2329,
    "preview": "name: Coverity\n\non:\n  schedule:\n    - cron: '0 3 * * 1'\n      # Mondays at 03:00\n  workflow_dispatch:\n\npermissions:\n  co"
  },
  {
    "path": "external/libzip/API-CHANGES.md",
    "chars": 4985,
    "preview": "# libzip API changes\n\nThis file describes changes in the libzip API and how to adapt your\ncode for them.\n\nYou can define"
  },
  {
    "path": "external/libzip/AUTHORS",
    "chars": 62,
    "preview": "Dieter Baron <dillo@nih.at>\nThomas Klausner <wiz@gatalith.at>\n"
  },
  {
    "path": "external/libzip/CMakeLists.txt",
    "chars": 16178,
    "preview": "cmake_minimum_required(VERSION 3.10)\n\nlist(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)\nif (${CMAKE_VERSI"
  },
  {
    "path": "external/libzip/INSTALL.md",
    "chars": 2498,
    "preview": "libzip uses [cmake](https://cmake.org) to build.\n\nYou'll need [zlib](http://www.zlib.net/) (at least version 1.1.2). It\n"
  },
  {
    "path": "external/libzip/LICENSE",
    "chars": 1454,
    "preview": "Copyright (C) 1999-2020 Dieter Baron and Thomas Klausner\n\nThe authors can be contacted at <info@libzip.org>\n\nRedistribut"
  },
  {
    "path": "external/libzip/NEWS.md",
    "chars": 10044,
    "preview": "# 1.11.4 [2025-05-23]\n\n* Use separate cmake package files for library and programs.\n* Improve documentation.\n\n# 1.11.3 ["
  },
  {
    "path": "external/libzip/README.md",
    "chars": 3446,
    "preview": "# libzip\n\n## A C Library for Reading, Creating, and Modifying Zip Archives\n\n\n## Why Use libzip?\n\nlibzip has been continu"
  },
  {
    "path": "external/libzip/SECURITY.md",
    "chars": 425,
    "preview": "# Security Policy\n\n## Supported Versions\n\nWe are not maintaining multiple branches, so all fixes will be committed to he"
  },
  {
    "path": "external/libzip/THANKS",
    "chars": 5296,
    "preview": "Thanks to Info-ZIP for info on the DOS-time/date conversion code,\nand some other general information gathered from their"
  },
  {
    "path": "external/libzip/TODO.md",
    "chars": 7407,
    "preview": "## Fuzzing\n\n- improve AES and PKWARE encryption tests\n- add more\n- review memset() uses\n\n### Torrentzip\n\n- Handle data s"
  },
  {
    "path": "external/libzip/android/do.sh",
    "chars": 1749,
    "preview": "\n# Author: Declan Moran\n# www.silverglint.com \n# Thanks to damaex (https://github.com/damaex), for significant contribut"
  },
  {
    "path": "external/libzip/android/docker/Dockerfile",
    "chars": 3467,
    "preview": "# Version: 1.0\n\n# Dockerfile for building libzip for android\n# https://github.com/dec1/libzip.git\n# creates docker conta"
  },
  {
    "path": "external/libzip/android/readme.txt",
    "chars": 726,
    "preview": "\nCross compile libzip for android.\n--------------------------------\nModify \"do.sh\" as appropriate if you need to specify"
  },
  {
    "path": "external/libzip/appveyor.yml",
    "chars": 2542,
    "preview": "os:\n- Visual Studio 2019\n\nenvironment:\n  PATH: C:\\Python311-x64\\Scripts;C:\\Python311-arm\\Scripts;$(PATH)\n  VCPKG_BINARY_"
  },
  {
    "path": "external/libzip/cmake/Dist.cmake",
    "chars": 3893,
    "preview": "# Copyright (C) 2020 Dieter Baron and Thomas Klausner\n#\n# The authors can be contacted at <info@libzip.org>\n#\n# Redistri"
  },
  {
    "path": "external/libzip/cmake/FindMbedTLS.cmake",
    "chars": 4488,
    "preview": "# Copyright (C) 2020 Dieter Baron and Thomas Klausner\n#\n# The authors can be contacted at <info@libzip.org>\n#\n# Redistri"
  },
  {
    "path": "external/libzip/cmake/FindNettle.cmake",
    "chars": 4403,
    "preview": "# Copyright (C) 2020 Dieter Baron and Thomas Klausner\n#\n# The authors can be contacted at <info@libzip.org>\n#\n# Redistri"
  },
  {
    "path": "external/libzip/cmake/Findzstd.cmake",
    "chars": 5766,
    "preview": "# Copyright (C) 2020 Dieter Baron and Thomas Klausner\n#\n# The authors can be contacted at <info@libzip.org>\n#\n# Redistri"
  },
  {
    "path": "external/libzip/cmake/GenerateZipErrorStrings.cmake",
    "chars": 1821,
    "preview": "# create zip_err_str.c from zip.h and zipint.h\nfile(READ ${PROJECT_SOURCE_DIR}/lib/zip.h zip_h)\nstring(REGEX MATCHALL \"#"
  },
  {
    "path": "external/libzip/cmake-compat/CMakePushCheckState.cmake",
    "chars": 3940,
    "preview": "# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying\n# file Copyright.txt or https://cmake.org/l"
  },
  {
    "path": "external/libzip/cmake-compat/CheckLibraryExists.cmake",
    "chars": 3685,
    "preview": "# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying\n# file Copyright.txt or https://cmake.org/l"
  },
  {
    "path": "external/libzip/cmake-compat/CheckSymbolExists.cmake",
    "chars": 6124,
    "preview": "# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying\n# file Copyright.txt or https://cmake.org/l"
  },
  {
    "path": "external/libzip/cmake-compat/FindBZip2.cmake",
    "chars": 3510,
    "preview": "# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying\n# file Copyright.txt or https://cmake.org/l"
  },
  {
    "path": "external/libzip/cmake-compat/FindGnuTLS.cmake",
    "chars": 2476,
    "preview": "# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying\n# file Copyright.txt or https://cmake.org/l"
  },
  {
    "path": "external/libzip/cmake-compat/FindLibLZMA.cmake",
    "chars": 5315,
    "preview": "# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying\n# file Copyright.txt or https://cmake.org/l"
  },
  {
    "path": "external/libzip/cmake-compat/FindPackageHandleStandardArgs.cmake",
    "chars": 17789,
    "preview": "# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying\n# file Copyright.txt or https://cmake.org/l"
  },
  {
    "path": "external/libzip/cmake-compat/FindPackageMessage.cmake",
    "chars": 1711,
    "preview": "# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying\n# file Copyright.txt or https://cmake.org/l"
  },
  {
    "path": "external/libzip/cmake-compat/SelectLibraryConfigurations.cmake",
    "chars": 3290,
    "preview": "# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying\n# file Copyright.txt or https://cmake.org/l"
  },
  {
    "path": "external/libzip/config.h.in",
    "chars": 2032,
    "preview": "#ifndef HAD_CONFIG_H\n#define HAD_CONFIG_H\n#ifndef _HAD_ZIPCONF_H\n#include \"zipconf.h\"\n#endif\n/* BEGIN DEFINES */\n#cmaked"
  },
  {
    "path": "external/libzip/examples/CMakeLists.txt",
    "chars": 270,
    "preview": "foreach(PROGRAM add-compressed-data autoclose-archive in-memory)\n    add_executable(${PROGRAM} ${PROGRAM}.c)\n    target_"
  },
  {
    "path": "external/libzip/examples/add-compressed-data.c",
    "chars": 5880,
    "preview": "/*\n  add-compressed-data.c -- add already compressed file to zip archive\n  Copyright (C) 2022-2023 Dieter Baron and Thom"
  }
]

// ... and 996 more files (download for full content)

About this extraction

This page contains the full source code of the hyperfield/ai-file-sorter GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 1196 files (8.3 MB), approximately 2.2M tokens, and a symbol index with 2850 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!